]> source.dussan.org Git - sonarqube.git/commitdiff
Move the previous measure page to temporary url
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Tue, 25 Jul 2017 11:37:00 +0000 (13:37 +0200)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Mon, 14 Aug 2017 09:44:44 +0000 (11:44 +0200)
132 files changed:
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.js
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.js.snap
server/sonar-web/src/main/js/app/utils/startReactApp.js
server/sonar-web/src/main/js/apps/code/components/ComponentMeasure.js
server/sonar-web/src/main/js/apps/component-measures-old/app/App.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/app/AppContainer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/app/actions.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/app/reducer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/components/IconBubbles.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/components/IconList.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/components/IconTree.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/components/IconTreemap.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/components/LeakPeriodLegend.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/components/Measure.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/components/Spinner.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/components/bubbleChart/BubbleChart.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/components/bubbleChart/MeasureBubbleChartContainer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/config/bubbles.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/config/complementary.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/config/domains.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/MeasureDetails.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/MeasureDetailsContainer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/MeasureDetailsHeader.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/MetricNotFound.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/actions.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/Breadcrumb.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/Breadcrumbs.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ComponentCell.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ComponentsList.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ComponentsListRow.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/EmptyComponentsList.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ListHeader.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ListView.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ListViewContainer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/MeasureCell.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/MeasureDrilldown.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/TreeView.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/TreeViewContainer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/reducer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/treemap/MeasureTreemap.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/details/treemap/MeasureTreemapContainer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/home/AllMeasures.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/home/AllMeasuresContainer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/home/AllMeasuresDomain.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/home/DomainMeasures.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/home/DomainMeasuresContainer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/home/Home.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/home/HomeContainer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/home/HomeMeasuresList.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/home/MeasureListValue.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/home/MeasuresList.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/home/actions.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/home/reducer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/hooks.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/routes.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/store/listViewActions.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/store/listViewReducer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/store/rootReducer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/store/statusActions.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/store/statusReducer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/store/treeViewActions.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/store/treeViewReducer.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/styles.css [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures-old/utils.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures/app/App.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/app/AppContainer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/app/actions.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/app/reducer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/components/IconBubbles.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/components/IconList.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/components/IconTree.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/components/IconTreemap.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/components/Measure.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/components/Spinner.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/components/bubbleChart/BubbleChart.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/components/bubbleChart/MeasureBubbleChartContainer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/config/bubbles.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/config/complementary.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/config/domains.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetails.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetailsContainer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetailsHeader.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/MetricNotFound.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/actions.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/drilldown/Breadcrumb.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/drilldown/Breadcrumbs.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ComponentCell.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ComponentsList.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ComponentsListRow.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/drilldown/EmptyComponentsList.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListHeader.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListView.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListViewContainer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/drilldown/MeasureCell.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/drilldown/MeasureDrilldown.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/drilldown/TreeView.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/drilldown/TreeViewContainer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/reducer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemap.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemapContainer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/home/AllMeasures.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/home/AllMeasuresContainer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/home/AllMeasuresDomain.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/home/DomainMeasures.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/home/DomainMeasuresContainer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/home/Home.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/home/HomeContainer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/home/HomeMeasuresList.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/home/MeasureListValue.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/home/MeasuresList.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/home/actions.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/home/reducer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/hooks.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/routes.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/store/listViewActions.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/store/listViewReducer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/store/rootReducer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/store/statusActions.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/store/statusReducer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/store/treeViewActions.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/store/treeViewReducer.js [deleted file]
server/sonar-web/src/main/js/apps/component-measures/styles.css [deleted file]
server/sonar-web/src/main/js/apps/component-measures/utils.js [deleted file]
server/sonar-web/src/main/js/apps/overview/main/BugsAndVulnerabilities.js
server/sonar-web/src/main/js/apps/overview/main/enhance.js
server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGateCondition.js
server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeakMeasures.js
server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverallMeasures.js
server/sonar-web/src/main/js/helpers/__tests__/urls-test.js
server/sonar-web/src/main/js/helpers/urls.js
server/sonar-web/src/main/js/store/rootReducer.js

index 5e3038d65f59adcb652925ebe36035cf0a06f654..ebf096e40e39ea9e26ec683b194672826bdd136e 100644 (file)
@@ -121,13 +121,13 @@ export default class ComponentNavMenu extends React.PureComponent {
     );
   }
 
-  renderComponentMeasuresLink() {
+  renderComponentMeasuresOldLink() {
     return (
       <li>
         <Link
-          to={{ pathname: '/component_measures', query: { id: this.props.component.key } }}
+          to={{ pathname: '/component_measures_old', query: { id: this.props.component.key } }}
           activeClassName="active">
-          {translate('layout.measures')}
+          Old Measures
         </Link>
       </li>
     );
@@ -359,7 +359,7 @@ export default class ComponentNavMenu extends React.PureComponent {
       <NavBarTabs>
         {this.renderDashboardLink()}
         {this.renderIssuesLink()}
-        {this.renderComponentMeasuresLink()}
+        {this.renderComponentMeasuresOldLink()}
         {this.renderCodeLink()}
         {this.renderActivityLink()}
         {this.renderAdministration()}
index 1772a834780be3a14ec60ede760d39492af132db..28da18be296bd2e5dd5e69eed31c51435107544f 100644 (file)
@@ -44,7 +44,7 @@ exports[`should work with extensions 1`] = `
       style={Object {}}
       to={
         Object {
-          "pathname": "/component_measures",
+          "pathname": "/component_measures_old",
           "query": Object {
             "id": "foo",
           },
@@ -243,7 +243,7 @@ exports[`should work with multiple extensions 1`] = `
       style={Object {}}
       to={
         Object {
-          "pathname": "/component_measures",
+          "pathname": "/component_measures_old",
           "query": Object {
             "id": "foo",
           },
index cda4a172b5e3c8514c54e72afa6ac6b9d50815ca..52dc397468c8e294f5d3e257651c7a56984058c3 100644 (file)
@@ -45,7 +45,7 @@ import backgroundTasksRoutes from '../../apps/background-tasks/routes';
 import codeRoutes from '../../apps/code/routes';
 import codingRulesRoutes from '../../apps/coding-rules/routes';
 import componentRoutes from '../../apps/component/routes';
-import componentMeasuresRoutes from '../../apps/component-measures/routes';
+import componentMeasuresRoutes from '../../apps/component-measures-old/routes';
 import customMeasuresRoutes from '../../apps/custom-measures/routes';
 import groupsRoutes from '../../apps/groups/routes';
 import issuesRoutes from '../../apps/issues/routes';
@@ -170,7 +170,7 @@ const startReactApp = () => {
                     getComponent={() =>
                       import('../components/ProjectContainer').then(i => i.default)}>
                     <Route path="code" childRoutes={codeRoutes} />
-                    <Route path="component_measures" childRoutes={componentMeasuresRoutes} />
+                    <Route path="component_measures_old" childRoutes={componentMeasuresRoutes} />
                     <Route path="custom_measures" childRoutes={customMeasuresRoutes} />
                     <Route path="dashboard" childRoutes={overviewRoutes} />
                     <Route path="project">
index e455acf4c4d2f957d3a8bceb86448d44dde14192..7ad6e2067c19c13c4c375648723bad495cd79cb0 100644 (file)
@@ -18,7 +18,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import React from 'react';
-import Measure from '../../component-measures/components/Measure';
+import Measure from '../../component-measures-old/components/Measure';
 
 const ComponentMeasure = ({ component, metricKey, metricType }) => {
   const isProject = component.qualifier === 'TRK';
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/app/App.js b/server/sonar-web/src/main/js/apps/component-measures-old/app/App.js
new file mode 100644 (file)
index 0000000..fd7caef
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import Helmet from 'react-helmet';
+import Spinner from './../components/Spinner';
+import { translate } from '../../../helpers/l10n';
+import '../styles.css';
+
+export default class App extends React.PureComponent {
+  state = { componentSet: false };
+
+  componentDidMount() {
+    this.props.setComponent(this.props.component);
+    this.props.fetchMetrics();
+    this.setState({ componentSet: true });
+  }
+
+  render() {
+    if (this.props.metrics == null || !this.state.componentSet) {
+      return <Spinner />;
+    }
+
+    return (
+      <main id="component-measures">
+        <Helmet title={translate('layout.measures')} />
+        {this.props.children}
+      </main>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/app/AppContainer.js b/server/sonar-web/src/main/js/apps/component-measures-old/app/AppContainer.js
new file mode 100644 (file)
index 0000000..dca2e1e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { connect } from 'react-redux';
+import App from './App';
+import { fetchMetrics, setComponent } from './actions';
+import { getComponent, getMeasuresAppAllMetrics } from '../../../store/rootReducer';
+
+const mapStateToProps = (state, ownProps) => ({
+  component: getComponent(state, ownProps.location.query.id),
+  metrics: getMeasuresAppAllMetrics(state)
+});
+
+const mapDispatchToProps = dispatch => {
+  return {
+    fetchMetrics: () => dispatch(fetchMetrics()),
+    setComponent: component => dispatch(setComponent(component))
+  };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(App);
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/app/actions.js b/server/sonar-web/src/main/js/apps/component-measures-old/app/actions.js
new file mode 100644 (file)
index 0000000..7cfb8ac
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { getMetrics } from '../../../api/metrics';
+
+/*
+ * Actions
+ */
+
+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
+ */
+
+export function displayHome() {
+  return { type: DISPLAY_HOME };
+}
+
+function receiveMetrics(metrics) {
+  return { type: RECEIVE_METRICS, metrics };
+}
+
+export function setComponent(component) {
+  return { type: SET_COMPONENT, component };
+}
+
+/*
+ * Workflow
+ */
+
+export function fetchMetrics() {
+  return dispatch => {
+    getMetrics().then(metrics => {
+      dispatch(receiveMetrics(metrics));
+    });
+  };
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/app/reducer.js b/server/sonar-web/src/main/js/apps/component-measures-old/app/reducer.js
new file mode 100644 (file)
index 0000000..165b79c
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { RECEIVE_METRICS, SET_COMPONENT } from './actions';
+
+const initialState = {
+  metrics: undefined
+};
+
+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-old/components/IconBubbles.js b/server/sonar-web/src/main/js/apps/component-measures-old/components/IconBubbles.js
new file mode 100644 (file)
index 0000000..130adcc
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+
+export default function IconBubbles() {
+  /* eslint max-len: 0 */
+  return (
+    <svg
+      className="measure-tab-icon"
+      viewBox="0 0 512 448"
+      fillRule="evenodd"
+      clipRule="evenodd"
+      strokeLinejoin="round"
+      strokeMiterlimit="1.414">
+      <path d="M352 256c52.984 0 96 43.016 96 96s-43.016 96-96 96-96-43.016-96-96 43.016-96 96-96zM128 96c70.645 0 128 57.355 128 128 0 70.645-57.355 128-128 128C57.355 352 0 294.645 0 224 0 153.355 57.355 96 128 96zM352 0c52.984 0 96 43.016 96 96s-43.016 96-96 96-96-43.016-96-96 43.016-96 96-96z" />
+    </svg>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/components/IconList.js b/server/sonar-web/src/main/js/apps/component-measures-old/components/IconList.js
new file mode 100644 (file)
index 0000000..df6d69e
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+
+export default function ListIcon() {
+  /* eslint max-len: 0 */
+  return (
+    <svg
+      className="measure-tab-icon"
+      viewBox="0 0 448 448"
+      fillRule="evenodd"
+      clipRule="evenodd"
+      strokeLinejoin="round"
+      strokeMiterlimit="1.414">
+      <path d="M448 48c0-8.83-7.17-16-16-16H16C7.17 32 0 39.17 0 48v32c0 8.83 7.17 16 16 16h416c8.83 0 16-7.17 16-16V48zM448 144c0-8.83-7.17-16-16-16H16c-8.83 0-16 7.17-16 16v32c0 8.83 7.17 16 16 16h416c8.83 0 16-7.17 16-16v-32zM448 240c0-8.83-7.17-16-16-16H16c-8.83 0-16 7.17-16 16v32c0 8.83 7.17 16 16 16h416c8.83 0 16-7.17 16-16v-32zM448 336.03c0-8.83-7.17-16-16-16H16c-8.83 0-16 7.17-16 16v32c0 8.83 7.17 16 16 16h416c8.83 0 16-7.17 16-16v-32z" />
+    </svg>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/components/IconTree.js b/server/sonar-web/src/main/js/apps/component-measures-old/components/IconTree.js
new file mode 100644 (file)
index 0000000..9270286
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+
+export default function IconTree() {
+  /* eslint max-len: 0 */
+  return (
+    <svg
+      className="measure-tab-icon"
+      viewBox="0 0 448 448"
+      fillRule="evenodd"
+      clipRule="evenodd"
+      strokeLinejoin="round"
+      strokeMiterlimit="1.414">
+      <path d="M448 48c0-8.83-7.17-16-16-16H16C7.17 32 0 39.17 0 48v32c0 8.83 7.17 16 16 16h416c8.83 0 16-7.17 16-16V48zM448 144c0-8.83-6.146-16-13.714-16H77.714C70.144 128 64 135.17 64 144v32c0 8.83 6.145 16 13.714 16h356.572c7.568 0 13.714-7.17 13.714-16v-32zM448 240c0-8.83-5.12-16-11.428-16H139.428C133.12 224 128 231.17 128 240v32c0 8.83 5.12 16 11.428 16h297.144c6.307 0 11.428-7.17 11.428-16v-32zM448 336.03c0-8.83-4.097-16-9.142-16H201.143c-5.046 0-9.143 7.17-9.143 16v32c0 8.83 4.097 16 9.143 16h237.715c5.045 0 9.142-7.17 9.142-16v-32z" />
+    </svg>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/components/IconTreemap.js b/server/sonar-web/src/main/js/apps/component-measures-old/components/IconTreemap.js
new file mode 100644 (file)
index 0000000..aef8aab
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+
+export default function IconTreemap() {
+  return (
+    <svg
+      className="measure-tab-icon"
+      viewBox="0 0 448 448"
+      fillRule="evenodd"
+      clipRule="evenodd"
+      strokeLinejoin="round"
+      strokeMiterlimit="1.414">
+      <path d="M0 0h224v448H0zM256 0h192v256H256zM256 288h192v160H256z" />
+    </svg>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/components/LeakPeriodLegend.js b/server/sonar-web/src/main/js/apps/component-measures-old/components/LeakPeriodLegend.js
new file mode 100644 (file)
index 0000000..22483f1
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import moment from 'moment';
+import Tooltip from '../../../components/controls/Tooltip';
+import { getPeriodLabel, getPeriodDate } from '../../../helpers/periods';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
+
+export default function LeakPeriodLegend({ component, period }) {
+  if (component.qualifier === 'APP') {
+    return (
+      <div className="measures-domains-leak-header">
+        {translate('issues.leak_period')}
+      </div>
+    );
+  }
+
+  const label = (
+    <div className="measures-domains-leak-header">
+      {translateWithParameters('overview.leak_period_x', getPeriodLabel(period))}
+    </div>
+  );
+
+  if (period.mode === 'days') {
+    return label;
+  }
+
+  const date = getPeriodDate(period);
+  const fromNow = moment(date).fromNow();
+  const tooltip = fromNow + ', ' + moment(date).format('LL');
+  return (
+    <Tooltip placement="bottom" overlay={tooltip}>
+      {label}
+    </Tooltip>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/components/Measure.js b/server/sonar-web/src/main/js/apps/component-measures-old/components/Measure.js
new file mode 100644 (file)
index 0000000..ba59123
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import PropTypes from 'prop-types';
+import Rating from '../../../components/ui/Rating';
+import Level from '../../../components/ui/Level';
+import { formatMeasure, isDiffMetric } from '../../../helpers/measures';
+import { TooltipsContainer } from '../../../components/mixins/tooltips-mixin';
+import { formatLeak, getRatingTooltip } from '../utils';
+
+export default class Measure extends React.PureComponent {
+  static propTypes = {
+    className: PropTypes.string,
+    measure: PropTypes.object,
+    metric: PropTypes.object,
+    decimals: PropTypes.number
+  };
+
+  renderRating(measure, metric) {
+    const value = isDiffMetric(metric.key) ? measure.leak : measure.value;
+    const tooltip = getRatingTooltip(metric.key, value);
+    const rating = <Rating value={value} />;
+
+    if (tooltip) {
+      return (
+        <TooltipsContainer>
+          <span>
+            <span title={tooltip} data-toggle="tooltip">
+              {rating}
+            </span>
+          </span>
+        </TooltipsContainer>
+      );
+    }
+
+    return rating;
+  }
+
+  render() {
+    const { measure, metric, decimals, className } = this.props;
+    const finalMetric = metric || measure.metric;
+
+    if (finalMetric.type === 'RATING') {
+      return this.renderRating(measure, finalMetric);
+    }
+
+    if (finalMetric.type === 'LEVEL') {
+      return <Level level={measure.value} />;
+    }
+
+    const formattedValue = isDiffMetric(finalMetric.key)
+      ? formatLeak(measure.leak, finalMetric, { decimals })
+      : formatMeasure(measure.value, finalMetric.type, { decimals });
+    return (
+      <span className={className}>
+        {formattedValue != null ? formattedValue : '–'}
+      </span>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/components/Spinner.js b/server/sonar-web/src/main/js/apps/component-measures-old/components/Spinner.js
new file mode 100644 (file)
index 0000000..3f899ac
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+
+export default function Spinner() {
+  return <i className="spinner spinner-margin" />;
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/components/bubbleChart/BubbleChart.js b/server/sonar-web/src/main/js/apps/component-measures-old/components/bubbleChart/BubbleChart.js
new file mode 100644 (file)
index 0000000..4729500
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import Spinner from './../Spinner';
+import OriginalBubbleChart from '../../../../components/charts/BubbleChart';
+import bubbles from '../../config/bubbles';
+import { getComponentLeaves } from '../../../../api/components';
+import { formatMeasure } from '../../../../helpers/measures';
+import Workspace from '../../../../components/workspace/main';
+import { getComponentUrl } from '../../../../helpers/urls';
+import { getLocalizedMetricName, translateWithParameters } from '../../../../helpers/l10n';
+
+const HEIGHT = 500;
+const BUBBLES_LIMIT = 500;
+
+function getMeasure(component, metric) {
+  return Number(component.measures[metric]) || 0;
+}
+
+export default class BubbleChart extends React.PureComponent {
+  state = {
+    fetching: 0,
+    files: []
+  };
+
+  componentWillMount() {
+    this.updateMetrics(this.props);
+  }
+
+  componentDidMount() {
+    this.mounted = true;
+    this.fetchFiles();
+  }
+
+  componentWillUpdate(nextProps) {
+    this.updateMetrics(nextProps);
+  }
+
+  componentDidUpdate(nextProps) {
+    if (nextProps.domainName !== this.props.domainName) {
+      this.fetchFiles();
+    }
+  }
+
+  componentWillUnmount() {
+    this.mounted = false;
+  }
+
+  updateMetrics(props) {
+    const { metrics, domainName } = props;
+    const conf = bubbles[domainName];
+    this.xMetric = metrics.find(m => m.key === conf.x);
+    this.yMetric = metrics.find(m => m.key === conf.y);
+    this.sizeMetric = metrics.find(m => m.key === conf.size);
+  }
+
+  fetchFiles() {
+    const { component } = this.props;
+    const metrics = [this.xMetric.key, this.yMetric.key, this.sizeMetric.key];
+    const options = {
+      s: 'metric',
+      metricSort: this.sizeMetric.key,
+      asc: false,
+      ps: BUBBLES_LIMIT
+    };
+
+    if (this.mounted) {
+      this.setState({ fetching: this.state.fetching + 1 });
+    }
+
+    getComponentLeaves(component.key, metrics, options).then(r => {
+      const files = r.components.map(file => {
+        const measures = {};
+
+        file.measures.forEach(measure => {
+          measures[measure.metric] = measure.value;
+        });
+        return { ...file, measures };
+      });
+
+      if (this.mounted) {
+        this.setState({
+          files,
+          fetching: this.state.fetching - 1,
+          total: files.length
+        });
+      }
+    });
+  }
+
+  getTooltip(component) {
+    const x = formatMeasure(getMeasure(component, this.xMetric.key), this.xMetric.type);
+    const y = formatMeasure(getMeasure(component, this.yMetric.key), this.yMetric.type);
+    const size = formatMeasure(getMeasure(component, this.sizeMetric.key), this.sizeMetric.type);
+    const inner = [
+      component.name,
+      `${this.xMetric.name}: ${x}`,
+      `${this.yMetric.name}: ${y}`,
+      `${this.sizeMetric.name}: ${size}`
+    ].join('<br>');
+
+    return `<div class="text-left">${inner}</div>`;
+  }
+
+  handleBubbleClick(component) {
+    if (['FIL', 'UTS'].includes(component.qualifier)) {
+      Workspace.openComponent({ key: component.key });
+    } else {
+      window.location = getComponentUrl(component.refKey || component.key);
+    }
+  }
+
+  renderBubbleChart() {
+    const items = this.state.files.map(file => {
+      return {
+        x: getMeasure(file, this.xMetric.key),
+        y: getMeasure(file, this.yMetric.key),
+        size: getMeasure(file, this.sizeMetric.key),
+        link: file,
+        tooltip: this.getTooltip(file)
+      };
+    });
+
+    const formatXTick = tick => formatMeasure(tick, this.xMetric.type);
+    const formatYTick = tick => formatMeasure(tick, this.yMetric.type);
+
+    return (
+      <OriginalBubbleChart
+        items={items}
+        height={HEIGHT}
+        padding={[25, 60, 50, 60]}
+        formatXTick={formatXTick}
+        formatYTick={formatYTick}
+        onBubbleClick={this.handleBubbleClick.bind(this)}
+      />
+    );
+  }
+
+  render() {
+    const { fetching } = this.state;
+
+    if (fetching) {
+      return (
+        <div className="measure-details-bubble-chart">
+          <div className="note text-center" style={{ lineHeight: `${HEIGHT}px` }}>
+            <Spinner />
+          </div>
+        </div>
+      );
+    }
+
+    return (
+      <div className="measure-details-bubble-chart">
+        <div>
+          {this.renderBubbleChart()}
+        </div>
+
+        <div className="measure-details-bubble-chart-axis x">
+          {getLocalizedMetricName(this.xMetric)}
+        </div>
+        <div className="measure-details-bubble-chart-axis y">
+          {getLocalizedMetricName(this.yMetric)}
+        </div>
+        <div className="measure-details-bubble-chart-axis size">
+          {translateWithParameters(
+            'component_measures.legend.size_x',
+            getLocalizedMetricName(this.sizeMetric)
+          )}
+        </div>
+      </div>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/components/bubbleChart/MeasureBubbleChartContainer.js b/server/sonar-web/src/main/js/apps/component-measures-old/components/bubbleChart/MeasureBubbleChartContainer.js
new file mode 100644 (file)
index 0000000..bc9741b
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { connect } from 'react-redux';
+import MeasureBubbleChart from './BubbleChart';
+import { getMeasuresAppAllMetrics, getMeasuresAppComponent } from '../../../../store/rootReducer';
+
+const mapStateToProps = state => {
+  return {
+    component: getMeasuresAppComponent(state),
+    metrics: getMeasuresAppAllMetrics(state)
+  };
+};
+
+const mapDispatchToProps = () => {
+  return {};
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(MeasureBubbleChart);
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/config/bubbles.js b/server/sonar-web/src/main/js/apps/component-measures-old/config/bubbles.js
new file mode 100644 (file)
index 0000000..28407f5
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+const bubblesConfig = {
+  Reliability: { x: 'ncloc', y: 'reliability_remediation_effort', size: 'bugs' },
+  Security: { x: 'ncloc', y: 'security_remediation_effort', size: 'vulnerabilities' },
+  Maintainability: { x: 'ncloc', y: 'sqale_index', size: 'code_smells' },
+  Coverage: { x: 'complexity', y: 'coverage', size: 'uncovered_lines' },
+  Duplications: { x: 'ncloc', y: 'duplicated_lines', size: 'duplicated_blocks' }
+};
+
+export default bubblesConfig;
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/config/complementary.js b/server/sonar-web/src/main/js/apps/component-measures-old/config/complementary.js
new file mode 100644 (file)
index 0000000..46340a2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+export default {
+  coverage: ['uncovered_lines', 'uncovered_conditions'],
+  line_coverage: ['uncovered_lines'],
+  branch_coverage: ['uncovered_conditions'],
+  uncovered_lines: ['line_coverage'],
+  uncovered_conditions: ['branch_coverage'],
+
+  new_coverage: ['new_uncovered_lines', 'new_uncovered_conditions'],
+  new_line_coverage: ['new_uncovered_lines'],
+  new_branch_coverage: ['new_uncovered_conditions'],
+  new_uncovered_lines: ['new_line_coverage'],
+  new_uncovered_conditions: ['new_branch_coverage'],
+
+  duplicated_lines_density: ['duplicated_lines'],
+  new_duplicated_lines_density: ['new_duplicated_lines'],
+  duplicated_lines: ['duplicated_lines_density'],
+  new_duplicated_lines: ['new_duplicated_lines_density']
+};
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/config/domains.js b/server/sonar-web/src/main/js/apps/component-measures-old/config/domains.js
new file mode 100644 (file)
index 0000000..6ac6a69
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+export const domains = {
+  Reliability: {
+    main: ['bugs', 'new_bugs', 'reliability_rating'],
+    order: [
+      'bugs',
+      'new_bugs',
+      'reliability_rating',
+      'reliability_remediation_effort',
+      'new_reliability_remediation_effort'
+    ]
+  },
+
+  Security: {
+    main: ['vulnerabilities', 'new_vulnerabilities', 'security_rating'],
+    order: [
+      'vulnerabilities',
+      'new_vulnerabilities',
+      'security_rating',
+      'security_remediation_effort',
+      'new_security_remediation_effort'
+    ]
+  },
+
+  Maintainability: {
+    main: ['code_smells', 'new_code_smells', 'sqale_rating'],
+    order: [
+      'code_smells',
+      'new_code_smells',
+      'sqale_rating',
+      'sqale_index',
+      'new_technical_debt',
+      'sqale_debt_ratio',
+      'new_sqale_debt_ratio',
+      'effort_to_reach_maintainability_rating_a'
+    ]
+  },
+
+  Coverage: {
+    main: ['coverage', 'new_coverage', 'tests'],
+    order: [
+      'coverage',
+      'new_coverage',
+      'line_coverage',
+      'new_line_coverage',
+      'branch_coverage',
+      'new_branch_coverage',
+      'uncovered_lines',
+      'new_uncovered_lines',
+      'uncovered_conditions',
+      'new_uncovered_conditions',
+      'new_lines_to_cover',
+
+      'lines_to_cover',
+
+      'tests',
+      'test_success',
+      'test_errors',
+      'test_failures',
+      'skipped_tests',
+      'test_success_density',
+      'test_execution_time'
+    ]
+  },
+
+  Duplications: {
+    main: ['duplicated_lines_density', 'new_duplicated_lines_density'],
+    order: [
+      'duplicated_lines_density',
+      'new_duplicated_lines_density',
+      'duplicated_blocks',
+      'new_duplicated_blocks',
+      'duplicated_lines',
+      'new_duplicated_lines',
+      'duplicated_files'
+    ]
+  },
+
+  Size: {
+    main: ['ncloc'],
+    order: [
+      'ncloc',
+      'lines',
+      'new_lines',
+      'statements',
+      'functions',
+      'classes',
+      'files',
+      'directories'
+    ]
+  },
+
+  Complexity: {
+    main: ['complexity'],
+    order: ['complexity', 'function_complexity', 'file_complexity', 'class_complexity']
+  },
+
+  Releasability: {
+    main: ['alert_status', 'releasability_rating'],
+    order: ['alert_status']
+  },
+
+  Issues: {
+    main: ['violations', 'new_violations'],
+    order: [
+      'violations',
+      'new_violations',
+      'blocker_violations',
+      'new_blocker_violations',
+      'critical_violations',
+      'new_critical_violations',
+      'major_violations',
+      'new_major_violations',
+      'minor_violations',
+      'new_minor_violations',
+      'info_violations',
+      'new_info_violations',
+      'open_issues',
+      'reopened_issues',
+      'confirmed_issues',
+      'false_positive_issues'
+    ]
+  }
+};
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/MeasureDetails.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/MeasureDetails.js
new file mode 100644 (file)
index 0000000..8188f3f
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { Link, IndexLink } from 'react-router';
+import Spinner from './../components/Spinner';
+import MeasureDetailsHeader from './MeasureDetailsHeader';
+import MeasureDrilldown from './drilldown/MeasureDrilldown';
+import MetricNotFound from './MetricNotFound';
+import { getPeriod, getPeriodDate } from '../../../helpers/periods';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
+
+export default class MeasureDetails extends React.PureComponent {
+  mounted: boolean;
+
+  state = {
+    loading: true
+  };
+
+  componentDidMount() {
+    this.mounted = true;
+    this.loadData();
+  }
+
+  componentDidUpdate(prevProps) {
+    if (prevProps.params.metricKey !== this.props.params.metricKey) {
+      this.loadData();
+    }
+  }
+
+  componentWillUnmount() {
+    this.mounted = false;
+  }
+
+  metricExists(): boolean {
+    const { metrics } = this.props;
+    const { metricKey } = this.props.params;
+    const metric = metrics.find(metric => metric.key === metricKey);
+    return !!metric;
+  }
+
+  loadData() {
+    if (this.metricExists()) {
+      this.setState({ loading: true });
+      const periodIndex = this.props.location.query.period || 1;
+      const onLoaded = () => this.mounted && this.setState({ loading: false });
+      this.props
+        .fetchMeasure(this.props.params.metricKey, Number(periodIndex))
+        .then(onLoaded, onLoaded);
+    }
+  }
+
+  render() {
+    if (!this.metricExists()) {
+      return <MetricNotFound />;
+    }
+
+    if (this.state.loading) {
+      return <Spinner />;
+    }
+
+    const { component, metric, secondaryMeasure, measure, periods, children } = this.props;
+
+    if (!measure) {
+      return <MetricNotFound />;
+    }
+
+    const { tab } = this.props.params;
+    const periodIndex = this.props.location.query.period || 1;
+    const period = getPeriod(periods, Number(periodIndex));
+    const periodDate = getPeriodDate(period);
+
+    return (
+      <section id="component-measures-details" className="page page-container page-limited">
+        <div className="note">
+          <IndexLink
+            to={{ pathname: '/component_measures_old', query: { id: component.key } }}
+            id="component-measures-back-to-all-measures"
+            className="text-muted">
+            {translate('component_measures.all_measures')}
+          </IndexLink>
+          {!!metric.domain &&
+            <span>
+              {' / '}
+              <Link
+                to={{
+                  pathname: `/component_measures_old/domain/${metric.domain}`,
+                  query: { id: component.key }
+                }}
+                className="text-muted">
+                {translateWithParameters('component_measures.domain_measures', metric.domain)}
+              </Link>
+            </span>}
+        </div>
+
+        <MeasureDetailsHeader
+          component={component}
+          leakPeriod={period}
+          measure={measure}
+          metric={metric}
+          secondaryMeasure={secondaryMeasure}
+        />
+
+        {measure &&
+          <MeasureDrilldown
+            component={component}
+            metric={metric}
+            tab={tab}
+            leakPeriod={period}
+            leakPeriodDate={periodDate}>
+            {children}
+          </MeasureDrilldown>}
+      </section>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/MeasureDetailsContainer.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/MeasureDetailsContainer.js
new file mode 100644 (file)
index 0000000..7ae3905
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { connect } from 'react-redux';
+import MeasureDetails from './MeasureDetails';
+import { fetchMeasure } from './actions';
+import {
+  getMeasuresAppAllMetrics,
+  getMeasuresAppDetailsMetric,
+  getMeasuresAppDetailsMeasure,
+  getMeasuresAppDetailsSecondaryMeasure,
+  getMeasuresAppDetailsPeriods,
+  getMeasuresAppComponent
+} from '../../../store/rootReducer';
+
+const mapStateToProps = state => {
+  return {
+    component: getMeasuresAppComponent(state),
+    metrics: getMeasuresAppAllMetrics(state),
+    metric: getMeasuresAppDetailsMetric(state),
+    measure: getMeasuresAppDetailsMeasure(state),
+    secondaryMeasure: getMeasuresAppDetailsSecondaryMeasure(state),
+    periods: getMeasuresAppDetailsPeriods(state)
+  };
+};
+
+const mapDispatchToProps = { fetchMeasure };
+
+export default connect(mapStateToProps, mapDispatchToProps)(MeasureDetails);
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/MeasureDetailsHeader.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/MeasureDetailsHeader.js
new file mode 100644 (file)
index 0000000..f2281c2
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { Link } from 'react-router';
+import Measure from './../components/Measure';
+import LanguageDistribution from '../../../components/charts/LanguageDistribution';
+import LeakPeriodLegend from '../components/LeakPeriodLegend';
+import IssueTypeIcon from '../../../components/ui/IssueTypeIcon';
+import HistoryIcon from '../../../components/icons-components/HistoryIcon';
+import Tooltip from '../../../components/controls/Tooltip';
+import { ComplexityDistribution } from '../../../components/shared/complexity-distribution';
+import { isDiffMetric } from '../../../helpers/measures';
+import { TooltipsContainer } from '../../../components/mixins/tooltips-mixin';
+import { getComponentMeasureHistory } from '../../../helpers/urls';
+import { getLocalizedMetricName, translate } from '../../../helpers/l10n';
+
+export default function MeasureDetailsHeader({
+  component,
+  measure,
+  metric,
+  secondaryMeasure,
+  leakPeriod
+}) {
+  const isDiff = isDiffMetric(metric.key);
+  return (
+    <header className="measure-details-header">
+      <h2 className="measure-details-metric">
+        <IssueTypeIcon query={metric.key} className="little-spacer-right" />
+        {getLocalizedMetricName(metric)}
+        {!isDiff &&
+          <Tooltip placement="right" overlay={translate('component_measures.show_metric_history')}>
+            <Link
+              className="js-show-history spacer-left button button-small button-compact"
+              to={getComponentMeasureHistory(component.key, metric.key)}>
+              <HistoryIcon />
+            </Link>
+          </Tooltip>}
+      </h2>
+
+      {isDiff &&
+        <div className="pull-right">
+          <LeakPeriodLegend component={component} period={leakPeriod} />
+        </div>}
+
+      <TooltipsContainer options={{ html: false }}>
+        <div className="measure-details-value">
+          {isDiff
+            ? <div className="measure-details-value-leak">
+                <Measure measure={measure} metric={metric} />
+              </div>
+            : <div className="measure-details-value-absolute">
+                <Measure measure={measure} metric={metric} />
+              </div>}
+
+          {secondaryMeasure &&
+            secondaryMeasure.metric === 'ncloc_language_distribution' &&
+            <div className="measure-details-secondary">
+              <LanguageDistribution distribution={secondaryMeasure.value} />
+            </div>}
+
+          {secondaryMeasure &&
+            secondaryMeasure.metric === 'function_complexity_distribution' &&
+            <div className="measure-details-secondary">
+              <ComplexityDistribution distribution={secondaryMeasure.value} of="function" />
+            </div>}
+
+          {secondaryMeasure &&
+            secondaryMeasure.metric === 'file_complexity_distribution' &&
+            <div className="measure-details-secondary">
+              <ComplexityDistribution distribution={secondaryMeasure.value} of="file" />
+            </div>}
+        </div>
+      </TooltipsContainer>
+    </header>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/MetricNotFound.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/MetricNotFound.js
new file mode 100644 (file)
index 0000000..57b5fee
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+// @flow
+import React from 'react';
+import { translate } from '../../../helpers/l10n';
+
+export default function MetricNotFound() {
+  return (
+    <div className="page page-limited">
+      <div className="alert alert-danger">
+        {translate('component_measures.not_found')}
+      </div>
+    </div>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/actions.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/actions.js
new file mode 100644 (file)
index 0000000..5557934
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { getMeasuresAndMeta } from '../../../api/measures';
+import { enhanceWithLeak } from '../utils';
+import { getMeasuresAppComponent, getMeasuresAppAllMetrics } from '../../../store/rootReducer';
+
+/*
+ * Actions
+ */
+
+export const REQUEST_MEASURE = 'measuresApp/details/REQUEST_MEASURE';
+export const RECEIVE_MEASURE = 'measuresApp/details/RECEIVE_MEASURE';
+
+/*
+ * Action Creators
+ */
+
+function requestMeasure(metric) {
+  return { type: REQUEST_MEASURE, metric };
+}
+
+function receiveMeasure(measure, secondaryMeasure, periods) {
+  return { type: RECEIVE_MEASURE, measure, secondaryMeasure, periods };
+}
+
+/*
+ * Workflow
+ */
+
+export function fetchMeasure(metricKey, periodIndex = 1) {
+  return (dispatch, getState) => {
+    const state = getState();
+    const component = getMeasuresAppComponent(state);
+    const metrics = getMeasuresAppAllMetrics(state);
+    const metricsToRequest = [metricKey];
+
+    if (metricKey === 'ncloc') {
+      metricsToRequest.push('ncloc_language_distribution');
+    }
+    if (metricKey === 'function_complexity') {
+      metricsToRequest.push('function_complexity_distribution');
+    }
+    if (metricKey === 'file_complexity') {
+      metricsToRequest.push('file_complexity_distribution');
+    }
+
+    const metric = metrics.find(m => m.key === metricKey);
+    dispatch(requestMeasure(metric));
+
+    return getMeasuresAndMeta(component.key, metricsToRequest, {
+      additionalFields: 'periods'
+    }).then(r => {
+      const measures = enhanceWithLeak(r.component.measures, periodIndex);
+      const measure = measures.find(m => m.metric === metricKey);
+      const secondaryMeasure = measures.find(m => m.metric !== metricKey);
+      dispatch(receiveMeasure(measure, secondaryMeasure, r.periods));
+    });
+  };
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/Breadcrumb.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/Breadcrumb.js
new file mode 100644 (file)
index 0000000..aa038d9
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import QualifierIcon from '../../../../components/shared/QualifierIcon';
+import { formatLeak } from '../../utils';
+import { formatMeasure, isDiffMetric } from '../../../../helpers/measures';
+
+const Breadcrumb = ({ component, metric, onBrowse }) => {
+  const handleClick = e => {
+    e.preventDefault();
+    e.target.blur();
+    onBrowse(component);
+  };
+
+  let inner;
+  if (onBrowse) {
+    inner = (
+      <a id={'component-measures-breadcrumb-' + component.key} href="#" onClick={handleClick}>
+        {component.name}
+      </a>
+    );
+  } else {
+    inner = (
+      <span>
+        {component.name}
+      </span>
+    );
+  }
+
+  const value = isDiffMetric(metric.key)
+    ? formatLeak(component.leak, metric)
+    : formatMeasure(component.value, metric.type);
+
+  return (
+    <span>
+      <QualifierIcon qualifier={component.qualifier} />
+      &nbsp;
+      {inner}
+      {value != null &&
+        <span>
+          {' (' + value + ')'}
+        </span>}
+    </span>
+  );
+};
+
+export default Breadcrumb;
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/Breadcrumbs.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/Breadcrumbs.js
new file mode 100644 (file)
index 0000000..227fad2
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import Breadcrumb from './Breadcrumb';
+
+const Breadcrumbs = ({ breadcrumbs, metric, onBrowse }) =>
+  <ul className="component-measures-breadcrumbs">
+    {breadcrumbs.map((component, index) =>
+      <li key={component.key}>
+        <Breadcrumb
+          component={component}
+          metric={metric}
+          onBrowse={index + 1 < breadcrumbs.length ? onBrowse : null}
+        />
+      </li>
+    )}
+  </ul>;
+
+export default Breadcrumbs;
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ComponentCell.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ComponentCell.js
new file mode 100644 (file)
index 0000000..6d9ae77
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import classNames from 'classnames';
+import QualifierIcon from '../../../../components/shared/QualifierIcon';
+import { splitPath } from '../../../../helpers/path';
+import { getComponentUrl } from '../../../../helpers/urls';
+
+const ComponentCell = ({ component, isSelected, onClick }) => {
+  const linkClassName = classNames('link-no-underline', {
+    selected: isSelected
+  });
+
+  const handleClick = e => {
+    const isLeftClickEvent = e.button === 0;
+    const isModifiedEvent = !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
+
+    if (isLeftClickEvent && !isModifiedEvent) {
+      e.preventDefault();
+      onClick();
+    }
+  };
+
+  let head = '';
+  let tail = component.name;
+
+  if (['DIR', 'FIL', 'UTS'].includes(component.qualifier)) {
+    const parts = splitPath(component.path);
+    head = parts.head;
+    tail = parts.tail;
+  }
+
+  const inner = (
+    <span title={component.refKey || component.key}>
+      <QualifierIcon qualifier={component.qualifier} />
+      &nbsp;
+      {head.length > 0 &&
+        <span className="note">
+          {head}/
+        </span>}
+      <span>{tail}</span>
+    </span>
+  );
+
+  return (
+    <td style={{ maxWidth: 0 }}>
+      <div
+        style={{
+          maxWidth: '100%',
+          whiteSpace: 'nowrap',
+          overflow: 'hidden',
+          textOverflow: 'ellipsis'
+        }}>
+        {component.refId == null || component.qualifier === 'DEV_PRJ'
+          ? <a
+              id={'component-measures-component-link-' + component.key}
+              className={linkClassName}
+              href={getComponentUrl(component.key)}
+              onClick={handleClick}>
+              {inner}
+            </a>
+          : <a
+              id={'component-measures-component-link-' + component.key}
+              className={linkClassName}
+              href={getComponentUrl(component.refKey || component.key)}>
+              <span className="big-spacer-right">
+                <i className="icon-detach" />
+              </span>
+
+              {inner}
+            </a>}
+      </div>
+    </td>
+  );
+};
+
+export default ComponentCell;
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ComponentsList.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ComponentsList.js
new file mode 100644 (file)
index 0000000..0faf5f6
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import ComponentsListRow from './ComponentsListRow';
+import EmptyComponentsList from './EmptyComponentsList';
+import complementary from '../../config/complementary';
+import { getLocalizedMetricName } from '../../../../helpers/l10n';
+
+const ComponentsList = ({ components, metrics, selected, metric, onClick }) => {
+  if (!components.length) {
+    return <EmptyComponentsList />;
+  }
+
+  const otherMetrics = (complementary[metric.key] || []).map(metric => {
+    return metrics.find(m => m.key === metric);
+  });
+
+  return (
+    <table className="data zebra zebra-hover">
+      {otherMetrics.length > 0 &&
+        <thead>
+          <tr>
+            <th>&nbsp;</th>
+            <th className="text-right">
+              <span className="small">
+                {getLocalizedMetricName(metric)}
+              </span>
+            </th>
+            {otherMetrics.map(metric =>
+              <th key={metric.key} className="text-right">
+                <span className="small">
+                  {getLocalizedMetricName(metric)}
+                </span>
+              </th>
+            )}
+          </tr>
+        </thead>}
+
+      <tbody>
+        {components.map(component =>
+          <ComponentsListRow
+            key={component.id}
+            component={component}
+            otherMetrics={otherMetrics}
+            isSelected={component === selected}
+            metric={metric}
+            onClick={onClick}
+          />
+        )}
+      </tbody>
+    </table>
+  );
+};
+
+export default ComponentsList;
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ComponentsListRow.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ComponentsListRow.js
new file mode 100644 (file)
index 0000000..8e01925
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import ComponentCell from './ComponentCell';
+import MeasureCell from './MeasureCell';
+
+const replaceMeasure = (component, measure) => {
+  return {
+    ...component,
+    value: measure.value,
+    leak: measure.leak
+  };
+};
+
+const ComponentsListRow = ({ component, otherMetrics, isSelected, metric, onClick }) => {
+  const handleClick = () => {
+    onClick(component);
+  };
+
+  const otherMeasures = otherMetrics.map(metric => {
+    const measure = component.measures.find(measure => measure.metric === metric.key);
+    return { ...measure, metric };
+  });
+
+  return (
+    <tr>
+      <ComponentCell
+        component={component}
+        isSelected={isSelected}
+        onClick={handleClick.bind(this, component)}
+      />
+
+      <MeasureCell component={component} metric={metric} />
+
+      {otherMeasures.map(measure =>
+        <MeasureCell
+          key={measure.metric.key}
+          component={replaceMeasure(component, measure)}
+          metric={measure.metric}
+        />
+      )}
+    </tr>
+  );
+};
+
+export default ComponentsListRow;
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/EmptyComponentsList.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/EmptyComponentsList.js
new file mode 100644 (file)
index 0000000..be032c0
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { translate } from '../../../../helpers/l10n';
+
+const EmptyComponentsList = () => {
+  return (
+    <div className="note">
+      {translate('no_results')}
+    </div>
+  );
+};
+
+export default EmptyComponentsList;
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ListHeader.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ListHeader.js
new file mode 100644 (file)
index 0000000..b929bac
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import Breadcrumbs from './Breadcrumbs';
+import { translateWithParameters } from '../../../../helpers/l10n';
+
+const ListHeader = props => {
+  const { metric, breadcrumbs, onBrowse } = props;
+  const { selectedIndex, componentsCount, onSelectPrevious, onSelectNext } = props;
+  const hasPrevious = selectedIndex > 0;
+  const hasNext = selectedIndex < componentsCount - 1;
+  const blur = fn => {
+    return e => {
+      e.target.blur();
+      fn();
+    };
+  };
+
+  return (
+    <header className="measure-details-viewer-header">
+      {breadcrumbs != null &&
+        breadcrumbs.length > 1 &&
+        <div className="measure-details-header-container">
+          <Breadcrumbs breadcrumbs={breadcrumbs} metric={metric} onBrowse={onBrowse} />
+        </div>}
+
+      {selectedIndex != null &&
+        selectedIndex !== -1 &&
+        <div className="pull-right">
+          <span className="note spacer-right">
+            {translateWithParameters(
+              'component_measures.x_of_y',
+              selectedIndex + 1,
+              componentsCount
+            )}
+          </span>
+
+          <div className="button-group">
+            {hasPrevious && <button onClick={blur(onSelectPrevious)}>&lt;</button>}
+            {hasNext && <button onClick={blur(onSelectNext)}>&gt;</button>}
+          </div>
+        </div>}
+    </header>
+  );
+};
+
+export default ListHeader;
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ListView.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ListView.js
new file mode 100644 (file)
index 0000000..88d28d8
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import PropTypes from 'prop-types';
+import classNames from 'classnames';
+import moment from 'moment';
+import ComponentsList from './ComponentsList';
+import ListHeader from './ListHeader';
+import Spinner from '../../components/Spinner';
+import SourceViewer from '../../../../components/SourceViewer/SourceViewer';
+import ListFooter from '../../../../components/controls/ListFooter';
+
+export default class ListView extends React.PureComponent {
+  static contextTypes = {
+    router: PropTypes.object.isRequired
+  };
+
+  componentDidMount() {
+    const { component, metric } = this.props;
+    if (component.qualifier === 'DEV') {
+      const { router } = this.context;
+      router.replace({ pathname: `metric/${metric.key}/tree`, query: { id: component.key } });
+    }
+    this.handleChangeBaseComponent(component);
+  }
+
+  componentDidUpdate(nextProps) {
+    if (nextProps.metric !== this.props.metric) {
+      this.handleChangeBaseComponent(this.props.component);
+    }
+
+    if (this.props.selected) {
+      this.scrollToViewer();
+    } else if (this.scrollTop) {
+      this.scrollToStoredPosition();
+    }
+  }
+
+  scrollToViewer() {
+    const { container } = this.refs;
+    const top = container.getBoundingClientRect().top + window.scrollY - 95 - 10;
+
+    // scroll only to top
+    if (window.scrollY > top) {
+      window.scrollTo(0, top);
+    }
+  }
+
+  scrollToStoredPosition() {
+    window.scrollTo(0, this.scrollTop);
+    this.scrollTop = null;
+  }
+
+  storeScrollPosition() {
+    this.scrollTop = window.scrollY;
+  }
+
+  handleChangeBaseComponent(baseComponent) {
+    const { metric, onFetchList } = this.props;
+    const periodIndex = this.props.location.query.period || 1;
+    onFetchList(baseComponent, metric, Number(periodIndex));
+  }
+
+  handleFetchMore() {
+    const periodIndex = this.props.location.query.period || 1;
+    this.props.onFetchMore(Number(periodIndex));
+  }
+
+  changeSelected(selected) {
+    this.props.onSelect(selected);
+  }
+
+  handleClick(selected) {
+    this.storeScrollPosition();
+    this.props.onSelect(selected);
+  }
+
+  handleBreadcrumbClick() {
+    this.props.onSelect(undefined);
+  }
+
+  render() {
+    const {
+      component,
+      components,
+      metrics,
+      metric,
+      leakPeriod,
+      selected,
+      total,
+      fetching
+    } = this.props;
+    const { onSelectNext, onSelectPrevious } = this.props;
+
+    const breadcrumbs = [component];
+    if (selected) {
+      breadcrumbs.push(selected);
+    }
+    const selectedIndex = components.indexOf(selected);
+    const sourceViewerPeriod = metric.key.indexOf('new_') === 0 && !!leakPeriod ? leakPeriod : null;
+    const sourceViewerPeriodDate =
+      sourceViewerPeriod != null ? moment(sourceViewerPeriod.date).toDate() : null;
+
+    const filterLine =
+      sourceViewerPeriodDate != null
+        ? line => {
+            if (line.scmDate) {
+              const scmDate = moment(line.scmDate).toDate();
+              return scmDate >= sourceViewerPeriodDate;
+            } else {
+              return false;
+            }
+          }
+        : undefined;
+
+    return (
+      <div ref="container" className="measure-details-plain-list">
+        <ListHeader
+          metric={metric}
+          breadcrumbs={breadcrumbs}
+          componentsCount={components.length}
+          selectedIndex={selectedIndex}
+          onSelectPrevious={onSelectPrevious}
+          onSelectNext={onSelectNext}
+          onBrowse={this.handleBreadcrumbClick.bind(this)}
+        />
+
+        {!selected &&
+          <div className={classNames({ 'new-loading': fetching })}>
+            {!fetching || components.length !== 0
+              ? <div>
+                  <ComponentsList
+                    components={components}
+                    metrics={metrics}
+                    selected={selected}
+                    metric={metric}
+                    onClick={this.handleClick.bind(this)}
+                  />
+                  <ListFooter
+                    count={components.length}
+                    total={total}
+                    loadMore={this.handleFetchMore.bind(this)}
+                  />
+                </div>
+              : <Spinner />}
+          </div>}
+
+        {!!selected &&
+          <div className="measure-details-viewer">
+            <SourceViewer component={selected.key} filterLine={filterLine} />
+          </div>}
+      </div>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ListViewContainer.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/ListViewContainer.js
new file mode 100644 (file)
index 0000000..bf6b3fc
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { connect } from 'react-redux';
+import ListView from './ListView';
+import {
+  fetchList,
+  fetchMore,
+  selectComponent,
+  selectNext,
+  selectPrevious
+} from '../../store/listViewActions';
+import {
+  getMeasuresAppListComponents,
+  getMeasuresAppListSelected,
+  getMeasuresAppListTotal,
+  getMeasuresAppListPageIndex,
+  getMeasuresAppAllMetrics,
+  getMeasuresAppDetailsMetric,
+  isMeasuresAppFetching,
+  getMeasuresAppComponent
+} from '../../../../store/rootReducer';
+
+const mapStateToProps = state => {
+  return {
+    components: getMeasuresAppListComponents(state),
+    selected: getMeasuresAppListSelected(state),
+    total: getMeasuresAppListTotal(state),
+    pageIndex: getMeasuresAppListPageIndex(state),
+    component: getMeasuresAppComponent(state),
+    metrics: getMeasuresAppAllMetrics(state),
+    metric: getMeasuresAppDetailsMetric(state),
+    fetching: isMeasuresAppFetching(state)
+  };
+};
+
+const mapDispatchToProps = dispatch => {
+  return {
+    onFetchList: (baseComponent, metric, periodIndex) =>
+      dispatch(fetchList(baseComponent, metric, periodIndex)),
+    onFetchMore: periodIndex => dispatch(fetchMore(periodIndex)),
+    onSelect: component => dispatch(selectComponent(component)),
+    onSelectNext: component => dispatch(selectNext(component)),
+    onSelectPrevious: component => dispatch(selectPrevious(component))
+  };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(ListView);
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/MeasureCell.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/MeasureCell.js
new file mode 100644 (file)
index 0000000..ee236ad
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import Measure from '../../components/Measure';
+
+const MeasureCell = ({ component, metric }) => {
+  return (
+    <td className="thin nowrap text-right">
+      <span id={'component-measures-component-measure-' + component.key + '-' + metric.key}>
+        <Measure measure={{ value: component.value, leak: component.leak }} metric={metric} />
+      </span>
+    </td>
+  );
+};
+
+export default MeasureCell;
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/MeasureDrilldown.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/MeasureDrilldown.js
new file mode 100644 (file)
index 0000000..ad956bd
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { Link } from 'react-router';
+import IconList from './../../components/IconList';
+import IconTree from './../../components/IconTree';
+import IconBubbles from './../../components/IconBubbles';
+import IconTreemap from './../../components/IconTreemap';
+import { hasBubbleChart, hasTreemap } from '../../utils';
+import { translate } from '../../../../helpers/l10n';
+
+export default function MeasureDrilldown(props) {
+  const { children, component, metric, ...other } = props;
+
+  const child = React.cloneElement(children, { ...other });
+
+  return (
+    <div className="measure-details-drilldown">
+      <ul className="measure-details-drilldown-mode">
+        {component.qualifier !== 'DEV' &&
+          <li>
+            <Link
+              activeClassName="active"
+              to={{
+                pathname: `/component_measures_old/metric/${metric.key}/list`,
+                query: { id: component.key }
+              }}>
+              <IconList />
+              {translate('component_measures.tab.list')}
+            </Link>
+          </li>}
+
+        <li>
+          <Link
+            activeClassName="active"
+            to={{
+              pathname: `/component_measures_old/metric/${metric.key}/tree`,
+              query: { id: component.key }
+            }}>
+            <IconTree />
+            {translate('component_measures.tab.tree')}
+          </Link>
+        </li>
+
+        {hasBubbleChart(metric.key) &&
+          <li>
+            <Link
+              activeClassName="active"
+              to={{
+                pathname: `/component_measures_old/metric/${metric.key}/bubbles`,
+                query: { id: component.key }
+              }}>
+              <IconBubbles />
+              {translate('component_measures.tab.bubbles')}
+            </Link>
+          </li>}
+
+        {hasTreemap(metric) &&
+          <li>
+            <Link
+              activeClassName="active"
+              to={{
+                pathname: `/component_measures_old/metric/${metric.key}/treemap`,
+                query: { id: component.key }
+              }}>
+              <IconTreemap />
+              {translate('component_measures.tab.treemap')}
+            </Link>
+          </li>}
+      </ul>
+
+      {child}
+    </div>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/TreeView.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/TreeView.js
new file mode 100644 (file)
index 0000000..0bbfe14
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import moment from 'moment';
+import ComponentsList from './ComponentsList';
+import ListHeader from './ListHeader';
+import Spinner from '../../components/Spinner';
+import SourceViewer from '../../../../components/SourceViewer/SourceViewer';
+import ListFooter from '../../../../components/controls/ListFooter';
+
+export default class TreeView extends React.PureComponent {
+  componentDidMount() {
+    this.handleChangeBaseComponent(this.props.component);
+  }
+
+  componentDidUpdate(nextProps) {
+    if (nextProps.metric !== this.props.metric) {
+      this.handleChangeBaseComponent(this.props.component);
+    }
+
+    if (this.props.selected) {
+      this.scrollToViewer();
+    } else if (this.scrollTop) {
+      this.scrollToStoredPosition();
+    }
+  }
+
+  scrollToViewer() {
+    const { container } = this.refs;
+    const top = container.getBoundingClientRect().top + window.scrollY - 95 - 10;
+
+    // scroll only to top
+    if (window.scrollY > top) {
+      window.scrollTo(0, top);
+    }
+  }
+
+  scrollToStoredPosition() {
+    window.scrollTo(0, this.scrollTop);
+    this.scrollTop = null;
+  }
+
+  storeScrollPosition() {
+    this.scrollTop = window.scrollY;
+  }
+
+  handleChangeBaseComponent(baseComponent) {
+    const { metric, onStart } = this.props;
+    const periodIndex = this.props.location.query.period || 1;
+    onStart(baseComponent, metric, Number(periodIndex));
+  }
+
+  handleFetchMore() {
+    this.props.onFetchMore();
+  }
+
+  changeSelected(selected) {
+    this.props.onSelect(selected);
+  }
+
+  canDrilldown(component) {
+    return !['FIL', 'UTS'].includes(component.qualifier);
+  }
+
+  handleClick(selected) {
+    if (this.canDrilldown(selected)) {
+      this.props.onDrilldown(selected);
+    } else {
+      this.storeScrollPosition();
+      this.props.onSelect(selected);
+    }
+  }
+
+  handleBreadcrumbClick(component) {
+    this.props.onUseBreadcrumbs(component, this.props.metric);
+  }
+
+  render() {
+    const {
+      components,
+      metrics,
+      breadcrumbs,
+      metric,
+      leakPeriod,
+      selected,
+      total,
+      fetching
+    } = this.props;
+    const { onSelectNext, onSelectPrevious } = this.props;
+
+    const selectedIndex = components.indexOf(selected);
+    const sourceViewerPeriod = metric.key.indexOf('new_') === 0 && !!leakPeriod ? leakPeriod : null;
+    const sourceViewerPeriodDate =
+      sourceViewerPeriod != null ? moment(sourceViewerPeriod.date).toDate() : null;
+
+    const filterLine =
+      sourceViewerPeriodDate != null
+        ? line => {
+            if (line.scmDate) {
+              const scmDate = moment(line.scmDate).toDate();
+              return scmDate >= sourceViewerPeriodDate;
+            } else {
+              return false;
+            }
+          }
+        : undefined;
+
+    return (
+      <div ref="container" className="measure-details-plain-list">
+        <ListHeader
+          metric={metric}
+          breadcrumbs={breadcrumbs}
+          componentsCount={components.length}
+          selectedIndex={selectedIndex}
+          onSelectPrevious={onSelectPrevious}
+          onSelectNext={onSelectNext}
+          onBrowse={this.handleBreadcrumbClick.bind(this)}
+        />
+
+        {!selected &&
+          <div>
+            {!fetching || components.length !== 0
+              ? <div>
+                  <ComponentsList
+                    components={components}
+                    metrics={metrics}
+                    selected={selected}
+                    metric={metric}
+                    onClick={this.handleClick.bind(this)}
+                  />
+                  <ListFooter
+                    count={components.length}
+                    total={total}
+                    loadMore={this.handleFetchMore.bind(this)}
+                  />
+                </div>
+              : <Spinner />}
+          </div>}
+
+        {!!selected &&
+          <div className="measure-details-viewer">
+            <SourceViewer component={selected.key} filterLine={filterLine} />
+          </div>}
+      </div>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/TreeViewContainer.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/drilldown/TreeViewContainer.js
new file mode 100644 (file)
index 0000000..a7ae418
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { connect } from 'react-redux';
+import TreeView from './TreeView';
+import {
+  start,
+  drilldown,
+  useBreadcrumbs,
+  fetchMore,
+  selectComponent,
+  selectNext,
+  selectPrevious
+} from '../../store/treeViewActions';
+import {
+  getMeasuresAppTreeComponents,
+  getMeasuresAppTreeBreadcrumbs,
+  getMeasuresAppTreeSelected,
+  getMeasuresAppTreeTotal,
+  getMeasuresAppTreePageIndex,
+  getMeasuresAppAllMetrics,
+  getMeasuresAppDetailsMetric,
+  isMeasuresAppFetching,
+  getMeasuresAppComponent
+} from '../../../../store/rootReducer';
+
+const mapStateToProps = state => {
+  return {
+    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)
+  };
+};
+
+const mapDispatchToProps = dispatch => {
+  return {
+    onStart: (rootComponent, metric, periodIndex) =>
+      dispatch(start(rootComponent, metric, periodIndex)),
+    onDrilldown: component => dispatch(drilldown(component)),
+    onUseBreadcrumbs: component => dispatch(useBreadcrumbs(component)),
+    onFetchMore: () => dispatch(fetchMore()),
+    onSelect: component => dispatch(selectComponent(component)),
+    onSelectNext: component => dispatch(selectNext(component)),
+    onSelectPrevious: component => dispatch(selectPrevious(component))
+  };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(TreeView);
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/reducer.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/reducer.js
new file mode 100644 (file)
index 0000000..ea68685
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { DISPLAY_HOME } from '../app/actions';
+import { REQUEST_MEASURE, RECEIVE_MEASURE } from './actions';
+
+const initialState = {
+  metric: undefined,
+  secondaryMeasure: undefined,
+  measure: undefined,
+  periods: undefined
+};
+
+export default function appReducer(state = initialState, action = {}) {
+  switch (action.type) {
+    case DISPLAY_HOME:
+      return initialState;
+    case REQUEST_MEASURE:
+      return { ...state, metric: action.metric };
+    case RECEIVE_MEASURE:
+      return {
+        ...state,
+        measure: action.measure,
+        secondaryMeasure: action.secondaryMeasure,
+        periods: action.periods
+      };
+    default:
+      return state;
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/treemap/MeasureTreemap.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/treemap/MeasureTreemap.js
new file mode 100644 (file)
index 0000000..2516b8d
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { scaleLinear, scaleOrdinal } from 'd3-scale';
+import Spinner from './../../components/Spinner';
+import { getLeakValue } from '../../utils';
+import { Treemap } from '../../../../components/charts/treemap';
+import { getChildren } from '../../../../api/components';
+import { formatMeasure } from '../../../../helpers/measures';
+import {
+  translate,
+  translateWithParameters,
+  getLocalizedMetricName
+} from '../../../../helpers/l10n';
+import { getComponentUrl } from '../../../../helpers/urls';
+import Workspace from '../../../../components/workspace/main';
+
+const HEIGHT = 500;
+
+export default class MeasureTreemap extends React.PureComponent {
+  state = {
+    fetching: true,
+    components: [],
+    breadcrumbs: []
+  };
+
+  componentDidMount() {
+    const { component } = this.props;
+
+    this.mounted = true;
+    this.fetchComponents(component.key);
+  }
+
+  componentDidUpdate(nextProps) {
+    if (nextProps.metric !== this.props.metric) {
+      this.fetchComponents(this.props.component.key);
+    }
+  }
+
+  componentWillUnmount() {
+    this.mounted = false;
+  }
+
+  fetchComponents(componentKey) {
+    const { metric } = this.props;
+    const metrics = ['ncloc', metric.key];
+    const options = {
+      s: 'metric',
+      metricSort: 'ncloc',
+      asc: false
+    };
+
+    return getChildren(componentKey, metrics, options).then(r => {
+      const components = r.components.map(component => {
+        const measures = {};
+        const key = component.refKey || component.key;
+
+        component.measures.forEach(measure => {
+          const shouldUseLeak = measure.metric.indexOf('new_') === 0;
+          measures[measure.metric] = shouldUseLeak ? getLeakValue(measure) : measure.value;
+        });
+        return { ...component, measures, key };
+      });
+
+      this.setState({
+        components,
+        fetching: false
+      });
+    });
+  }
+
+  getTooltip(component) {
+    const { metric } = this.props;
+
+    let inner = [
+      component.name,
+      `${translate('metric.ncloc.name')}: ${formatMeasure(component.measures['ncloc'], 'INT')}`
+    ];
+
+    const colorMeasure = component.measures[metric.key];
+    const formatted = colorMeasure != null ? formatMeasure(colorMeasure, metric.type) : '—';
+    inner.push(`${getLocalizedMetricName(metric)}: ${formatted}`);
+    inner = inner.join('<br>');
+    return `<div class="text-left">${inner}</div>`;
+  }
+  getPercentColorScale(metric) {
+    const color = scaleLinear().domain([0, 25, 50, 75, 100]);
+    color.range(
+      metric.direction === 1
+        ? ['#d4333f', '#ed7d20', '#eabe06', '#b0d513', '#00aa00']
+        : ['#00aa00', '#b0d513', '#eabe06', '#ed7d20', '#d4333f']
+    );
+    return color;
+  }
+  getRatingColorScale() {
+    return scaleLinear()
+      .domain([1, 2, 3, 4, 5])
+      .range(['#00aa00', '#b0d513', '#eabe06', '#ed7d20', '#d4333f']);
+  }
+  getLevelColorScale() {
+    return scaleOrdinal()
+      .domain(['ERROR', 'WARN', 'OK', 'NONE'])
+      .range(['#d4333f', '#ed7d20', '#00aa00', '#b4b4b4']);
+  }
+  getScale() {
+    const { metric } = this.props;
+    if (metric.type === 'LEVEL') {
+      return this.getLevelColorScale();
+    }
+    if (metric.type === 'RATING') {
+      return this.getRatingColorScale();
+    }
+    return this.getPercentColorScale(metric);
+  }
+  handleRectangleClick(node) {
+    const isFile = node.qualifier === 'FIL' || node.qualifier === 'UTS';
+    if (isFile) {
+      Workspace.openComponent({ key: node.key });
+      return;
+    }
+    this.fetchComponents(node.key).then(() => {
+      let nextBreadcrumbs = [...this.state.breadcrumbs];
+      const index = this.state.breadcrumbs.findIndex(b => b.key === node.key);
+      if (index !== -1) {
+        nextBreadcrumbs = nextBreadcrumbs.slice(0, index);
+      }
+      nextBreadcrumbs = [
+        ...nextBreadcrumbs,
+        {
+          key: node.key,
+          name: node.name,
+          qualifier: node.qualifier
+        }
+      ];
+      this.setState({ breadcrumbs: nextBreadcrumbs });
+    });
+  }
+  handleReset() {
+    const { component } = this.props;
+    this.fetchComponents(component.key).then(() => {
+      this.setState({ breadcrumbs: [] });
+    });
+  }
+  renderTreemap() {
+    const { metric } = this.props;
+    const colorScale = this.getScale();
+    const items = this.state.components
+      .filter(component => component.measures['ncloc'])
+      .map(component => {
+        const colorMeasure = component.measures[metric.key];
+        return {
+          id: component.id,
+          key: component.key,
+          name: component.name,
+          qualifier: component.qualifier,
+          size: component.measures['ncloc'],
+          color: colorMeasure != null ? colorScale(colorMeasure) : '#777',
+          tooltip: this.getTooltip(component),
+          label: component.name,
+          link: getComponentUrl(component.key)
+        };
+      });
+    return (
+      <Treemap
+        items={items}
+        breadcrumbs={this.state.breadcrumbs}
+        height={HEIGHT}
+        canBeClicked={() => true}
+        onRectangleClick={this.handleRectangleClick.bind(this)}
+        onReset={this.handleReset.bind(this)}
+      />
+    );
+  }
+  render() {
+    const { metric } = this.props;
+    const { fetching } = this.state;
+    if (fetching) {
+      return (
+        <div className="measure-details-treemap">
+          <div className="note text-center" style={{ lineHeight: `${HEIGHT}px` }}>
+            <Spinner />
+          </div>
+        </div>
+      );
+    }
+    return (
+      <div className="measure-details-treemap">
+        <ul className="list-inline note measure-details-treemap-legend">
+          <li>
+            {translateWithParameters(
+              'component_measures.legend.color_x',
+              getLocalizedMetricName(metric)
+            )}
+          </li>
+          <li>
+            {translateWithParameters(
+              'component_measures.legend.size_x',
+              translate('metric.ncloc.name')
+            )}
+          </li>
+        </ul>
+        {this.renderTreemap()}
+      </div>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/details/treemap/MeasureTreemapContainer.js b/server/sonar-web/src/main/js/apps/component-measures-old/details/treemap/MeasureTreemapContainer.js
new file mode 100644 (file)
index 0000000..5a3e26d
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { connect } from 'react-redux';
+import MeasureTreemap from './MeasureTreemap';
+import {
+  getMeasuresAppDetailsMetric,
+  getMeasuresAppComponent
+} from '../../../../store/rootReducer';
+
+const mapStateToProps = state => {
+  return {
+    component: getMeasuresAppComponent(state),
+    metric: getMeasuresAppDetailsMetric(state)
+  };
+};
+
+const mapDispatchToProps = () => {
+  return {};
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(MeasureTreemap);
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/home/AllMeasures.js b/server/sonar-web/src/main/js/apps/component-measures-old/home/AllMeasures.js
new file mode 100644 (file)
index 0000000..ab69f4b
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import AllMeasuresDomain from './AllMeasuresDomain';
+import { getLeakPeriodLabel } from '../../../helpers/periods';
+
+export default function AllMeasures(props) {
+  const { component, domains, periods } = props;
+  const leakPeriodLabel = getLeakPeriodLabel(periods);
+
+  return (
+    <ul className="measures-domains">
+      {domains.map(domain =>
+        <AllMeasuresDomain
+          key={domain.name}
+          domain={domain}
+          component={component}
+          leakPeriodLabel={leakPeriodLabel}
+        />
+      )}
+    </ul>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/home/AllMeasuresContainer.js b/server/sonar-web/src/main/js/apps/component-measures-old/home/AllMeasuresContainer.js
new file mode 100644 (file)
index 0000000..5ec9cc7
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { connect } from 'react-redux';
+import AllMeasures from './AllMeasures';
+import {
+  getMeasuresAppHomeDomains,
+  getMeasuresAppHomePeriods,
+  getMeasuresAppComponent
+} from '../../../store/rootReducer';
+
+const mapStateToProps = state => {
+  return {
+    component: getMeasuresAppComponent(state),
+    domains: getMeasuresAppHomeDomains(state),
+    periods: getMeasuresAppHomePeriods(state)
+  };
+};
+
+export default connect(mapStateToProps)(AllMeasures);
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/home/AllMeasuresDomain.js b/server/sonar-web/src/main/js/apps/component-measures-old/home/AllMeasuresDomain.js
new file mode 100644 (file)
index 0000000..1111a36
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import PropTypes from 'prop-types';
+import HomeMeasuresList from './HomeMeasuresList';
+import { getLocalizedMetricDomain } from '../../../helpers/l10n';
+
+export default function AllMeasuresDomain(props) {
+  const { domain, component, displayHeader } = props;
+
+  return (
+    <li>
+      {displayHeader &&
+        <header className="page-header">
+          <h3 className="page-title">
+            {getLocalizedMetricDomain(domain.name)}
+          </h3>
+        </header>}
+
+      <HomeMeasuresList domain={domain} component={component} />
+    </li>
+  );
+}
+
+AllMeasuresDomain.defaultProps = {
+  displayHeader: true
+};
+
+AllMeasuresDomain.propTypes = {
+  displayHeader: PropTypes.bool
+};
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/home/DomainMeasures.js b/server/sonar-web/src/main/js/apps/component-measures-old/home/DomainMeasures.js
new file mode 100644 (file)
index 0000000..22343bc
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import HomeMeasuresList from './HomeMeasuresList';
+import MeasureBubbleChartContainer from '../components/bubbleChart/MeasureBubbleChartContainer';
+import { hasBubbleChart } from '../utils';
+
+export default function DomainMeasures(props) {
+  const { component, domains } = props;
+  const { domainName } = props.params;
+  const domain = domains.find(d => d.name === domainName);
+
+  return (
+    <section id="component-measures-domain">
+      <HomeMeasuresList domain={domain} component={component} />
+
+      {hasBubbleChart(domainName) && <MeasureBubbleChartContainer domainName={domainName} />}
+    </section>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/home/DomainMeasuresContainer.js b/server/sonar-web/src/main/js/apps/component-measures-old/home/DomainMeasuresContainer.js
new file mode 100644 (file)
index 0000000..c442bfc
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { connect } from 'react-redux';
+import DomainMeasures from './DomainMeasures';
+import {
+  getMeasuresAppHomeDomains,
+  getMeasuresAppHomePeriods,
+  getMeasuresAppComponent
+} from '../../../store/rootReducer';
+
+const mapStateToProps = state => {
+  return {
+    component: getMeasuresAppComponent(state),
+    domains: getMeasuresAppHomeDomains(state),
+    periods: getMeasuresAppHomePeriods(state)
+  };
+};
+
+export default connect(mapStateToProps)(DomainMeasures);
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/home/Home.js b/server/sonar-web/src/main/js/apps/component-measures-old/home/Home.js
new file mode 100644 (file)
index 0000000..43ca784
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { Link, IndexLink } from 'react-router';
+import LeakPeriodLegend from '../components/LeakPeriodLegend';
+import { getLeakPeriod } from '../../../helpers/periods';
+import { translate, getLocalizedMetricDomain } from '../../../helpers/l10n';
+
+export default class Home extends React.PureComponent {
+  componentDidMount() {
+    document.querySelector('html').classList.add('dashboard-page');
+    this.props.onDisplay();
+    this.props.fetchMeasures();
+  }
+
+  componentWillUnmount() {
+    document.querySelector('html').classList.remove('dashboard-page');
+  }
+
+  render() {
+    const { component, domains, periods } = this.props;
+
+    if (domains == null) {
+      return null;
+    }
+
+    const leakPeriod = getLeakPeriod(periods);
+
+    return (
+      <section id="component-measures-home" className="page page-container page-limited">
+        <header id="component-measures-home-header" className="home-header">
+          <nav className="nav-pills pull-left">
+            <ul>
+              <li>
+                <IndexLink
+                  to={{ pathname: '/component_measures_old', query: { id: component.key } }}
+                  activeClassName="active">
+                  {translate('all')}
+                </IndexLink>
+              </li>
+              {domains.map(domain =>
+                <li key={domain.name}>
+                  <Link
+                    to={{
+                      pathname: `/component_measures_old/domain/${domain.name}`,
+                      query: { id: component.key }
+                    }}
+                    activeClassName="active">
+                    {getLocalizedMetricDomain(domain.name)}
+                  </Link>
+                </li>
+              )}
+            </ul>
+          </nav>
+
+          {leakPeriod != null && <LeakPeriodLegend component={component} period={leakPeriod} />}
+        </header>
+
+        <main id="component-measures-home-main">
+          {this.props.children}
+        </main>
+      </section>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/home/HomeContainer.js b/server/sonar-web/src/main/js/apps/component-measures-old/home/HomeContainer.js
new file mode 100644 (file)
index 0000000..0605a3a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { connect } from 'react-redux';
+import Home from './Home';
+import { fetchMeasures } from './actions';
+import { displayHome } from '../app/actions';
+import {
+  getMeasuresAppHomeDomains,
+  getMeasuresAppHomePeriods,
+  getMeasuresAppComponent
+} from '../../../store/rootReducer';
+
+const mapStateToProps = state => {
+  return {
+    component: getMeasuresAppComponent(state),
+    domains: getMeasuresAppHomeDomains(state),
+    periods: getMeasuresAppHomePeriods(state)
+  };
+};
+
+const mapDispatchToProps = dispatch => {
+  return {
+    onDisplay: () => dispatch(displayHome()),
+    fetchMeasures: () => dispatch(fetchMeasures())
+  };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(Home);
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/home/HomeMeasuresList.js b/server/sonar-web/src/main/js/apps/component-measures-old/home/HomeMeasuresList.js
new file mode 100644 (file)
index 0000000..7d70066
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { partition, sortBy } from 'lodash';
+import MeasuresList from './MeasuresList';
+import { domains } from '../config/domains';
+import { getLocalizedMetricName } from '../../../helpers/l10n';
+
+function sortMeasures(measures, order) {
+  const [known, unknown] = partition(measures, measure => order.includes(measure.metric.key));
+  return [
+    ...sortBy(known, measure => order.indexOf(measure.metric.key)),
+    ...sortBy(unknown, measure => getLocalizedMetricName(measure.metric))
+  ];
+}
+
+function filterIssuesMeasures(measures) {
+  const BANNED_MEASURES = [
+    'blocker_violations',
+    'new_blocker_violations',
+    'critical_violations',
+    'new_critical_violations',
+    'major_violations',
+    'new_major_violations',
+    'minor_violations',
+    'new_minor_violations',
+    'info_violations',
+    'new_info_violations'
+  ];
+  return measures.filter(measure => !BANNED_MEASURES.includes(measure.metric.key));
+}
+
+const HomeMeasuresList = ({ domain, component }) => {
+  const { measures, name } = domain;
+  const config = domains[name] || {};
+
+  const filteredMeasures = filterIssuesMeasures(measures);
+
+  const configMain = config.main || [];
+  const [mainMeasures, otherMeasures] = partition(filteredMeasures, measure =>
+    configMain.includes(measure.metric.key)
+  );
+
+  const configOrder = config.order || [];
+  const sortedMainMeasures = sortMeasures(mainMeasures, configOrder);
+  const sortedOtherMeasures = sortMeasures(otherMeasures, configOrder);
+
+  return (
+    <div className="home-measures-list clearfix">
+      {sortedMainMeasures.length > 0 &&
+        <MeasuresList
+          className="main-domain-measures"
+          measures={sortedMainMeasures}
+          component={component}
+          spaces={[]}
+        />}
+
+      {sortedOtherMeasures.length > 0 &&
+        <MeasuresList measures={sortedOtherMeasures} component={component} spaces={[]} />}
+    </div>
+  );
+};
+
+export default HomeMeasuresList;
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/home/MeasureListValue.js b/server/sonar-web/src/main/js/apps/component-measures-old/home/MeasureListValue.js
new file mode 100644 (file)
index 0000000..da121fc
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import Measure from '../components/Measure';
+import { isDiffMetric } from '../../../helpers/measures';
+
+const MeasureListValue = ({ measure }) => {
+  const { metric } = measure;
+
+  if (isDiffMetric(metric.key)) {
+    return (
+      <div
+        id={`measure-${measure.metric.key}-leak`}
+        className="domain-measures-value domain-measures-leak">
+        <Measure measure={measure} />
+      </div>
+    );
+  }
+
+  return (
+    <div id={`measure-${measure.metric.key}-value`} className="domain-measures-value">
+      <Measure measure={measure} />
+    </div>
+  );
+};
+
+export default MeasureListValue;
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/home/MeasuresList.js b/server/sonar-web/src/main/js/apps/component-measures-old/home/MeasuresList.js
new file mode 100644 (file)
index 0000000..d400cf4
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { Link } from 'react-router';
+import MeasureListValue from './MeasureListValue';
+import { getLocalizedMetricName } from '../../../helpers/l10n';
+import IssueTypeIcon from '../../../components/ui/IssueTypeIcon';
+
+const MeasuresList = ({ measures, component, className = 'domain-measures' }) => {
+  return (
+    <ul className={className}>
+      {measures.map(measure =>
+        <li key={measure.metric.key} id={`measure-${measure.metric.key}`}>
+          <Link
+            to={{
+              pathname: `/component_measures_old/metric/${measure.metric.key}`,
+              query: { id: component.key }
+            }}>
+            <div className="domain-measures-name">
+              <IssueTypeIcon query={measure.metric.key} className="little-spacer-right" />
+              <span id={`measure-${measure.metric.key}-name`}>
+                {getLocalizedMetricName(measure.metric)}
+              </span>
+            </div>
+
+            <MeasureListValue measure={measure} />
+          </Link>
+        </li>
+      )}
+    </ul>
+  );
+};
+
+export default MeasuresList;
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/home/actions.js b/server/sonar-web/src/main/js/apps/component-measures-old/home/actions.js
new file mode 100644 (file)
index 0000000..6ae4585
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { startFetching, stopFetching } from '../store/statusActions';
+import { getMeasuresAndMeta } from '../../../api/measures';
+import { getLeakValue } from '../utils';
+import { getMeasuresAppComponent, getMeasuresAppAllMetrics } from '../../../store/rootReducer';
+
+export const RECEIVE_MEASURES = 'measuresApp/home/RECEIVE_MEASURES';
+
+export function receiveMeasures(measures, periods) {
+  return { type: RECEIVE_MEASURES, measures, periods };
+}
+
+function banQualityGate(component, measures) {
+  let newMeasures = [...measures];
+
+  if (!['VW', 'SVW', 'APP'].includes(component.qualifier)) {
+    newMeasures = newMeasures.filter(measure => measure.metric !== 'alert_status');
+  }
+
+  if (component.qualifier === 'APP') {
+    newMeasures = newMeasures.filter(
+      measure =>
+        measure.metric !== 'releasability_rating' && measure.metric !== 'releasability_effort'
+    );
+  }
+
+  return newMeasures;
+}
+
+export function fetchMeasures() {
+  return (dispatch, getState) => {
+    dispatch(startFetching());
+
+    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')
+      .map(metric => metric.key);
+
+    getMeasuresAndMeta(component.key, metricKeys, { additionalFields: 'periods' }).then(r => {
+      const measures = banQualityGate(component, r.component.measures)
+        .map(measure => {
+          const metric = metrics.find(metric => metric.key === measure.metric);
+          const leak = getLeakValue(measure);
+          return { ...measure, metric, leak };
+        })
+        .filter(measure => {
+          const hasValue = measure.value != null;
+          const hasLeakValue = measure.leak != null;
+          return hasValue || hasLeakValue;
+        });
+
+      const newBugs = measures.find(measure => measure.metric.key === 'new_bugs');
+
+      const applicationPeriods = newBugs ? [{ index: 1 }] : [];
+      const periods = component.qualifier === 'APP' ? applicationPeriods : r.periods;
+
+      dispatch(receiveMeasures(measures, periods));
+      dispatch(stopFetching());
+    });
+  };
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/home/reducer.js b/server/sonar-web/src/main/js/apps/component-measures-old/home/reducer.js
new file mode 100644 (file)
index 0000000..e752229
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { groupBy, partition, sortBy, toPairs } from 'lodash';
+import { RECEIVE_MEASURES } from './actions';
+import { getLocalizedMetricName } from '../../../helpers/l10n';
+
+const initialState = {
+  measures: undefined,
+  domains: undefined,
+  periods: undefined
+};
+
+function groupByDomains(measures) {
+  const KNOWN_DOMAINS = [
+    'Releasability',
+    'Reliability',
+    'Security',
+    'Maintainability',
+    'Coverage',
+    'Duplications',
+    'Size',
+    'Complexity'
+  ];
+
+  const domains = sortBy(
+    toPairs(groupBy(measures, measure => measure.metric.domain)).map(r => {
+      const [name, measures] = r;
+      const sortedMeasures = sortBy(measures, measure => getLocalizedMetricName(measure.metric));
+
+      return { name, measures: sortedMeasures };
+    }),
+    'name'
+  );
+  const [knownDomains, unknownDomains] = partition(domains, domain =>
+    KNOWN_DOMAINS.includes(domain.name)
+  );
+  return [
+    ...sortBy(knownDomains, domain => KNOWN_DOMAINS.indexOf(domain.name)),
+    ...sortBy(unknownDomains, domain => domain.name)
+  ];
+}
+
+export default function(state = initialState, action = {}) {
+  switch (action.type) {
+    case RECEIVE_MEASURES:
+      return {
+        ...state,
+        measures: action.measures,
+        domains: groupByDomains(action.measures),
+        periods: action.periods
+      };
+    default:
+      return state;
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/hooks.js b/server/sonar-web/src/main/js/apps/component-measures-old/hooks.js
new file mode 100644 (file)
index 0000000..001948f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { isDiffMetric } from '../../helpers/measures';
+
+export function checkHistoryExistence(nextState, replace) {
+  const { metricKey } = nextState.params;
+
+  if (isDiffMetric(metricKey)) {
+    replace({
+      pathname: metricKey,
+      query: nextState.location.query
+    });
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/routes.js b/server/sonar-web/src/main/js/apps/component-measures-old/routes.js
new file mode 100644 (file)
index 0000000..a57af5a
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+const routes = [
+  {
+    getComponent(_, callback) {
+      import('./app/AppContainer').then(i => callback(null, i.default));
+    },
+    childRoutes: [
+      {
+        getComponent(_, callback) {
+          import('./home/HomeContainer').then(i => callback(null, i.default));
+        },
+        childRoutes: [
+          {
+            getIndexRoute(_, callback) {
+              import('./home/AllMeasuresContainer').then(i =>
+                callback(null, { component: i.default })
+              );
+            }
+          },
+          {
+            path: 'domain/:domainName',
+            getComponent(_, callback) {
+              import('./home/DomainMeasuresContainer').then(i => callback(null, i.default));
+            }
+          }
+        ]
+      },
+      {
+        path: 'metric/:metricKey',
+        getComponent(_, callback) {
+          import('./details/MeasureDetailsContainer').then(i => callback(null, i.default));
+        },
+        childRoutes: [
+          {
+            indexRoute: {
+              onEnter(nextState, replace) {
+                const { params, location } = nextState;
+                replace({
+                  pathname: `/component_measures_old/metric/${params.metricKey}/list`,
+                  query: location.query
+                });
+              }
+            }
+          },
+          {
+            path: 'list',
+            getComponent(_, callback) {
+              import('./details/drilldown/ListViewContainer').then(i => callback(null, i.default));
+            }
+          },
+          {
+            path: 'tree',
+            getComponent(_, callback) {
+              import('./details/drilldown/TreeViewContainer').then(i => callback(null, i.default));
+            }
+          },
+          {
+            path: 'history',
+            onEnter(nextState, replace) {
+              replace({
+                pathname: '/project/activity',
+                query: {
+                  id: nextState.location.query.id,
+                  graph: 'custom',
+                  custom_metrics: nextState.params.metricKey
+                }
+              });
+            }
+          },
+          {
+            path: 'treemap',
+            getComponent(_, callback) {
+              import('./details/treemap/MeasureTreemapContainer').then(i =>
+                callback(null, i.default)
+              );
+            }
+          }
+        ]
+      }
+    ]
+  }
+];
+
+export default routes;
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/store/listViewActions.js b/server/sonar-web/src/main/js/apps/component-measures-old/store/listViewActions.js
new file mode 100644 (file)
index 0000000..2bbd93d
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { getComponentTree } from '../../../api/components';
+import { enhanceWithMeasure } from '../utils';
+import { startFetching, stopFetching } from './statusActions';
+import complementary from '../config/complementary';
+import { getMeasuresAppList } from '../../../store/rootReducer';
+
+export const UPDATE_STORE = 'measuresApp/drilldown/list/UPDATE_STORE';
+
+function updateStore(state) {
+  return { type: UPDATE_STORE, state };
+}
+
+function getComplementary(metric) {
+  const comp = complementary[metric] || [];
+  return [metric, ...comp];
+}
+
+function makeRequest(baseComponent, metric, options, periodIndex = 1) {
+  const asc = metric.direction === 1;
+  const ps = 100;
+  const finalOptions = { asc, ps, metricSortFilter: 'withMeasuresOnly' };
+
+  if (metric.key.indexOf('new_') === 0) {
+    Object.assign(options, {
+      s: 'metricPeriod,name',
+      metricSort: metric.key,
+      metricPeriodSort: periodIndex
+    });
+  } else {
+    Object.assign(options, {
+      s: 'metric,name',
+      metricSort: metric.key
+    });
+  }
+
+  Object.assign(finalOptions, options);
+  return getComponentTree('leaves', baseComponent.key, getComplementary(metric.key), finalOptions);
+}
+
+function fetchLeaves(baseComponent, metric, pageIndex = 1, periodIndex = 1) {
+  const options = { p: pageIndex };
+
+  return makeRequest(baseComponent, metric, options, periodIndex).then(r => {
+    const nextComponents = enhanceWithMeasure(r.components, metric.key, periodIndex);
+
+    return {
+      components: nextComponents,
+      pageIndex: r.paging.pageIndex,
+      total: r.paging.total
+    };
+  });
+}
+
+/**
+ * Fetch the first page of components for a given base component
+ * @param baseComponent
+ * @param metric
+ * @param periodIndex
+ */
+export function fetchList(baseComponent, metric, periodIndex = 1) {
+  return (dispatch, getState) => {
+    const list = getMeasuresAppList(getState());
+    if (list.baseComponent === baseComponent && list.metric === metric) {
+      return Promise.resolve();
+    }
+
+    dispatch(startFetching());
+    return fetchLeaves(baseComponent, metric, 1, periodIndex).then(r => {
+      dispatch(
+        updateStore({
+          ...r,
+          baseComponent,
+          metric
+        })
+      );
+      dispatch(stopFetching());
+    });
+  };
+}
+
+export function fetchMore(periodIndex) {
+  return (dispatch, getState) => {
+    const { baseComponent, metric, pageIndex, components } = getMeasuresAppList(getState());
+    dispatch(startFetching());
+    return fetchLeaves(baseComponent, metric, pageIndex + 1, periodIndex).then(r => {
+      const nextComponents = [...components, ...r.components];
+      dispatch(updateStore({ ...r, components: nextComponents }));
+      dispatch(stopFetching());
+    });
+  };
+}
+
+/**
+ * Select specified component from the list
+ * @param component A component to select
+ */
+export function selectComponent(component) {
+  return dispatch => {
+    dispatch(updateStore({ selected: component }));
+  };
+}
+
+/**
+ * Select next element from the list of components
+ */
+export function selectNext() {
+  return (dispatch, getState) => {
+    const { components, selected } = getMeasuresAppList(getState());
+    const selectedIndex = components.indexOf(selected);
+    if (selectedIndex < components.length - 1) {
+      const nextSelected = components[selectedIndex + 1];
+      dispatch(selectComponent(nextSelected));
+    }
+  };
+}
+
+/**
+ * Select previous element from the list of components
+ */
+export function selectPrevious() {
+  return (dispatch, getState) => {
+    const { components, selected } = getMeasuresAppList(getState());
+    const selectedIndex = components.indexOf(selected);
+    if (selectedIndex > 0) {
+      const nextSelected = components[selectedIndex - 1];
+      dispatch(selectComponent(nextSelected));
+    }
+  };
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/store/listViewReducer.js b/server/sonar-web/src/main/js/apps/component-measures-old/store/listViewReducer.js
new file mode 100644 (file)
index 0000000..ee8f9ae
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { DISPLAY_HOME } from './../app/actions';
+import { UPDATE_STORE } from './listViewActions';
+
+const initialState = {
+  components: [],
+  total: 0
+};
+
+export default function drilldownReducer(state = initialState, action = {}) {
+  switch (action.type) {
+    case DISPLAY_HOME:
+      return initialState;
+    case UPDATE_STORE:
+      return { ...state, ...action.state };
+    default:
+      return state;
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/store/rootReducer.js b/server/sonar-web/src/main/js/apps/component-measures-old/store/rootReducer.js
new file mode 100644 (file)
index 0000000..079a7e4
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { 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-old/store/statusActions.js b/server/sonar-web/src/main/js/apps/component-measures-old/store/statusActions.js
new file mode 100644 (file)
index 0000000..d07feba
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+export const START_FETCHING = 'measuresApp/status/START_FETCHING';
+export const STOP_FETCHING = 'measuresApp/status/STOP_FETCHING';
+
+export function startFetching() {
+  return { type: START_FETCHING };
+}
+
+export function stopFetching() {
+  return { type: STOP_FETCHING };
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/store/statusReducer.js b/server/sonar-web/src/main/js/apps/component-measures-old/store/statusReducer.js
new file mode 100644 (file)
index 0000000..1a993be
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { START_FETCHING, STOP_FETCHING } from './statusActions';
+
+const initialState = {
+  fetching: false
+};
+
+export default function drilldownReducer(state = initialState, action = {}) {
+  switch (action.type) {
+    case START_FETCHING:
+      return { ...state, fetching: true };
+    case STOP_FETCHING:
+      return { ...state, fetching: false };
+    default:
+      return state;
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/store/treeViewActions.js b/server/sonar-web/src/main/js/apps/component-measures-old/store/treeViewActions.js
new file mode 100644 (file)
index 0000000..34fffe1
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { initial } from 'lodash';
+import { getComponentTree } from '../../../api/components';
+import { enhanceWithMeasure } from '../utils';
+import { startFetching, stopFetching } from './statusActions';
+import complementary from '../config/complementary';
+import { getMeasuresAppTree } from '../../../store/rootReducer';
+
+/*
+ * Actions
+ */
+
+export const UPDATE_STORE = 'measuresApp/drilldown/tree/UPDATE_STORE';
+export const INIT = 'measuresApp/drilldown/tree/INIT';
+
+/*
+ * Action Creators
+ */
+
+/**
+ * Internal
+ * Update store
+ * @param state
+ * @returns {{type: string, state: *}}
+ */
+function updateStore(state) {
+  return { type: UPDATE_STORE, state };
+}
+
+/**
+ * Init tree view drilldown for the given root component and given metric
+ * @param rootComponent
+ * @param metric
+ * @param periodIndex
+ * @returns {{type: string, rootComponent: *, metric: *}}
+ */
+function init(rootComponent, metric, periodIndex = 1) {
+  return { type: INIT, rootComponent, metric, periodIndex };
+}
+
+/*
+ * Workflow
+ */
+
+function getComplementary(metric) {
+  const comp = complementary[metric] || [];
+  return [metric, ...comp];
+}
+
+function makeRequest(rootComponent, baseComponent, metric, options, periodIndex = 1) {
+  const asc = metric.direction === 1;
+  const ps = 100;
+  const finalOptions = { asc, ps, metricSortFilter: 'withMeasuresOnly' };
+
+  if (metric.key.indexOf('new_') === 0) {
+    Object.assign(options, {
+      s: 'metricPeriod,name',
+      metricSort: metric.key,
+      metricPeriodSort: periodIndex
+    });
+  } else {
+    Object.assign(options, {
+      s: 'metric,name',
+      metricSort: metric.key
+    });
+  }
+
+  if (rootComponent.qualifier === 'DEV' && baseComponent.qualifier !== 'DEV') {
+    Object.assign(options, { developerId: rootComponent.id });
+  }
+
+  Object.assign(finalOptions, options);
+
+  const finalKey = baseComponent.refKey || baseComponent.key;
+
+  return getComponentTree('children', finalKey, getComplementary(metric.key), finalOptions);
+}
+
+function fetchComponents(rootComponent, baseComponent, metric, pageIndex = 1, periodIndex = 1) {
+  const options = { p: pageIndex };
+
+  return makeRequest(rootComponent, baseComponent, metric, options, periodIndex).then(r => {
+    const nextComponents = enhanceWithMeasure(r.components, metric.key, periodIndex);
+
+    return {
+      baseComponent,
+      components: nextComponents,
+      pageIndex: r.paging.pageIndex,
+      total: r.paging.total
+    };
+  });
+}
+
+/**
+ * Fetch the first page of components for a given base component
+ * @param baseComponent
+ */
+function fetchList(baseComponent) {
+  return (dispatch, getState) => {
+    const { metric, periodIndex, rootComponent } = getMeasuresAppTree(getState());
+
+    dispatch(startFetching());
+    return fetchComponents(rootComponent, baseComponent, metric, 1, periodIndex).then(r => {
+      dispatch(
+        updateStore({
+          ...r,
+          baseComponent,
+          breadcrumbs: [baseComponent]
+        })
+      );
+      dispatch(stopFetching());
+    });
+  };
+}
+
+/**
+ * Init tree view with root component and metric.
+ * Fetch the first page of components if needed.
+ * @param rootComponent
+ * @param metric
+ * @param periodIndex
+ * @returns {function()}
+ */
+export function start(rootComponent, metric, periodIndex = 1) {
+  return (dispatch, getState) => {
+    const tree = getMeasuresAppTree(getState());
+    if (rootComponent === tree.rootComponent && metric === tree.metric) {
+      return Promise.resolve();
+    }
+
+    dispatch(init(rootComponent, metric, periodIndex));
+    dispatch(fetchList(rootComponent));
+  };
+}
+
+/**
+ * Drilldown to the component
+ * @param component
+ */
+export function drilldown(component) {
+  return (dispatch, getState) => {
+    const { metric, rootComponent, breadcrumbs, periodIndex } = getMeasuresAppTree(getState());
+    dispatch(startFetching());
+    return fetchComponents(rootComponent, component, metric, 1, periodIndex).then(r => {
+      dispatch(
+        updateStore({
+          ...r,
+          breadcrumbs: [...breadcrumbs, component],
+          selected: undefined
+        })
+      );
+      dispatch(stopFetching());
+    });
+  };
+}
+
+/**
+ * Go up using breadcrumbs
+ * @param component
+ */
+export function useBreadcrumbs(component) {
+  return (dispatch, getState) => {
+    const { metric, rootComponent, breadcrumbs, periodIndex } = getMeasuresAppTree(getState());
+    const index = breadcrumbs.indexOf(component);
+    dispatch(startFetching());
+    return fetchComponents(rootComponent, component, metric, 1, periodIndex).then(r => {
+      dispatch(
+        updateStore({
+          ...r,
+          breadcrumbs: breadcrumbs.slice(0, index + 1),
+          selected: undefined
+        })
+      );
+      dispatch(stopFetching());
+    });
+  };
+}
+
+export function fetchMore() {
+  return (dispatch, getState) => {
+    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];
+      dispatch(updateStore({ ...r, components: nextComponents }));
+      dispatch(stopFetching());
+    });
+  };
+}
+
+/**
+ * Select given component from the list
+ * @param component
+ */
+export function selectComponent(component) {
+  return (dispatch, getState) => {
+    const { breadcrumbs } = getMeasuresAppTree(getState());
+    const nextBreadcrumbs = [...breadcrumbs, component];
+    dispatch(
+      updateStore({
+        selected: component,
+        breadcrumbs: nextBreadcrumbs
+      })
+    );
+  };
+}
+
+/**
+ * Select next element from the list of components
+ */
+export function selectNext() {
+  return (dispatch, getState) => {
+    const { components, selected, breadcrumbs } = getMeasuresAppTree(getState());
+    const selectedIndex = components.indexOf(selected);
+    if (selectedIndex < components.length - 1) {
+      const nextSelected = components[selectedIndex + 1];
+      const nextBreadcrumbs = [...initial(breadcrumbs), nextSelected];
+      dispatch(
+        updateStore({
+          selected: nextSelected,
+          breadcrumbs: nextBreadcrumbs
+        })
+      );
+    }
+  };
+}
+
+/**
+ * Select previous element from the list of components
+ */
+export function selectPrevious() {
+  return (dispatch, getState) => {
+    const { components, selected, breadcrumbs } = getMeasuresAppTree(getState());
+    const selectedIndex = components.indexOf(selected);
+    if (selectedIndex > 0) {
+      const nextSelected = components[selectedIndex - 1];
+      const nextBreadcrumbs = [...initial(breadcrumbs), nextSelected];
+      dispatch(
+        updateStore({
+          selected: nextSelected,
+          breadcrumbs: nextBreadcrumbs
+        })
+      );
+    }
+  };
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/store/treeViewReducer.js b/server/sonar-web/src/main/js/apps/component-measures-old/store/treeViewReducer.js
new file mode 100644 (file)
index 0000000..71050fd
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { pick } from 'lodash';
+import { DISPLAY_HOME } from './../app/actions';
+import { UPDATE_STORE, INIT } from './treeViewActions';
+
+const initialState = {
+  components: [],
+  breadcrumbs: [],
+  total: 0
+};
+
+export default function drilldownReducer(state = initialState, action = {}) {
+  switch (action.type) {
+    case DISPLAY_HOME:
+      return initialState;
+    case UPDATE_STORE:
+      return { ...state, ...action.state };
+    case INIT:
+      return { ...state, ...pick(action, ['rootComponent', 'metric', 'periodIndex']) };
+    default:
+      return state;
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/styles.css b/server/sonar-web/src/main/js/apps/component-measures-old/styles.css
new file mode 100644 (file)
index 0000000..b72fcf3
--- /dev/null
@@ -0,0 +1,404 @@
+.home-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+  margin-bottom: 20px;
+}
+
+.measures-domains {
+}
+
+.measures-domains > li {
+  margin-bottom: 20px;
+}
+
+.measures-domains > li > div {
+  border: 1px solid #e6e6e6;
+  background-color: #fff;
+}
+
+.measures-domains-leak-header {
+  line-height: 22px;
+  padding: 0 10px;
+  border: 1px solid #eae3c7;
+  background-color: #fbf3d5;
+  white-space: nowrap;
+}
+
+.main-domain-measures {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: space-around;
+  float: left;
+  width: 480px;
+  margin-right: 60px;
+}
+
+.main-domain-measures > li {
+  padding: 12px 0;
+}
+
+.main-domain-measures > li > a {
+  display: flex;
+  flex-direction: column-reverse;
+  width: 160px;
+  border: none;
+  text-align: center;
+}
+
+.main-domain-measures .domain-measures-value {
+  height: 40px;
+  box-sizing: border-box;
+  color: #444;
+  font-size: 30px;
+  font-weight: 300;
+}
+
+.main-domain-measures .domain-measures-value .rating,
+.measure-details-value .rating {
+  vertical-align: top;
+  width: 40px;
+  height: 40px;
+  line-height: 40px;
+  border-radius: 40px;
+  font-size: 24px;
+}
+
+.main-domain-measures .domain-measures-name {
+  margin-top: 8px;
+}
+
+.main-domain-measures .domain-measures-name > span:last-child {
+  border-bottom: 1px solid #cae3f2;
+}
+
+.main-domain-measures .domain-measures-leak {
+  margin: 0 20px;
+  border: 1px solid #eae3c7;
+  background-color: #fbf3d5;
+}
+
+.domain-measures {
+  overflow: hidden;
+  line-height: 1.4;
+}
+
+.domain-measures > li > a {
+  display: flex;
+  justify-content: space-between;
+  border: none;
+}
+
+.domain-measures > li:nth-child(odd) > a {
+  background-color: #f8f8f8;
+}
+
+.domain-measures > li > a:hover {
+  background-color: #ecf6fe !important;
+}
+
+.domain-measures .domain-measures-name,
+.domain-measures .domain-measures-value {
+  padding: 7px 10px;
+  box-sizing: border-box;
+}
+
+.domain-measures .domain-measures-name {
+  width: calc(100% - 160px);
+  line-height: 24px;
+}
+
+.domain-measures .domain-measures-name > span {
+  border-bottom: 1px solid #cae3f2;
+}
+
+.domain-measures .domain-measures-value {
+  min-width: 80px;
+  color: #444;
+  text-align: right;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.domain-measures .domain-measures-leak {
+  background-color: #fbf3d5;
+  transition: background-color 0.3s ease;
+}
+
+.domain-measures .domain-measures > li:nth-child(odd) .domain-measures-leak {
+  background-color: #f5eed0;
+}
+
+.measure-details {
+  margin-top: 10px;
+}
+
+.measure-details-header {
+  position: relative;
+  margin-top: 10px;
+  margin-bottom: 30px;
+}
+
+.measure-details-metric,
+.measure-details-value {
+}
+
+.measure-details-metric {
+  display: inline-block;
+  margin-bottom: 10px;
+}
+
+.measure-details-metric > a:not(.button) {
+  border: none;
+  color: #444;
+}
+
+.measure-details-metric > a:not(.button):hover {
+  color: #236a97;
+}
+
+.measure-details-value {
+  font-size: 24px;
+}
+
+.measure-details-value-absolute {
+  display: inline-block;
+  vertical-align: middle;
+  padding: 5px 0;
+  font-weight: 300;
+}
+
+.measure-details-value-leak {
+  display: inline-block;
+  vertical-align: middle;
+  padding: 4px 10px;
+  border: 1px solid #eae3c7;
+  background-color: #fbf3d5;
+  font-weight: 300;
+}
+
+.measure-details-value-absolute + .measure-details-value-leak {
+  margin-left: 20px;
+}
+
+.measure-details-secondary {
+  display: inline-block;
+  vertical-align: middle;
+  width: 260px;
+  margin-left: 20px;
+}
+
+.measure-details-drilldown {
+  margin-top: 20px;
+}
+
+.measure-details-drilldown-mode {
+  display: flex;
+  margin-bottom: 10px;
+  border-bottom: 1px solid #e6e6e6;
+}
+
+.measure-details-drilldown-mode > li {
+  margin-bottom: -1px;
+}
+
+.measure-details-drilldown-mode > li + li {
+  margin-left: 2px;
+}
+
+.measure-details-drilldown-mode > li > a {
+  display: inline-block;
+  padding: 5px 10px;
+  border-bottom: 2px solid transparent;
+  color: #444;
+}
+
+.measure-details-drilldown-mode > li > a:hover,
+.measure-details-drilldown-mode > li > a.active {
+  border-bottom-color: #4b9fd5;
+}
+
+.measure-details-drilldown-mode > li > a.active .measure-tab-icon path {
+  fill: #4b9fd5;
+}
+
+.measure-details-plain-list {
+}
+
+.measure-details-components {
+  width: 300px;
+  padding: 10px;
+  box-sizing: border-box;
+}
+
+.measure-details-components > li > a {
+  display: flex;
+  padding-top: 5px;
+  padding-bottom: 5px;
+  border: none;
+  color: #444;
+}
+
+.measure-details-components > li > a:hover,
+.measure-details-components > li > a.selected {
+  background-color: #cae3f2 !important;
+}
+
+.measure-details-component-name,
+.measure-details-component-value {
+  padding-right: 10px;
+  box-sizing: border-box;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.measure-details-component-name {
+  width: calc(100% - 60px);
+  padding-left: 10px;
+}
+
+.measure-details-component-value {
+  width: 60px;
+  text-align: right;
+}
+
+.measure-details-viewer {
+  min-height: 100vh;
+}
+
+.measure-details-viewer-header {
+  margin-bottom: 10px;
+  line-height: 24px;
+}
+
+.measure-details-viewer-header .button-group {
+  vertical-align: top;
+}
+
+.measure-details-header-container {
+  display: inline-block;
+  line-height: 16px;
+  padding-right: 10px;
+}
+
+.measure-tab-icon {
+  display: inline-block;
+  width: 14px;
+  height: 14px;
+  margin-right: 6px;
+}
+
+.measure-tab-icon path {
+  fill: #aeaeae;
+  transition: fill 0.3s ease;
+}
+
+.measure-details-components-up-icon path {
+  fill: #aeaeae;
+}
+
+.measure-details-history {
+  padding: 10px 0;
+}
+
+.measure-details-bubble-chart {
+  position: relative;
+  margin: 40px 0 10px;
+  padding: 30px 0 30px 60px;
+  border: 1px solid #e6e6e6;
+  background-color: #fff;
+}
+
+.measure-details-bubble-chart-axis {
+  position: absolute;
+  color: #777;
+  font-size: 12px;
+}
+
+.measure-details-bubble-chart-axis.x {
+  left: 50%;
+  bottom: 10px;
+  width: 500px;
+  margin-left: -250px;
+  text-align: center;
+}
+
+.measure-details-bubble-chart-axis.y {
+  top: 50%;
+  left: -20px;
+  transform: rotate(-90deg);
+}
+
+.measure-details-bubble-chart-axis.size {
+  left: 50%;
+  top: 10px;
+  width: 500px;
+  margin-left: -250px;
+  text-align: center;
+}
+
+.measure-details-treemap {
+  margin: 20px 0;
+}
+
+.measure-details-treemap-legend {
+  margin-bottom: 10px;
+}
+
+.component-measures-breadcrumbs {
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.component-measures-breadcrumbs > li {
+  padding: 5px 5px 3px;
+}
+
+.component-measures-breadcrumbs > li:first-child {
+  padding-left: 0;
+}
+
+.component-measures-breadcrumbs > li::after {
+  position: relative;
+  top: -1px;
+  padding-left: 10px;
+  color: #777;
+  font-size: 11px;
+  content: ">";
+}
+
+.component-measures-breadcrumbs > li:last-child::after {
+  display: none;
+}
+
+.home-measures-list {
+  border: 1px solid #e6e6e6;
+  background-color: #fff;
+}
+
+.nav-pills > ul {
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.nav-pills > ul > li > a {
+  display: inline-block;
+  vertical-align: middle;
+  padding: 3px 10px;
+  border: 1px solid transparent;
+  border-radius: 24px;
+  color: #236a97;
+  transition: none;
+}
+
+.nav-pills > ul > li > a:hover {
+  border-color: #236a97;
+}
+
+.nav-pills > ul > li.active > a,
+.nav-pills > ul > li > a.active {
+  background-color: #236a97;
+  color: #fff;
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures-old/utils.js b/server/sonar-web/src/main/js/apps/component-measures-old/utils.js
new file mode 100644 (file)
index 0000000..20595c7
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import bubbles from './config/bubbles';
+import {
+  formatMeasure,
+  formatMeasureVariation,
+  getRatingTooltip as nextGetRatingTooltip,
+  isDiffMetric
+} from '../../helpers/measures';
+
+export function getLeakValue(measure, periodIndex = 1) {
+  if (!measure) {
+    return null;
+  }
+
+  const period = measure.periods
+    ? measure.periods.find(period => period.index === periodIndex)
+    : null;
+
+  return period ? period.value : null;
+}
+
+export function getSingleMeasureValue(measures) {
+  if (!measures || !measures.length) {
+    return null;
+  }
+
+  return measures[0].value;
+}
+
+export function getSingleLeakValue(measures, periodIndex = 1) {
+  if (!measures || !measures.length) {
+    return null;
+  }
+
+  const measure = measures[0];
+
+  const period = measure.periods
+    ? measure.periods.find(period => period.index === periodIndex)
+    : null;
+
+  return period ? period.value : null;
+}
+
+export function formatLeak(value, metric, options) {
+  if (isDiffMetric(metric.key)) {
+    return formatMeasure(value, metric.type, options);
+  } else {
+    return formatMeasureVariation(value, metric.type, options);
+  }
+}
+
+export function enhanceWithLeak(measures, periodIndex = 1) {
+  function enhanceSingle(measure) {
+    return { ...measure, leak: getLeakValue(measure, periodIndex) };
+  }
+
+  if (Array.isArray(measures)) {
+    return measures.map(enhanceSingle);
+  } else {
+    return enhanceSingle(measures);
+  }
+}
+
+export function enhanceWithSingleMeasure(components, periodIndex = 1) {
+  return components.map(component => {
+    return {
+      ...component,
+      value: getSingleMeasureValue(component.measures),
+      leak: getSingleLeakValue(component.measures, periodIndex)
+    };
+  });
+}
+
+export function enhanceWithMeasure(components, metric, periodIndex = 1) {
+  return components.map(component => {
+    const measuresWithLeak = enhanceWithLeak(component.measures, periodIndex);
+    const measure = measuresWithLeak.find(measure => measure.metric === metric);
+    const value = measure ? measure.value : null;
+    const leak = measure ? measure.leak : null;
+    return { ...component, value, leak, measures: measuresWithLeak };
+  });
+}
+
+export function hasBubbleChart(domainName) {
+  return !!bubbles[domainName];
+}
+
+export function hasTreemap(metric) {
+  return ['PERCENT', 'RATING', 'LEVEL'].indexOf(metric.type) !== -1;
+}
+
+export function filterOutEmptyMeasures(components) {
+  return components.filter(component => component.value !== null || component.leak !== null);
+}
+
+export function getRatingTooltip(metricKey, value) {
+  const finalMetricKey = metricKey.indexOf('new_') === 0 ? metricKey.substr(4) : metricKey;
+  const KNOWN_RATINGS = ['sqale_rating', 'reliability_rating', 'security_rating'];
+  if (KNOWN_RATINGS.includes(finalMetricKey)) {
+    return nextGetRatingTooltip(finalMetricKey, value);
+  }
+  return null;
+}
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
deleted file mode 100644 (file)
index fd7caef..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import Helmet from 'react-helmet';
-import Spinner from './../components/Spinner';
-import { translate } from '../../../helpers/l10n';
-import '../styles.css';
-
-export default class App extends React.PureComponent {
-  state = { componentSet: false };
-
-  componentDidMount() {
-    this.props.setComponent(this.props.component);
-    this.props.fetchMetrics();
-    this.setState({ componentSet: true });
-  }
-
-  render() {
-    if (this.props.metrics == null || !this.state.componentSet) {
-      return <Spinner />;
-    }
-
-    return (
-      <main id="component-measures">
-        <Helmet title={translate('layout.measures')} />
-        {this.props.children}
-      </main>
-    );
-  }
-}
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
deleted file mode 100644 (file)
index dca2e1e..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { connect } from 'react-redux';
-import App from './App';
-import { fetchMetrics, setComponent } from './actions';
-import { getComponent, getMeasuresAppAllMetrics } from '../../../store/rootReducer';
-
-const mapStateToProps = (state, ownProps) => ({
-  component: getComponent(state, ownProps.location.query.id),
-  metrics: getMeasuresAppAllMetrics(state)
-});
-
-const mapDispatchToProps = dispatch => {
-  return {
-    fetchMetrics: () => dispatch(fetchMetrics()),
-    setComponent: component => dispatch(setComponent(component))
-  };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(App);
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
deleted file mode 100644 (file)
index 7cfb8ac..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { getMetrics } from '../../../api/metrics';
-
-/*
- * Actions
- */
-
-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
- */
-
-export function displayHome() {
-  return { type: DISPLAY_HOME };
-}
-
-function receiveMetrics(metrics) {
-  return { type: RECEIVE_METRICS, metrics };
-}
-
-export function setComponent(component) {
-  return { type: SET_COMPONENT, component };
-}
-
-/*
- * Workflow
- */
-
-export function fetchMetrics() {
-  return dispatch => {
-    getMetrics().then(metrics => {
-      dispatch(receiveMetrics(metrics));
-    });
-  };
-}
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
deleted file mode 100644 (file)
index 165b79c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { RECEIVE_METRICS, SET_COMPONENT } from './actions';
-
-const initialState = {
-  metrics: undefined
-};
-
-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/IconBubbles.js b/server/sonar-web/src/main/js/apps/component-measures/components/IconBubbles.js
deleted file mode 100644 (file)
index 130adcc..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-
-export default function IconBubbles() {
-  /* eslint max-len: 0 */
-  return (
-    <svg
-      className="measure-tab-icon"
-      viewBox="0 0 512 448"
-      fillRule="evenodd"
-      clipRule="evenodd"
-      strokeLinejoin="round"
-      strokeMiterlimit="1.414">
-      <path d="M352 256c52.984 0 96 43.016 96 96s-43.016 96-96 96-96-43.016-96-96 43.016-96 96-96zM128 96c70.645 0 128 57.355 128 128 0 70.645-57.355 128-128 128C57.355 352 0 294.645 0 224 0 153.355 57.355 96 128 96zM352 0c52.984 0 96 43.016 96 96s-43.016 96-96 96-96-43.016-96-96 43.016-96 96-96z" />
-    </svg>
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/IconList.js b/server/sonar-web/src/main/js/apps/component-measures/components/IconList.js
deleted file mode 100644 (file)
index df6d69e..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-
-export default function ListIcon() {
-  /* eslint max-len: 0 */
-  return (
-    <svg
-      className="measure-tab-icon"
-      viewBox="0 0 448 448"
-      fillRule="evenodd"
-      clipRule="evenodd"
-      strokeLinejoin="round"
-      strokeMiterlimit="1.414">
-      <path d="M448 48c0-8.83-7.17-16-16-16H16C7.17 32 0 39.17 0 48v32c0 8.83 7.17 16 16 16h416c8.83 0 16-7.17 16-16V48zM448 144c0-8.83-7.17-16-16-16H16c-8.83 0-16 7.17-16 16v32c0 8.83 7.17 16 16 16h416c8.83 0 16-7.17 16-16v-32zM448 240c0-8.83-7.17-16-16-16H16c-8.83 0-16 7.17-16 16v32c0 8.83 7.17 16 16 16h416c8.83 0 16-7.17 16-16v-32zM448 336.03c0-8.83-7.17-16-16-16H16c-8.83 0-16 7.17-16 16v32c0 8.83 7.17 16 16 16h416c8.83 0 16-7.17 16-16v-32z" />
-    </svg>
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/IconTree.js b/server/sonar-web/src/main/js/apps/component-measures/components/IconTree.js
deleted file mode 100644 (file)
index 9270286..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-
-export default function IconTree() {
-  /* eslint max-len: 0 */
-  return (
-    <svg
-      className="measure-tab-icon"
-      viewBox="0 0 448 448"
-      fillRule="evenodd"
-      clipRule="evenodd"
-      strokeLinejoin="round"
-      strokeMiterlimit="1.414">
-      <path d="M448 48c0-8.83-7.17-16-16-16H16C7.17 32 0 39.17 0 48v32c0 8.83 7.17 16 16 16h416c8.83 0 16-7.17 16-16V48zM448 144c0-8.83-6.146-16-13.714-16H77.714C70.144 128 64 135.17 64 144v32c0 8.83 6.145 16 13.714 16h356.572c7.568 0 13.714-7.17 13.714-16v-32zM448 240c0-8.83-5.12-16-11.428-16H139.428C133.12 224 128 231.17 128 240v32c0 8.83 5.12 16 11.428 16h297.144c6.307 0 11.428-7.17 11.428-16v-32zM448 336.03c0-8.83-4.097-16-9.142-16H201.143c-5.046 0-9.143 7.17-9.143 16v32c0 8.83 4.097 16 9.143 16h237.715c5.045 0 9.142-7.17 9.142-16v-32z" />
-    </svg>
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/IconTreemap.js b/server/sonar-web/src/main/js/apps/component-measures/components/IconTreemap.js
deleted file mode 100644 (file)
index aef8aab..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-
-export default function IconTreemap() {
-  return (
-    <svg
-      className="measure-tab-icon"
-      viewBox="0 0 448 448"
-      fillRule="evenodd"
-      clipRule="evenodd"
-      strokeLinejoin="round"
-      strokeMiterlimit="1.414">
-      <path d="M0 0h224v448H0zM256 0h192v256H256zM256 288h192v160H256z" />
-    </svg>
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.js b/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.js
deleted file mode 100644 (file)
index 22483f1..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import moment from 'moment';
-import Tooltip from '../../../components/controls/Tooltip';
-import { getPeriodLabel, getPeriodDate } from '../../../helpers/periods';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-
-export default function LeakPeriodLegend({ component, period }) {
-  if (component.qualifier === 'APP') {
-    return (
-      <div className="measures-domains-leak-header">
-        {translate('issues.leak_period')}
-      </div>
-    );
-  }
-
-  const label = (
-    <div className="measures-domains-leak-header">
-      {translateWithParameters('overview.leak_period_x', getPeriodLabel(period))}
-    </div>
-  );
-
-  if (period.mode === 'days') {
-    return label;
-  }
-
-  const date = getPeriodDate(period);
-  const fromNow = moment(date).fromNow();
-  const tooltip = fromNow + ', ' + moment(date).format('LL');
-  return (
-    <Tooltip placement="bottom" overlay={tooltip}>
-      {label}
-    </Tooltip>
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/Measure.js b/server/sonar-web/src/main/js/apps/component-measures/components/Measure.js
deleted file mode 100644 (file)
index ba59123..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import PropTypes from 'prop-types';
-import Rating from '../../../components/ui/Rating';
-import Level from '../../../components/ui/Level';
-import { formatMeasure, isDiffMetric } from '../../../helpers/measures';
-import { TooltipsContainer } from '../../../components/mixins/tooltips-mixin';
-import { formatLeak, getRatingTooltip } from '../utils';
-
-export default class Measure extends React.PureComponent {
-  static propTypes = {
-    className: PropTypes.string,
-    measure: PropTypes.object,
-    metric: PropTypes.object,
-    decimals: PropTypes.number
-  };
-
-  renderRating(measure, metric) {
-    const value = isDiffMetric(metric.key) ? measure.leak : measure.value;
-    const tooltip = getRatingTooltip(metric.key, value);
-    const rating = <Rating value={value} />;
-
-    if (tooltip) {
-      return (
-        <TooltipsContainer>
-          <span>
-            <span title={tooltip} data-toggle="tooltip">
-              {rating}
-            </span>
-          </span>
-        </TooltipsContainer>
-      );
-    }
-
-    return rating;
-  }
-
-  render() {
-    const { measure, metric, decimals, className } = this.props;
-    const finalMetric = metric || measure.metric;
-
-    if (finalMetric.type === 'RATING') {
-      return this.renderRating(measure, finalMetric);
-    }
-
-    if (finalMetric.type === 'LEVEL') {
-      return <Level level={measure.value} />;
-    }
-
-    const formattedValue = isDiffMetric(finalMetric.key)
-      ? formatLeak(measure.leak, finalMetric, { decimals })
-      : formatMeasure(measure.value, finalMetric.type, { decimals });
-    return (
-      <span className={className}>
-        {formattedValue != null ? formattedValue : '–'}
-      </span>
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/Spinner.js b/server/sonar-web/src/main/js/apps/component-measures/components/Spinner.js
deleted file mode 100644 (file)
index 3f899ac..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-
-export default function Spinner() {
-  return <i className="spinner spinner-margin" />;
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/bubbleChart/BubbleChart.js b/server/sonar-web/src/main/js/apps/component-measures/components/bubbleChart/BubbleChart.js
deleted file mode 100644 (file)
index 4729500..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import Spinner from './../Spinner';
-import OriginalBubbleChart from '../../../../components/charts/BubbleChart';
-import bubbles from '../../config/bubbles';
-import { getComponentLeaves } from '../../../../api/components';
-import { formatMeasure } from '../../../../helpers/measures';
-import Workspace from '../../../../components/workspace/main';
-import { getComponentUrl } from '../../../../helpers/urls';
-import { getLocalizedMetricName, translateWithParameters } from '../../../../helpers/l10n';
-
-const HEIGHT = 500;
-const BUBBLES_LIMIT = 500;
-
-function getMeasure(component, metric) {
-  return Number(component.measures[metric]) || 0;
-}
-
-export default class BubbleChart extends React.PureComponent {
-  state = {
-    fetching: 0,
-    files: []
-  };
-
-  componentWillMount() {
-    this.updateMetrics(this.props);
-  }
-
-  componentDidMount() {
-    this.mounted = true;
-    this.fetchFiles();
-  }
-
-  componentWillUpdate(nextProps) {
-    this.updateMetrics(nextProps);
-  }
-
-  componentDidUpdate(nextProps) {
-    if (nextProps.domainName !== this.props.domainName) {
-      this.fetchFiles();
-    }
-  }
-
-  componentWillUnmount() {
-    this.mounted = false;
-  }
-
-  updateMetrics(props) {
-    const { metrics, domainName } = props;
-    const conf = bubbles[domainName];
-    this.xMetric = metrics.find(m => m.key === conf.x);
-    this.yMetric = metrics.find(m => m.key === conf.y);
-    this.sizeMetric = metrics.find(m => m.key === conf.size);
-  }
-
-  fetchFiles() {
-    const { component } = this.props;
-    const metrics = [this.xMetric.key, this.yMetric.key, this.sizeMetric.key];
-    const options = {
-      s: 'metric',
-      metricSort: this.sizeMetric.key,
-      asc: false,
-      ps: BUBBLES_LIMIT
-    };
-
-    if (this.mounted) {
-      this.setState({ fetching: this.state.fetching + 1 });
-    }
-
-    getComponentLeaves(component.key, metrics, options).then(r => {
-      const files = r.components.map(file => {
-        const measures = {};
-
-        file.measures.forEach(measure => {
-          measures[measure.metric] = measure.value;
-        });
-        return { ...file, measures };
-      });
-
-      if (this.mounted) {
-        this.setState({
-          files,
-          fetching: this.state.fetching - 1,
-          total: files.length
-        });
-      }
-    });
-  }
-
-  getTooltip(component) {
-    const x = formatMeasure(getMeasure(component, this.xMetric.key), this.xMetric.type);
-    const y = formatMeasure(getMeasure(component, this.yMetric.key), this.yMetric.type);
-    const size = formatMeasure(getMeasure(component, this.sizeMetric.key), this.sizeMetric.type);
-    const inner = [
-      component.name,
-      `${this.xMetric.name}: ${x}`,
-      `${this.yMetric.name}: ${y}`,
-      `${this.sizeMetric.name}: ${size}`
-    ].join('<br>');
-
-    return `<div class="text-left">${inner}</div>`;
-  }
-
-  handleBubbleClick(component) {
-    if (['FIL', 'UTS'].includes(component.qualifier)) {
-      Workspace.openComponent({ key: component.key });
-    } else {
-      window.location = getComponentUrl(component.refKey || component.key);
-    }
-  }
-
-  renderBubbleChart() {
-    const items = this.state.files.map(file => {
-      return {
-        x: getMeasure(file, this.xMetric.key),
-        y: getMeasure(file, this.yMetric.key),
-        size: getMeasure(file, this.sizeMetric.key),
-        link: file,
-        tooltip: this.getTooltip(file)
-      };
-    });
-
-    const formatXTick = tick => formatMeasure(tick, this.xMetric.type);
-    const formatYTick = tick => formatMeasure(tick, this.yMetric.type);
-
-    return (
-      <OriginalBubbleChart
-        items={items}
-        height={HEIGHT}
-        padding={[25, 60, 50, 60]}
-        formatXTick={formatXTick}
-        formatYTick={formatYTick}
-        onBubbleClick={this.handleBubbleClick.bind(this)}
-      />
-    );
-  }
-
-  render() {
-    const { fetching } = this.state;
-
-    if (fetching) {
-      return (
-        <div className="measure-details-bubble-chart">
-          <div className="note text-center" style={{ lineHeight: `${HEIGHT}px` }}>
-            <Spinner />
-          </div>
-        </div>
-      );
-    }
-
-    return (
-      <div className="measure-details-bubble-chart">
-        <div>
-          {this.renderBubbleChart()}
-        </div>
-
-        <div className="measure-details-bubble-chart-axis x">
-          {getLocalizedMetricName(this.xMetric)}
-        </div>
-        <div className="measure-details-bubble-chart-axis y">
-          {getLocalizedMetricName(this.yMetric)}
-        </div>
-        <div className="measure-details-bubble-chart-axis size">
-          {translateWithParameters(
-            'component_measures.legend.size_x',
-            getLocalizedMetricName(this.sizeMetric)
-          )}
-        </div>
-      </div>
-    );
-  }
-}
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
deleted file mode 100644 (file)
index bc9741b..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { connect } from 'react-redux';
-import MeasureBubbleChart from './BubbleChart';
-import { getMeasuresAppAllMetrics, getMeasuresAppComponent } from '../../../../store/rootReducer';
-
-const mapStateToProps = state => {
-  return {
-    component: getMeasuresAppComponent(state),
-    metrics: getMeasuresAppAllMetrics(state)
-  };
-};
-
-const mapDispatchToProps = () => {
-  return {};
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(MeasureBubbleChart);
diff --git a/server/sonar-web/src/main/js/apps/component-measures/config/bubbles.js b/server/sonar-web/src/main/js/apps/component-measures/config/bubbles.js
deleted file mode 100644 (file)
index 28407f5..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-const bubblesConfig = {
-  Reliability: { x: 'ncloc', y: 'reliability_remediation_effort', size: 'bugs' },
-  Security: { x: 'ncloc', y: 'security_remediation_effort', size: 'vulnerabilities' },
-  Maintainability: { x: 'ncloc', y: 'sqale_index', size: 'code_smells' },
-  Coverage: { x: 'complexity', y: 'coverage', size: 'uncovered_lines' },
-  Duplications: { x: 'ncloc', y: 'duplicated_lines', size: 'duplicated_blocks' }
-};
-
-export default bubblesConfig;
diff --git a/server/sonar-web/src/main/js/apps/component-measures/config/complementary.js b/server/sonar-web/src/main/js/apps/component-measures/config/complementary.js
deleted file mode 100644 (file)
index 46340a2..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-export default {
-  coverage: ['uncovered_lines', 'uncovered_conditions'],
-  line_coverage: ['uncovered_lines'],
-  branch_coverage: ['uncovered_conditions'],
-  uncovered_lines: ['line_coverage'],
-  uncovered_conditions: ['branch_coverage'],
-
-  new_coverage: ['new_uncovered_lines', 'new_uncovered_conditions'],
-  new_line_coverage: ['new_uncovered_lines'],
-  new_branch_coverage: ['new_uncovered_conditions'],
-  new_uncovered_lines: ['new_line_coverage'],
-  new_uncovered_conditions: ['new_branch_coverage'],
-
-  duplicated_lines_density: ['duplicated_lines'],
-  new_duplicated_lines_density: ['new_duplicated_lines'],
-  duplicated_lines: ['duplicated_lines_density'],
-  new_duplicated_lines: ['new_duplicated_lines_density']
-};
diff --git a/server/sonar-web/src/main/js/apps/component-measures/config/domains.js b/server/sonar-web/src/main/js/apps/component-measures/config/domains.js
deleted file mode 100644 (file)
index 6ac6a69..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-export const domains = {
-  Reliability: {
-    main: ['bugs', 'new_bugs', 'reliability_rating'],
-    order: [
-      'bugs',
-      'new_bugs',
-      'reliability_rating',
-      'reliability_remediation_effort',
-      'new_reliability_remediation_effort'
-    ]
-  },
-
-  Security: {
-    main: ['vulnerabilities', 'new_vulnerabilities', 'security_rating'],
-    order: [
-      'vulnerabilities',
-      'new_vulnerabilities',
-      'security_rating',
-      'security_remediation_effort',
-      'new_security_remediation_effort'
-    ]
-  },
-
-  Maintainability: {
-    main: ['code_smells', 'new_code_smells', 'sqale_rating'],
-    order: [
-      'code_smells',
-      'new_code_smells',
-      'sqale_rating',
-      'sqale_index',
-      'new_technical_debt',
-      'sqale_debt_ratio',
-      'new_sqale_debt_ratio',
-      'effort_to_reach_maintainability_rating_a'
-    ]
-  },
-
-  Coverage: {
-    main: ['coverage', 'new_coverage', 'tests'],
-    order: [
-      'coverage',
-      'new_coverage',
-      'line_coverage',
-      'new_line_coverage',
-      'branch_coverage',
-      'new_branch_coverage',
-      'uncovered_lines',
-      'new_uncovered_lines',
-      'uncovered_conditions',
-      'new_uncovered_conditions',
-      'new_lines_to_cover',
-
-      'lines_to_cover',
-
-      'tests',
-      'test_success',
-      'test_errors',
-      'test_failures',
-      'skipped_tests',
-      'test_success_density',
-      'test_execution_time'
-    ]
-  },
-
-  Duplications: {
-    main: ['duplicated_lines_density', 'new_duplicated_lines_density'],
-    order: [
-      'duplicated_lines_density',
-      'new_duplicated_lines_density',
-      'duplicated_blocks',
-      'new_duplicated_blocks',
-      'duplicated_lines',
-      'new_duplicated_lines',
-      'duplicated_files'
-    ]
-  },
-
-  Size: {
-    main: ['ncloc'],
-    order: [
-      'ncloc',
-      'lines',
-      'new_lines',
-      'statements',
-      'functions',
-      'classes',
-      'files',
-      'directories'
-    ]
-  },
-
-  Complexity: {
-    main: ['complexity'],
-    order: ['complexity', 'function_complexity', 'file_complexity', 'class_complexity']
-  },
-
-  Releasability: {
-    main: ['alert_status', 'releasability_rating'],
-    order: ['alert_status']
-  },
-
-  Issues: {
-    main: ['violations', 'new_violations'],
-    order: [
-      'violations',
-      'new_violations',
-      'blocker_violations',
-      'new_blocker_violations',
-      'critical_violations',
-      'new_critical_violations',
-      'major_violations',
-      'new_major_violations',
-      'minor_violations',
-      'new_minor_violations',
-      'info_violations',
-      'new_info_violations',
-      'open_issues',
-      'reopened_issues',
-      'confirmed_issues',
-      'false_positive_issues'
-    ]
-  }
-};
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
deleted file mode 100644 (file)
index ab1c938..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { Link, IndexLink } from 'react-router';
-import Spinner from './../components/Spinner';
-import MeasureDetailsHeader from './MeasureDetailsHeader';
-import MeasureDrilldown from './drilldown/MeasureDrilldown';
-import MetricNotFound from './MetricNotFound';
-import { getPeriod, getPeriodDate } from '../../../helpers/periods';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-
-export default class MeasureDetails extends React.PureComponent {
-  mounted: boolean;
-
-  state = {
-    loading: true
-  };
-
-  componentDidMount() {
-    this.mounted = true;
-    this.loadData();
-  }
-
-  componentDidUpdate(prevProps) {
-    if (prevProps.params.metricKey !== this.props.params.metricKey) {
-      this.loadData();
-    }
-  }
-
-  componentWillUnmount() {
-    this.mounted = false;
-  }
-
-  metricExists(): boolean {
-    const { metrics } = this.props;
-    const { metricKey } = this.props.params;
-    const metric = metrics.find(metric => metric.key === metricKey);
-    return !!metric;
-  }
-
-  loadData() {
-    if (this.metricExists()) {
-      this.setState({ loading: true });
-      const periodIndex = this.props.location.query.period || 1;
-      const onLoaded = () => this.mounted && this.setState({ loading: false });
-      this.props
-        .fetchMeasure(this.props.params.metricKey, Number(periodIndex))
-        .then(onLoaded, onLoaded);
-    }
-  }
-
-  render() {
-    if (!this.metricExists()) {
-      return <MetricNotFound />;
-    }
-
-    if (this.state.loading) {
-      return <Spinner />;
-    }
-
-    const { component, metric, secondaryMeasure, measure, periods, children } = this.props;
-
-    if (!measure) {
-      return <MetricNotFound />;
-    }
-
-    const { tab } = this.props.params;
-    const periodIndex = this.props.location.query.period || 1;
-    const period = getPeriod(periods, Number(periodIndex));
-    const periodDate = getPeriodDate(period);
-
-    return (
-      <section id="component-measures-details" className="page page-container page-limited">
-        <div className="note">
-          <IndexLink
-            to={{ pathname: '/component_measures', query: { id: component.key } }}
-            id="component-measures-back-to-all-measures"
-            className="text-muted">
-            {translate('component_measures.all_measures')}
-          </IndexLink>
-          {!!metric.domain &&
-            <span>
-              {' / '}
-              <Link
-                to={{
-                  pathname: `/component_measures/domain/${metric.domain}`,
-                  query: { id: component.key }
-                }}
-                className="text-muted">
-                {translateWithParameters('component_measures.domain_measures', metric.domain)}
-              </Link>
-            </span>}
-        </div>
-
-        <MeasureDetailsHeader
-          component={component}
-          leakPeriod={period}
-          measure={measure}
-          metric={metric}
-          secondaryMeasure={secondaryMeasure}
-        />
-
-        {measure &&
-          <MeasureDrilldown
-            component={component}
-            metric={metric}
-            tab={tab}
-            leakPeriod={period}
-            leakPeriodDate={periodDate}>
-            {children}
-          </MeasureDrilldown>}
-      </section>
-    );
-  }
-}
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
deleted file mode 100644 (file)
index 7ae3905..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { connect } from 'react-redux';
-import MeasureDetails from './MeasureDetails';
-import { fetchMeasure } from './actions';
-import {
-  getMeasuresAppAllMetrics,
-  getMeasuresAppDetailsMetric,
-  getMeasuresAppDetailsMeasure,
-  getMeasuresAppDetailsSecondaryMeasure,
-  getMeasuresAppDetailsPeriods,
-  getMeasuresAppComponent
-} from '../../../store/rootReducer';
-
-const mapStateToProps = state => {
-  return {
-    component: getMeasuresAppComponent(state),
-    metrics: getMeasuresAppAllMetrics(state),
-    metric: getMeasuresAppDetailsMetric(state),
-    measure: getMeasuresAppDetailsMeasure(state),
-    secondaryMeasure: getMeasuresAppDetailsSecondaryMeasure(state),
-    periods: getMeasuresAppDetailsPeriods(state)
-  };
-};
-
-const mapDispatchToProps = { fetchMeasure };
-
-export default connect(mapStateToProps, mapDispatchToProps)(MeasureDetails);
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetailsHeader.js b/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetailsHeader.js
deleted file mode 100644 (file)
index f2281c2..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { Link } from 'react-router';
-import Measure from './../components/Measure';
-import LanguageDistribution from '../../../components/charts/LanguageDistribution';
-import LeakPeriodLegend from '../components/LeakPeriodLegend';
-import IssueTypeIcon from '../../../components/ui/IssueTypeIcon';
-import HistoryIcon from '../../../components/icons-components/HistoryIcon';
-import Tooltip from '../../../components/controls/Tooltip';
-import { ComplexityDistribution } from '../../../components/shared/complexity-distribution';
-import { isDiffMetric } from '../../../helpers/measures';
-import { TooltipsContainer } from '../../../components/mixins/tooltips-mixin';
-import { getComponentMeasureHistory } from '../../../helpers/urls';
-import { getLocalizedMetricName, translate } from '../../../helpers/l10n';
-
-export default function MeasureDetailsHeader({
-  component,
-  measure,
-  metric,
-  secondaryMeasure,
-  leakPeriod
-}) {
-  const isDiff = isDiffMetric(metric.key);
-  return (
-    <header className="measure-details-header">
-      <h2 className="measure-details-metric">
-        <IssueTypeIcon query={metric.key} className="little-spacer-right" />
-        {getLocalizedMetricName(metric)}
-        {!isDiff &&
-          <Tooltip placement="right" overlay={translate('component_measures.show_metric_history')}>
-            <Link
-              className="js-show-history spacer-left button button-small button-compact"
-              to={getComponentMeasureHistory(component.key, metric.key)}>
-              <HistoryIcon />
-            </Link>
-          </Tooltip>}
-      </h2>
-
-      {isDiff &&
-        <div className="pull-right">
-          <LeakPeriodLegend component={component} period={leakPeriod} />
-        </div>}
-
-      <TooltipsContainer options={{ html: false }}>
-        <div className="measure-details-value">
-          {isDiff
-            ? <div className="measure-details-value-leak">
-                <Measure measure={measure} metric={metric} />
-              </div>
-            : <div className="measure-details-value-absolute">
-                <Measure measure={measure} metric={metric} />
-              </div>}
-
-          {secondaryMeasure &&
-            secondaryMeasure.metric === 'ncloc_language_distribution' &&
-            <div className="measure-details-secondary">
-              <LanguageDistribution distribution={secondaryMeasure.value} />
-            </div>}
-
-          {secondaryMeasure &&
-            secondaryMeasure.metric === 'function_complexity_distribution' &&
-            <div className="measure-details-secondary">
-              <ComplexityDistribution distribution={secondaryMeasure.value} of="function" />
-            </div>}
-
-          {secondaryMeasure &&
-            secondaryMeasure.metric === 'file_complexity_distribution' &&
-            <div className="measure-details-secondary">
-              <ComplexityDistribution distribution={secondaryMeasure.value} of="file" />
-            </div>}
-        </div>
-      </TooltipsContainer>
-    </header>
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/MetricNotFound.js b/server/sonar-web/src/main/js/apps/component-measures/details/MetricNotFound.js
deleted file mode 100644 (file)
index 57b5fee..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-// @flow
-import React from 'react';
-import { translate } from '../../../helpers/l10n';
-
-export default function MetricNotFound() {
-  return (
-    <div className="page page-limited">
-      <div className="alert alert-danger">
-        {translate('component_measures.not_found')}
-      </div>
-    </div>
-  );
-}
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
deleted file mode 100644 (file)
index 5557934..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { getMeasuresAndMeta } from '../../../api/measures';
-import { enhanceWithLeak } from '../utils';
-import { getMeasuresAppComponent, getMeasuresAppAllMetrics } from '../../../store/rootReducer';
-
-/*
- * Actions
- */
-
-export const REQUEST_MEASURE = 'measuresApp/details/REQUEST_MEASURE';
-export const RECEIVE_MEASURE = 'measuresApp/details/RECEIVE_MEASURE';
-
-/*
- * Action Creators
- */
-
-function requestMeasure(metric) {
-  return { type: REQUEST_MEASURE, metric };
-}
-
-function receiveMeasure(measure, secondaryMeasure, periods) {
-  return { type: RECEIVE_MEASURE, measure, secondaryMeasure, periods };
-}
-
-/*
- * Workflow
- */
-
-export function fetchMeasure(metricKey, periodIndex = 1) {
-  return (dispatch, getState) => {
-    const state = getState();
-    const component = getMeasuresAppComponent(state);
-    const metrics = getMeasuresAppAllMetrics(state);
-    const metricsToRequest = [metricKey];
-
-    if (metricKey === 'ncloc') {
-      metricsToRequest.push('ncloc_language_distribution');
-    }
-    if (metricKey === 'function_complexity') {
-      metricsToRequest.push('function_complexity_distribution');
-    }
-    if (metricKey === 'file_complexity') {
-      metricsToRequest.push('file_complexity_distribution');
-    }
-
-    const metric = metrics.find(m => m.key === metricKey);
-    dispatch(requestMeasure(metric));
-
-    return getMeasuresAndMeta(component.key, metricsToRequest, {
-      additionalFields: 'periods'
-    }).then(r => {
-      const measures = enhanceWithLeak(r.component.measures, periodIndex);
-      const measure = measures.find(m => m.metric === metricKey);
-      const secondaryMeasure = measures.find(m => m.metric !== metricKey);
-      dispatch(receiveMeasure(measure, secondaryMeasure, r.periods));
-    });
-  };
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/Breadcrumb.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/Breadcrumb.js
deleted file mode 100644 (file)
index aa038d9..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import QualifierIcon from '../../../../components/shared/QualifierIcon';
-import { formatLeak } from '../../utils';
-import { formatMeasure, isDiffMetric } from '../../../../helpers/measures';
-
-const Breadcrumb = ({ component, metric, onBrowse }) => {
-  const handleClick = e => {
-    e.preventDefault();
-    e.target.blur();
-    onBrowse(component);
-  };
-
-  let inner;
-  if (onBrowse) {
-    inner = (
-      <a id={'component-measures-breadcrumb-' + component.key} href="#" onClick={handleClick}>
-        {component.name}
-      </a>
-    );
-  } else {
-    inner = (
-      <span>
-        {component.name}
-      </span>
-    );
-  }
-
-  const value = isDiffMetric(metric.key)
-    ? formatLeak(component.leak, metric)
-    : formatMeasure(component.value, metric.type);
-
-  return (
-    <span>
-      <QualifierIcon qualifier={component.qualifier} />
-      &nbsp;
-      {inner}
-      {value != null &&
-        <span>
-          {' (' + value + ')'}
-        </span>}
-    </span>
-  );
-};
-
-export default Breadcrumb;
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/Breadcrumbs.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/Breadcrumbs.js
deleted file mode 100644 (file)
index 227fad2..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import Breadcrumb from './Breadcrumb';
-
-const Breadcrumbs = ({ breadcrumbs, metric, onBrowse }) =>
-  <ul className="component-measures-breadcrumbs">
-    {breadcrumbs.map((component, index) =>
-      <li key={component.key}>
-        <Breadcrumb
-          component={component}
-          metric={metric}
-          onBrowse={index + 1 < breadcrumbs.length ? onBrowse : null}
-        />
-      </li>
-    )}
-  </ul>;
-
-export default Breadcrumbs;
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ComponentCell.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ComponentCell.js
deleted file mode 100644 (file)
index 6d9ae77..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import classNames from 'classnames';
-import QualifierIcon from '../../../../components/shared/QualifierIcon';
-import { splitPath } from '../../../../helpers/path';
-import { getComponentUrl } from '../../../../helpers/urls';
-
-const ComponentCell = ({ component, isSelected, onClick }) => {
-  const linkClassName = classNames('link-no-underline', {
-    selected: isSelected
-  });
-
-  const handleClick = e => {
-    const isLeftClickEvent = e.button === 0;
-    const isModifiedEvent = !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
-
-    if (isLeftClickEvent && !isModifiedEvent) {
-      e.preventDefault();
-      onClick();
-    }
-  };
-
-  let head = '';
-  let tail = component.name;
-
-  if (['DIR', 'FIL', 'UTS'].includes(component.qualifier)) {
-    const parts = splitPath(component.path);
-    head = parts.head;
-    tail = parts.tail;
-  }
-
-  const inner = (
-    <span title={component.refKey || component.key}>
-      <QualifierIcon qualifier={component.qualifier} />
-      &nbsp;
-      {head.length > 0 &&
-        <span className="note">
-          {head}/
-        </span>}
-      <span>{tail}</span>
-    </span>
-  );
-
-  return (
-    <td style={{ maxWidth: 0 }}>
-      <div
-        style={{
-          maxWidth: '100%',
-          whiteSpace: 'nowrap',
-          overflow: 'hidden',
-          textOverflow: 'ellipsis'
-        }}>
-        {component.refId == null || component.qualifier === 'DEV_PRJ'
-          ? <a
-              id={'component-measures-component-link-' + component.key}
-              className={linkClassName}
-              href={getComponentUrl(component.key)}
-              onClick={handleClick}>
-              {inner}
-            </a>
-          : <a
-              id={'component-measures-component-link-' + component.key}
-              className={linkClassName}
-              href={getComponentUrl(component.refKey || component.key)}>
-              <span className="big-spacer-right">
-                <i className="icon-detach" />
-              </span>
-
-              {inner}
-            </a>}
-      </div>
-    </td>
-  );
-};
-
-export default ComponentCell;
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ComponentsList.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ComponentsList.js
deleted file mode 100644 (file)
index 0faf5f6..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import ComponentsListRow from './ComponentsListRow';
-import EmptyComponentsList from './EmptyComponentsList';
-import complementary from '../../config/complementary';
-import { getLocalizedMetricName } from '../../../../helpers/l10n';
-
-const ComponentsList = ({ components, metrics, selected, metric, onClick }) => {
-  if (!components.length) {
-    return <EmptyComponentsList />;
-  }
-
-  const otherMetrics = (complementary[metric.key] || []).map(metric => {
-    return metrics.find(m => m.key === metric);
-  });
-
-  return (
-    <table className="data zebra zebra-hover">
-      {otherMetrics.length > 0 &&
-        <thead>
-          <tr>
-            <th>&nbsp;</th>
-            <th className="text-right">
-              <span className="small">
-                {getLocalizedMetricName(metric)}
-              </span>
-            </th>
-            {otherMetrics.map(metric =>
-              <th key={metric.key} className="text-right">
-                <span className="small">
-                  {getLocalizedMetricName(metric)}
-                </span>
-              </th>
-            )}
-          </tr>
-        </thead>}
-
-      <tbody>
-        {components.map(component =>
-          <ComponentsListRow
-            key={component.id}
-            component={component}
-            otherMetrics={otherMetrics}
-            isSelected={component === selected}
-            metric={metric}
-            onClick={onClick}
-          />
-        )}
-      </tbody>
-    </table>
-  );
-};
-
-export default ComponentsList;
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ComponentsListRow.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ComponentsListRow.js
deleted file mode 100644 (file)
index 8e01925..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import ComponentCell from './ComponentCell';
-import MeasureCell from './MeasureCell';
-
-const replaceMeasure = (component, measure) => {
-  return {
-    ...component,
-    value: measure.value,
-    leak: measure.leak
-  };
-};
-
-const ComponentsListRow = ({ component, otherMetrics, isSelected, metric, onClick }) => {
-  const handleClick = () => {
-    onClick(component);
-  };
-
-  const otherMeasures = otherMetrics.map(metric => {
-    const measure = component.measures.find(measure => measure.metric === metric.key);
-    return { ...measure, metric };
-  });
-
-  return (
-    <tr>
-      <ComponentCell
-        component={component}
-        isSelected={isSelected}
-        onClick={handleClick.bind(this, component)}
-      />
-
-      <MeasureCell component={component} metric={metric} />
-
-      {otherMeasures.map(measure =>
-        <MeasureCell
-          key={measure.metric.key}
-          component={replaceMeasure(component, measure)}
-          metric={measure.metric}
-        />
-      )}
-    </tr>
-  );
-};
-
-export default ComponentsListRow;
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/EmptyComponentsList.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/EmptyComponentsList.js
deleted file mode 100644 (file)
index be032c0..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { translate } from '../../../../helpers/l10n';
-
-const EmptyComponentsList = () => {
-  return (
-    <div className="note">
-      {translate('no_results')}
-    </div>
-  );
-};
-
-export default EmptyComponentsList;
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListHeader.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListHeader.js
deleted file mode 100644 (file)
index b929bac..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import Breadcrumbs from './Breadcrumbs';
-import { translateWithParameters } from '../../../../helpers/l10n';
-
-const ListHeader = props => {
-  const { metric, breadcrumbs, onBrowse } = props;
-  const { selectedIndex, componentsCount, onSelectPrevious, onSelectNext } = props;
-  const hasPrevious = selectedIndex > 0;
-  const hasNext = selectedIndex < componentsCount - 1;
-  const blur = fn => {
-    return e => {
-      e.target.blur();
-      fn();
-    };
-  };
-
-  return (
-    <header className="measure-details-viewer-header">
-      {breadcrumbs != null &&
-        breadcrumbs.length > 1 &&
-        <div className="measure-details-header-container">
-          <Breadcrumbs breadcrumbs={breadcrumbs} metric={metric} onBrowse={onBrowse} />
-        </div>}
-
-      {selectedIndex != null &&
-        selectedIndex !== -1 &&
-        <div className="pull-right">
-          <span className="note spacer-right">
-            {translateWithParameters(
-              'component_measures.x_of_y',
-              selectedIndex + 1,
-              componentsCount
-            )}
-          </span>
-
-          <div className="button-group">
-            {hasPrevious && <button onClick={blur(onSelectPrevious)}>&lt;</button>}
-            {hasNext && <button onClick={blur(onSelectNext)}>&gt;</button>}
-          </div>
-        </div>}
-    </header>
-  );
-};
-
-export default ListHeader;
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListView.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListView.js
deleted file mode 100644 (file)
index 88d28d8..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import PropTypes from 'prop-types';
-import classNames from 'classnames';
-import moment from 'moment';
-import ComponentsList from './ComponentsList';
-import ListHeader from './ListHeader';
-import Spinner from '../../components/Spinner';
-import SourceViewer from '../../../../components/SourceViewer/SourceViewer';
-import ListFooter from '../../../../components/controls/ListFooter';
-
-export default class ListView extends React.PureComponent {
-  static contextTypes = {
-    router: PropTypes.object.isRequired
-  };
-
-  componentDidMount() {
-    const { component, metric } = this.props;
-    if (component.qualifier === 'DEV') {
-      const { router } = this.context;
-      router.replace({ pathname: `metric/${metric.key}/tree`, query: { id: component.key } });
-    }
-    this.handleChangeBaseComponent(component);
-  }
-
-  componentDidUpdate(nextProps) {
-    if (nextProps.metric !== this.props.metric) {
-      this.handleChangeBaseComponent(this.props.component);
-    }
-
-    if (this.props.selected) {
-      this.scrollToViewer();
-    } else if (this.scrollTop) {
-      this.scrollToStoredPosition();
-    }
-  }
-
-  scrollToViewer() {
-    const { container } = this.refs;
-    const top = container.getBoundingClientRect().top + window.scrollY - 95 - 10;
-
-    // scroll only to top
-    if (window.scrollY > top) {
-      window.scrollTo(0, top);
-    }
-  }
-
-  scrollToStoredPosition() {
-    window.scrollTo(0, this.scrollTop);
-    this.scrollTop = null;
-  }
-
-  storeScrollPosition() {
-    this.scrollTop = window.scrollY;
-  }
-
-  handleChangeBaseComponent(baseComponent) {
-    const { metric, onFetchList } = this.props;
-    const periodIndex = this.props.location.query.period || 1;
-    onFetchList(baseComponent, metric, Number(periodIndex));
-  }
-
-  handleFetchMore() {
-    const periodIndex = this.props.location.query.period || 1;
-    this.props.onFetchMore(Number(periodIndex));
-  }
-
-  changeSelected(selected) {
-    this.props.onSelect(selected);
-  }
-
-  handleClick(selected) {
-    this.storeScrollPosition();
-    this.props.onSelect(selected);
-  }
-
-  handleBreadcrumbClick() {
-    this.props.onSelect(undefined);
-  }
-
-  render() {
-    const {
-      component,
-      components,
-      metrics,
-      metric,
-      leakPeriod,
-      selected,
-      total,
-      fetching
-    } = this.props;
-    const { onSelectNext, onSelectPrevious } = this.props;
-
-    const breadcrumbs = [component];
-    if (selected) {
-      breadcrumbs.push(selected);
-    }
-    const selectedIndex = components.indexOf(selected);
-    const sourceViewerPeriod = metric.key.indexOf('new_') === 0 && !!leakPeriod ? leakPeriod : null;
-    const sourceViewerPeriodDate =
-      sourceViewerPeriod != null ? moment(sourceViewerPeriod.date).toDate() : null;
-
-    const filterLine =
-      sourceViewerPeriodDate != null
-        ? line => {
-            if (line.scmDate) {
-              const scmDate = moment(line.scmDate).toDate();
-              return scmDate >= sourceViewerPeriodDate;
-            } else {
-              return false;
-            }
-          }
-        : undefined;
-
-    return (
-      <div ref="container" className="measure-details-plain-list">
-        <ListHeader
-          metric={metric}
-          breadcrumbs={breadcrumbs}
-          componentsCount={components.length}
-          selectedIndex={selectedIndex}
-          onSelectPrevious={onSelectPrevious}
-          onSelectNext={onSelectNext}
-          onBrowse={this.handleBreadcrumbClick.bind(this)}
-        />
-
-        {!selected &&
-          <div className={classNames({ 'new-loading': fetching })}>
-            {!fetching || components.length !== 0
-              ? <div>
-                  <ComponentsList
-                    components={components}
-                    metrics={metrics}
-                    selected={selected}
-                    metric={metric}
-                    onClick={this.handleClick.bind(this)}
-                  />
-                  <ListFooter
-                    count={components.length}
-                    total={total}
-                    loadMore={this.handleFetchMore.bind(this)}
-                  />
-                </div>
-              : <Spinner />}
-          </div>}
-
-        {!!selected &&
-          <div className="measure-details-viewer">
-            <SourceViewer component={selected.key} filterLine={filterLine} />
-          </div>}
-      </div>
-    );
-  }
-}
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
deleted file mode 100644 (file)
index bf6b3fc..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { connect } from 'react-redux';
-import ListView from './ListView';
-import {
-  fetchList,
-  fetchMore,
-  selectComponent,
-  selectNext,
-  selectPrevious
-} from '../../store/listViewActions';
-import {
-  getMeasuresAppListComponents,
-  getMeasuresAppListSelected,
-  getMeasuresAppListTotal,
-  getMeasuresAppListPageIndex,
-  getMeasuresAppAllMetrics,
-  getMeasuresAppDetailsMetric,
-  isMeasuresAppFetching,
-  getMeasuresAppComponent
-} from '../../../../store/rootReducer';
-
-const mapStateToProps = state => {
-  return {
-    components: getMeasuresAppListComponents(state),
-    selected: getMeasuresAppListSelected(state),
-    total: getMeasuresAppListTotal(state),
-    pageIndex: getMeasuresAppListPageIndex(state),
-    component: getMeasuresAppComponent(state),
-    metrics: getMeasuresAppAllMetrics(state),
-    metric: getMeasuresAppDetailsMetric(state),
-    fetching: isMeasuresAppFetching(state)
-  };
-};
-
-const mapDispatchToProps = dispatch => {
-  return {
-    onFetchList: (baseComponent, metric, periodIndex) =>
-      dispatch(fetchList(baseComponent, metric, periodIndex)),
-    onFetchMore: periodIndex => dispatch(fetchMore(periodIndex)),
-    onSelect: component => dispatch(selectComponent(component)),
-    onSelectNext: component => dispatch(selectNext(component)),
-    onSelectPrevious: component => dispatch(selectPrevious(component))
-  };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(ListView);
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/MeasureCell.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/MeasureCell.js
deleted file mode 100644 (file)
index ee236ad..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import Measure from '../../components/Measure';
-
-const MeasureCell = ({ component, metric }) => {
-  return (
-    <td className="thin nowrap text-right">
-      <span id={'component-measures-component-measure-' + component.key + '-' + metric.key}>
-        <Measure measure={{ value: component.value, leak: component.leak }} metric={metric} />
-      </span>
-    </td>
-  );
-};
-
-export default MeasureCell;
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
deleted file mode 100644 (file)
index f54768d..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { Link } from 'react-router';
-import IconList from './../../components/IconList';
-import IconTree from './../../components/IconTree';
-import IconBubbles from './../../components/IconBubbles';
-import IconTreemap from './../../components/IconTreemap';
-import { hasBubbleChart, hasTreemap } from '../../utils';
-import { translate } from '../../../../helpers/l10n';
-
-export default function MeasureDrilldown(props) {
-  const { children, component, metric, ...other } = props;
-
-  const child = React.cloneElement(children, { ...other });
-
-  return (
-    <div className="measure-details-drilldown">
-      <ul className="measure-details-drilldown-mode">
-        {component.qualifier !== 'DEV' &&
-          <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: `/component_measures/metric/${metric.key}/tree`,
-              query: { id: component.key }
-            }}>
-            <IconTree />
-            {translate('component_measures.tab.tree')}
-          </Link>
-        </li>
-
-        {hasBubbleChart(metric.key) &&
-          <li>
-            <Link
-              activeClassName="active"
-              to={{
-                pathname: `/component_measures/metric/${metric.key}/bubbles`,
-                query: { id: component.key }
-              }}>
-              <IconBubbles />
-              {translate('component_measures.tab.bubbles')}
-            </Link>
-          </li>}
-
-        {hasTreemap(metric) &&
-          <li>
-            <Link
-              activeClassName="active"
-              to={{
-                pathname: `/component_measures/metric/${metric.key}/treemap`,
-                query: { id: component.key }
-              }}>
-              <IconTreemap />
-              {translate('component_measures.tab.treemap')}
-            </Link>
-          </li>}
-      </ul>
-
-      {child}
-    </div>
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/TreeView.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/TreeView.js
deleted file mode 100644 (file)
index 0bbfe14..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import moment from 'moment';
-import ComponentsList from './ComponentsList';
-import ListHeader from './ListHeader';
-import Spinner from '../../components/Spinner';
-import SourceViewer from '../../../../components/SourceViewer/SourceViewer';
-import ListFooter from '../../../../components/controls/ListFooter';
-
-export default class TreeView extends React.PureComponent {
-  componentDidMount() {
-    this.handleChangeBaseComponent(this.props.component);
-  }
-
-  componentDidUpdate(nextProps) {
-    if (nextProps.metric !== this.props.metric) {
-      this.handleChangeBaseComponent(this.props.component);
-    }
-
-    if (this.props.selected) {
-      this.scrollToViewer();
-    } else if (this.scrollTop) {
-      this.scrollToStoredPosition();
-    }
-  }
-
-  scrollToViewer() {
-    const { container } = this.refs;
-    const top = container.getBoundingClientRect().top + window.scrollY - 95 - 10;
-
-    // scroll only to top
-    if (window.scrollY > top) {
-      window.scrollTo(0, top);
-    }
-  }
-
-  scrollToStoredPosition() {
-    window.scrollTo(0, this.scrollTop);
-    this.scrollTop = null;
-  }
-
-  storeScrollPosition() {
-    this.scrollTop = window.scrollY;
-  }
-
-  handleChangeBaseComponent(baseComponent) {
-    const { metric, onStart } = this.props;
-    const periodIndex = this.props.location.query.period || 1;
-    onStart(baseComponent, metric, Number(periodIndex));
-  }
-
-  handleFetchMore() {
-    this.props.onFetchMore();
-  }
-
-  changeSelected(selected) {
-    this.props.onSelect(selected);
-  }
-
-  canDrilldown(component) {
-    return !['FIL', 'UTS'].includes(component.qualifier);
-  }
-
-  handleClick(selected) {
-    if (this.canDrilldown(selected)) {
-      this.props.onDrilldown(selected);
-    } else {
-      this.storeScrollPosition();
-      this.props.onSelect(selected);
-    }
-  }
-
-  handleBreadcrumbClick(component) {
-    this.props.onUseBreadcrumbs(component, this.props.metric);
-  }
-
-  render() {
-    const {
-      components,
-      metrics,
-      breadcrumbs,
-      metric,
-      leakPeriod,
-      selected,
-      total,
-      fetching
-    } = this.props;
-    const { onSelectNext, onSelectPrevious } = this.props;
-
-    const selectedIndex = components.indexOf(selected);
-    const sourceViewerPeriod = metric.key.indexOf('new_') === 0 && !!leakPeriod ? leakPeriod : null;
-    const sourceViewerPeriodDate =
-      sourceViewerPeriod != null ? moment(sourceViewerPeriod.date).toDate() : null;
-
-    const filterLine =
-      sourceViewerPeriodDate != null
-        ? line => {
-            if (line.scmDate) {
-              const scmDate = moment(line.scmDate).toDate();
-              return scmDate >= sourceViewerPeriodDate;
-            } else {
-              return false;
-            }
-          }
-        : undefined;
-
-    return (
-      <div ref="container" className="measure-details-plain-list">
-        <ListHeader
-          metric={metric}
-          breadcrumbs={breadcrumbs}
-          componentsCount={components.length}
-          selectedIndex={selectedIndex}
-          onSelectPrevious={onSelectPrevious}
-          onSelectNext={onSelectNext}
-          onBrowse={this.handleBreadcrumbClick.bind(this)}
-        />
-
-        {!selected &&
-          <div>
-            {!fetching || components.length !== 0
-              ? <div>
-                  <ComponentsList
-                    components={components}
-                    metrics={metrics}
-                    selected={selected}
-                    metric={metric}
-                    onClick={this.handleClick.bind(this)}
-                  />
-                  <ListFooter
-                    count={components.length}
-                    total={total}
-                    loadMore={this.handleFetchMore.bind(this)}
-                  />
-                </div>
-              : <Spinner />}
-          </div>}
-
-        {!!selected &&
-          <div className="measure-details-viewer">
-            <SourceViewer component={selected.key} filterLine={filterLine} />
-          </div>}
-      </div>
-    );
-  }
-}
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
deleted file mode 100644 (file)
index a7ae418..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { connect } from 'react-redux';
-import TreeView from './TreeView';
-import {
-  start,
-  drilldown,
-  useBreadcrumbs,
-  fetchMore,
-  selectComponent,
-  selectNext,
-  selectPrevious
-} from '../../store/treeViewActions';
-import {
-  getMeasuresAppTreeComponents,
-  getMeasuresAppTreeBreadcrumbs,
-  getMeasuresAppTreeSelected,
-  getMeasuresAppTreeTotal,
-  getMeasuresAppTreePageIndex,
-  getMeasuresAppAllMetrics,
-  getMeasuresAppDetailsMetric,
-  isMeasuresAppFetching,
-  getMeasuresAppComponent
-} from '../../../../store/rootReducer';
-
-const mapStateToProps = state => {
-  return {
-    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)
-  };
-};
-
-const mapDispatchToProps = dispatch => {
-  return {
-    onStart: (rootComponent, metric, periodIndex) =>
-      dispatch(start(rootComponent, metric, periodIndex)),
-    onDrilldown: component => dispatch(drilldown(component)),
-    onUseBreadcrumbs: component => dispatch(useBreadcrumbs(component)),
-    onFetchMore: () => dispatch(fetchMore()),
-    onSelect: component => dispatch(selectComponent(component)),
-    onSelectNext: component => dispatch(selectNext(component)),
-    onSelectPrevious: component => dispatch(selectPrevious(component))
-  };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(TreeView);
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/reducer.js b/server/sonar-web/src/main/js/apps/component-measures/details/reducer.js
deleted file mode 100644 (file)
index ea68685..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { DISPLAY_HOME } from '../app/actions';
-import { REQUEST_MEASURE, RECEIVE_MEASURE } from './actions';
-
-const initialState = {
-  metric: undefined,
-  secondaryMeasure: undefined,
-  measure: undefined,
-  periods: undefined
-};
-
-export default function appReducer(state = initialState, action = {}) {
-  switch (action.type) {
-    case DISPLAY_HOME:
-      return initialState;
-    case REQUEST_MEASURE:
-      return { ...state, metric: action.metric };
-    case RECEIVE_MEASURE:
-      return {
-        ...state,
-        measure: action.measure,
-        secondaryMeasure: action.secondaryMeasure,
-        periods: action.periods
-      };
-    default:
-      return state;
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemap.js b/server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemap.js
deleted file mode 100644 (file)
index 2516b8d..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { scaleLinear, scaleOrdinal } from 'd3-scale';
-import Spinner from './../../components/Spinner';
-import { getLeakValue } from '../../utils';
-import { Treemap } from '../../../../components/charts/treemap';
-import { getChildren } from '../../../../api/components';
-import { formatMeasure } from '../../../../helpers/measures';
-import {
-  translate,
-  translateWithParameters,
-  getLocalizedMetricName
-} from '../../../../helpers/l10n';
-import { getComponentUrl } from '../../../../helpers/urls';
-import Workspace from '../../../../components/workspace/main';
-
-const HEIGHT = 500;
-
-export default class MeasureTreemap extends React.PureComponent {
-  state = {
-    fetching: true,
-    components: [],
-    breadcrumbs: []
-  };
-
-  componentDidMount() {
-    const { component } = this.props;
-
-    this.mounted = true;
-    this.fetchComponents(component.key);
-  }
-
-  componentDidUpdate(nextProps) {
-    if (nextProps.metric !== this.props.metric) {
-      this.fetchComponents(this.props.component.key);
-    }
-  }
-
-  componentWillUnmount() {
-    this.mounted = false;
-  }
-
-  fetchComponents(componentKey) {
-    const { metric } = this.props;
-    const metrics = ['ncloc', metric.key];
-    const options = {
-      s: 'metric',
-      metricSort: 'ncloc',
-      asc: false
-    };
-
-    return getChildren(componentKey, metrics, options).then(r => {
-      const components = r.components.map(component => {
-        const measures = {};
-        const key = component.refKey || component.key;
-
-        component.measures.forEach(measure => {
-          const shouldUseLeak = measure.metric.indexOf('new_') === 0;
-          measures[measure.metric] = shouldUseLeak ? getLeakValue(measure) : measure.value;
-        });
-        return { ...component, measures, key };
-      });
-
-      this.setState({
-        components,
-        fetching: false
-      });
-    });
-  }
-
-  getTooltip(component) {
-    const { metric } = this.props;
-
-    let inner = [
-      component.name,
-      `${translate('metric.ncloc.name')}: ${formatMeasure(component.measures['ncloc'], 'INT')}`
-    ];
-
-    const colorMeasure = component.measures[metric.key];
-    const formatted = colorMeasure != null ? formatMeasure(colorMeasure, metric.type) : '—';
-    inner.push(`${getLocalizedMetricName(metric)}: ${formatted}`);
-    inner = inner.join('<br>');
-    return `<div class="text-left">${inner}</div>`;
-  }
-  getPercentColorScale(metric) {
-    const color = scaleLinear().domain([0, 25, 50, 75, 100]);
-    color.range(
-      metric.direction === 1
-        ? ['#d4333f', '#ed7d20', '#eabe06', '#b0d513', '#00aa00']
-        : ['#00aa00', '#b0d513', '#eabe06', '#ed7d20', '#d4333f']
-    );
-    return color;
-  }
-  getRatingColorScale() {
-    return scaleLinear()
-      .domain([1, 2, 3, 4, 5])
-      .range(['#00aa00', '#b0d513', '#eabe06', '#ed7d20', '#d4333f']);
-  }
-  getLevelColorScale() {
-    return scaleOrdinal()
-      .domain(['ERROR', 'WARN', 'OK', 'NONE'])
-      .range(['#d4333f', '#ed7d20', '#00aa00', '#b4b4b4']);
-  }
-  getScale() {
-    const { metric } = this.props;
-    if (metric.type === 'LEVEL') {
-      return this.getLevelColorScale();
-    }
-    if (metric.type === 'RATING') {
-      return this.getRatingColorScale();
-    }
-    return this.getPercentColorScale(metric);
-  }
-  handleRectangleClick(node) {
-    const isFile = node.qualifier === 'FIL' || node.qualifier === 'UTS';
-    if (isFile) {
-      Workspace.openComponent({ key: node.key });
-      return;
-    }
-    this.fetchComponents(node.key).then(() => {
-      let nextBreadcrumbs = [...this.state.breadcrumbs];
-      const index = this.state.breadcrumbs.findIndex(b => b.key === node.key);
-      if (index !== -1) {
-        nextBreadcrumbs = nextBreadcrumbs.slice(0, index);
-      }
-      nextBreadcrumbs = [
-        ...nextBreadcrumbs,
-        {
-          key: node.key,
-          name: node.name,
-          qualifier: node.qualifier
-        }
-      ];
-      this.setState({ breadcrumbs: nextBreadcrumbs });
-    });
-  }
-  handleReset() {
-    const { component } = this.props;
-    this.fetchComponents(component.key).then(() => {
-      this.setState({ breadcrumbs: [] });
-    });
-  }
-  renderTreemap() {
-    const { metric } = this.props;
-    const colorScale = this.getScale();
-    const items = this.state.components
-      .filter(component => component.measures['ncloc'])
-      .map(component => {
-        const colorMeasure = component.measures[metric.key];
-        return {
-          id: component.id,
-          key: component.key,
-          name: component.name,
-          qualifier: component.qualifier,
-          size: component.measures['ncloc'],
-          color: colorMeasure != null ? colorScale(colorMeasure) : '#777',
-          tooltip: this.getTooltip(component),
-          label: component.name,
-          link: getComponentUrl(component.key)
-        };
-      });
-    return (
-      <Treemap
-        items={items}
-        breadcrumbs={this.state.breadcrumbs}
-        height={HEIGHT}
-        canBeClicked={() => true}
-        onRectangleClick={this.handleRectangleClick.bind(this)}
-        onReset={this.handleReset.bind(this)}
-      />
-    );
-  }
-  render() {
-    const { metric } = this.props;
-    const { fetching } = this.state;
-    if (fetching) {
-      return (
-        <div className="measure-details-treemap">
-          <div className="note text-center" style={{ lineHeight: `${HEIGHT}px` }}>
-            <Spinner />
-          </div>
-        </div>
-      );
-    }
-    return (
-      <div className="measure-details-treemap">
-        <ul className="list-inline note measure-details-treemap-legend">
-          <li>
-            {translateWithParameters(
-              'component_measures.legend.color_x',
-              getLocalizedMetricName(metric)
-            )}
-          </li>
-          <li>
-            {translateWithParameters(
-              'component_measures.legend.size_x',
-              translate('metric.ncloc.name')
-            )}
-          </li>
-        </ul>
-        {this.renderTreemap()}
-      </div>
-    );
-  }
-}
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
deleted file mode 100644 (file)
index 5a3e26d..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { connect } from 'react-redux';
-import MeasureTreemap from './MeasureTreemap';
-import {
-  getMeasuresAppDetailsMetric,
-  getMeasuresAppComponent
-} from '../../../../store/rootReducer';
-
-const mapStateToProps = state => {
-  return {
-    component: getMeasuresAppComponent(state),
-    metric: getMeasuresAppDetailsMetric(state)
-  };
-};
-
-const mapDispatchToProps = () => {
-  return {};
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(MeasureTreemap);
diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/AllMeasures.js b/server/sonar-web/src/main/js/apps/component-measures/home/AllMeasures.js
deleted file mode 100644 (file)
index ab69f4b..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import AllMeasuresDomain from './AllMeasuresDomain';
-import { getLeakPeriodLabel } from '../../../helpers/periods';
-
-export default function AllMeasures(props) {
-  const { component, domains, periods } = props;
-  const leakPeriodLabel = getLeakPeriodLabel(periods);
-
-  return (
-    <ul className="measures-domains">
-      {domains.map(domain =>
-        <AllMeasuresDomain
-          key={domain.name}
-          domain={domain}
-          component={component}
-          leakPeriodLabel={leakPeriodLabel}
-        />
-      )}
-    </ul>
-  );
-}
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
deleted file mode 100644 (file)
index 5ec9cc7..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { connect } from 'react-redux';
-import AllMeasures from './AllMeasures';
-import {
-  getMeasuresAppHomeDomains,
-  getMeasuresAppHomePeriods,
-  getMeasuresAppComponent
-} from '../../../store/rootReducer';
-
-const mapStateToProps = state => {
-  return {
-    component: getMeasuresAppComponent(state),
-    domains: getMeasuresAppHomeDomains(state),
-    periods: getMeasuresAppHomePeriods(state)
-  };
-};
-
-export default connect(mapStateToProps)(AllMeasures);
diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/AllMeasuresDomain.js b/server/sonar-web/src/main/js/apps/component-measures/home/AllMeasuresDomain.js
deleted file mode 100644 (file)
index 1111a36..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import PropTypes from 'prop-types';
-import HomeMeasuresList from './HomeMeasuresList';
-import { getLocalizedMetricDomain } from '../../../helpers/l10n';
-
-export default function AllMeasuresDomain(props) {
-  const { domain, component, displayHeader } = props;
-
-  return (
-    <li>
-      {displayHeader &&
-        <header className="page-header">
-          <h3 className="page-title">
-            {getLocalizedMetricDomain(domain.name)}
-          </h3>
-        </header>}
-
-      <HomeMeasuresList domain={domain} component={component} />
-    </li>
-  );
-}
-
-AllMeasuresDomain.defaultProps = {
-  displayHeader: true
-};
-
-AllMeasuresDomain.propTypes = {
-  displayHeader: PropTypes.bool
-};
diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/DomainMeasures.js b/server/sonar-web/src/main/js/apps/component-measures/home/DomainMeasures.js
deleted file mode 100644 (file)
index 22343bc..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import HomeMeasuresList from './HomeMeasuresList';
-import MeasureBubbleChartContainer from '../components/bubbleChart/MeasureBubbleChartContainer';
-import { hasBubbleChart } from '../utils';
-
-export default function DomainMeasures(props) {
-  const { component, domains } = props;
-  const { domainName } = props.params;
-  const domain = domains.find(d => d.name === domainName);
-
-  return (
-    <section id="component-measures-domain">
-      <HomeMeasuresList domain={domain} component={component} />
-
-      {hasBubbleChart(domainName) && <MeasureBubbleChartContainer domainName={domainName} />}
-    </section>
-  );
-}
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
deleted file mode 100644 (file)
index c442bfc..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { connect } from 'react-redux';
-import DomainMeasures from './DomainMeasures';
-import {
-  getMeasuresAppHomeDomains,
-  getMeasuresAppHomePeriods,
-  getMeasuresAppComponent
-} from '../../../store/rootReducer';
-
-const mapStateToProps = state => {
-  return {
-    component: getMeasuresAppComponent(state),
-    domains: getMeasuresAppHomeDomains(state),
-    periods: getMeasuresAppHomePeriods(state)
-  };
-};
-
-export default connect(mapStateToProps)(DomainMeasures);
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
deleted file mode 100644 (file)
index b81be29..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { Link, IndexLink } from 'react-router';
-import LeakPeriodLegend from '../components/LeakPeriodLegend';
-import { getLeakPeriod } from '../../../helpers/periods';
-import { translate, getLocalizedMetricDomain } from '../../../helpers/l10n';
-
-export default class Home extends React.PureComponent {
-  componentDidMount() {
-    document.querySelector('html').classList.add('dashboard-page');
-    this.props.onDisplay();
-    this.props.fetchMeasures();
-  }
-
-  componentWillUnmount() {
-    document.querySelector('html').classList.remove('dashboard-page');
-  }
-
-  render() {
-    const { component, domains, periods } = this.props;
-
-    if (domains == null) {
-      return null;
-    }
-
-    const leakPeriod = getLeakPeriod(periods);
-
-    return (
-      <section id="component-measures-home" className="page page-container page-limited">
-        <header id="component-measures-home-header" className="home-header">
-          <nav className="nav-pills pull-left">
-            <ul>
-              <li>
-                <IndexLink
-                  to={{ pathname: '/component_measures', query: { id: component.key } }}
-                  activeClassName="active">
-                  {translate('all')}
-                </IndexLink>
-              </li>
-              {domains.map(domain =>
-                <li key={domain.name}>
-                  <Link
-                    to={{
-                      pathname: `/component_measures/domain/${domain.name}`,
-                      query: { id: component.key }
-                    }}
-                    activeClassName="active">
-                    {getLocalizedMetricDomain(domain.name)}
-                  </Link>
-                </li>
-              )}
-            </ul>
-          </nav>
-
-          {leakPeriod != null && <LeakPeriodLegend component={component} period={leakPeriod} />}
-        </header>
-
-        <main id="component-measures-home-main">
-          {this.props.children}
-        </main>
-      </section>
-    );
-  }
-}
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
deleted file mode 100644 (file)
index 0605a3a..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { connect } from 'react-redux';
-import Home from './Home';
-import { fetchMeasures } from './actions';
-import { displayHome } from '../app/actions';
-import {
-  getMeasuresAppHomeDomains,
-  getMeasuresAppHomePeriods,
-  getMeasuresAppComponent
-} from '../../../store/rootReducer';
-
-const mapStateToProps = state => {
-  return {
-    component: getMeasuresAppComponent(state),
-    domains: getMeasuresAppHomeDomains(state),
-    periods: getMeasuresAppHomePeriods(state)
-  };
-};
-
-const mapDispatchToProps = dispatch => {
-  return {
-    onDisplay: () => dispatch(displayHome()),
-    fetchMeasures: () => dispatch(fetchMeasures())
-  };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(Home);
diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/HomeMeasuresList.js b/server/sonar-web/src/main/js/apps/component-measures/home/HomeMeasuresList.js
deleted file mode 100644 (file)
index 7d70066..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { partition, sortBy } from 'lodash';
-import MeasuresList from './MeasuresList';
-import { domains } from '../config/domains';
-import { getLocalizedMetricName } from '../../../helpers/l10n';
-
-function sortMeasures(measures, order) {
-  const [known, unknown] = partition(measures, measure => order.includes(measure.metric.key));
-  return [
-    ...sortBy(known, measure => order.indexOf(measure.metric.key)),
-    ...sortBy(unknown, measure => getLocalizedMetricName(measure.metric))
-  ];
-}
-
-function filterIssuesMeasures(measures) {
-  const BANNED_MEASURES = [
-    'blocker_violations',
-    'new_blocker_violations',
-    'critical_violations',
-    'new_critical_violations',
-    'major_violations',
-    'new_major_violations',
-    'minor_violations',
-    'new_minor_violations',
-    'info_violations',
-    'new_info_violations'
-  ];
-  return measures.filter(measure => !BANNED_MEASURES.includes(measure.metric.key));
-}
-
-const HomeMeasuresList = ({ domain, component }) => {
-  const { measures, name } = domain;
-  const config = domains[name] || {};
-
-  const filteredMeasures = filterIssuesMeasures(measures);
-
-  const configMain = config.main || [];
-  const [mainMeasures, otherMeasures] = partition(filteredMeasures, measure =>
-    configMain.includes(measure.metric.key)
-  );
-
-  const configOrder = config.order || [];
-  const sortedMainMeasures = sortMeasures(mainMeasures, configOrder);
-  const sortedOtherMeasures = sortMeasures(otherMeasures, configOrder);
-
-  return (
-    <div className="home-measures-list clearfix">
-      {sortedMainMeasures.length > 0 &&
-        <MeasuresList
-          className="main-domain-measures"
-          measures={sortedMainMeasures}
-          component={component}
-          spaces={[]}
-        />}
-
-      {sortedOtherMeasures.length > 0 &&
-        <MeasuresList measures={sortedOtherMeasures} component={component} spaces={[]} />}
-    </div>
-  );
-};
-
-export default HomeMeasuresList;
diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/MeasureListValue.js b/server/sonar-web/src/main/js/apps/component-measures/home/MeasureListValue.js
deleted file mode 100644 (file)
index da121fc..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import Measure from '../components/Measure';
-import { isDiffMetric } from '../../../helpers/measures';
-
-const MeasureListValue = ({ measure }) => {
-  const { metric } = measure;
-
-  if (isDiffMetric(metric.key)) {
-    return (
-      <div
-        id={`measure-${measure.metric.key}-leak`}
-        className="domain-measures-value domain-measures-leak">
-        <Measure measure={measure} />
-      </div>
-    );
-  }
-
-  return (
-    <div id={`measure-${measure.metric.key}-value`} className="domain-measures-value">
-      <Measure measure={measure} />
-    </div>
-  );
-};
-
-export default MeasureListValue;
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
deleted file mode 100644 (file)
index 3ba27f5..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { Link } from 'react-router';
-import MeasureListValue from './MeasureListValue';
-import { getLocalizedMetricName } from '../../../helpers/l10n';
-import IssueTypeIcon from '../../../components/ui/IssueTypeIcon';
-
-const MeasuresList = ({ measures, component, className = 'domain-measures' }) => {
-  return (
-    <ul className={className}>
-      {measures.map(measure =>
-        <li key={measure.metric.key} id={`measure-${measure.metric.key}`}>
-          <Link
-            to={{
-              pathname: `/component_measures/metric/${measure.metric.key}`,
-              query: { id: component.key }
-            }}>
-            <div className="domain-measures-name">
-              <IssueTypeIcon query={measure.metric.key} className="little-spacer-right" />
-              <span id={`measure-${measure.metric.key}-name`}>
-                {getLocalizedMetricName(measure.metric)}
-              </span>
-            </div>
-
-            <MeasureListValue measure={measure} />
-          </Link>
-        </li>
-      )}
-    </ul>
-  );
-};
-
-export default MeasuresList;
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
deleted file mode 100644 (file)
index 6ae4585..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { startFetching, stopFetching } from '../store/statusActions';
-import { getMeasuresAndMeta } from '../../../api/measures';
-import { getLeakValue } from '../utils';
-import { getMeasuresAppComponent, getMeasuresAppAllMetrics } from '../../../store/rootReducer';
-
-export const RECEIVE_MEASURES = 'measuresApp/home/RECEIVE_MEASURES';
-
-export function receiveMeasures(measures, periods) {
-  return { type: RECEIVE_MEASURES, measures, periods };
-}
-
-function banQualityGate(component, measures) {
-  let newMeasures = [...measures];
-
-  if (!['VW', 'SVW', 'APP'].includes(component.qualifier)) {
-    newMeasures = newMeasures.filter(measure => measure.metric !== 'alert_status');
-  }
-
-  if (component.qualifier === 'APP') {
-    newMeasures = newMeasures.filter(
-      measure =>
-        measure.metric !== 'releasability_rating' && measure.metric !== 'releasability_effort'
-    );
-  }
-
-  return newMeasures;
-}
-
-export function fetchMeasures() {
-  return (dispatch, getState) => {
-    dispatch(startFetching());
-
-    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')
-      .map(metric => metric.key);
-
-    getMeasuresAndMeta(component.key, metricKeys, { additionalFields: 'periods' }).then(r => {
-      const measures = banQualityGate(component, r.component.measures)
-        .map(measure => {
-          const metric = metrics.find(metric => metric.key === measure.metric);
-          const leak = getLeakValue(measure);
-          return { ...measure, metric, leak };
-        })
-        .filter(measure => {
-          const hasValue = measure.value != null;
-          const hasLeakValue = measure.leak != null;
-          return hasValue || hasLeakValue;
-        });
-
-      const newBugs = measures.find(measure => measure.metric.key === 'new_bugs');
-
-      const applicationPeriods = newBugs ? [{ index: 1 }] : [];
-      const periods = component.qualifier === 'APP' ? applicationPeriods : r.periods;
-
-      dispatch(receiveMeasures(measures, periods));
-      dispatch(stopFetching());
-    });
-  };
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/reducer.js b/server/sonar-web/src/main/js/apps/component-measures/home/reducer.js
deleted file mode 100644 (file)
index e752229..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { groupBy, partition, sortBy, toPairs } from 'lodash';
-import { RECEIVE_MEASURES } from './actions';
-import { getLocalizedMetricName } from '../../../helpers/l10n';
-
-const initialState = {
-  measures: undefined,
-  domains: undefined,
-  periods: undefined
-};
-
-function groupByDomains(measures) {
-  const KNOWN_DOMAINS = [
-    'Releasability',
-    'Reliability',
-    'Security',
-    'Maintainability',
-    'Coverage',
-    'Duplications',
-    'Size',
-    'Complexity'
-  ];
-
-  const domains = sortBy(
-    toPairs(groupBy(measures, measure => measure.metric.domain)).map(r => {
-      const [name, measures] = r;
-      const sortedMeasures = sortBy(measures, measure => getLocalizedMetricName(measure.metric));
-
-      return { name, measures: sortedMeasures };
-    }),
-    'name'
-  );
-  const [knownDomains, unknownDomains] = partition(domains, domain =>
-    KNOWN_DOMAINS.includes(domain.name)
-  );
-  return [
-    ...sortBy(knownDomains, domain => KNOWN_DOMAINS.indexOf(domain.name)),
-    ...sortBy(unknownDomains, domain => domain.name)
-  ];
-}
-
-export default function(state = initialState, action = {}) {
-  switch (action.type) {
-    case RECEIVE_MEASURES:
-      return {
-        ...state,
-        measures: action.measures,
-        domains: groupByDomains(action.measures),
-        periods: action.periods
-      };
-    default:
-      return state;
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/hooks.js b/server/sonar-web/src/main/js/apps/component-measures/hooks.js
deleted file mode 100644 (file)
index 001948f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { isDiffMetric } from '../../helpers/measures';
-
-export function checkHistoryExistence(nextState, replace) {
-  const { metricKey } = nextState.params;
-
-  if (isDiffMetric(metricKey)) {
-    replace({
-      pathname: metricKey,
-      query: nextState.location.query
-    });
-  }
-}
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
deleted file mode 100644 (file)
index 0c4f83d..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-const routes = [
-  {
-    getComponent(_, callback) {
-      import('./app/AppContainer').then(i => callback(null, i.default));
-    },
-    childRoutes: [
-      {
-        getComponent(_, callback) {
-          import('./home/HomeContainer').then(i => callback(null, i.default));
-        },
-        childRoutes: [
-          {
-            getIndexRoute(_, callback) {
-              import('./home/AllMeasuresContainer').then(i =>
-                callback(null, { component: i.default })
-              );
-            }
-          },
-          {
-            path: 'domain/:domainName',
-            getComponent(_, callback) {
-              import('./home/DomainMeasuresContainer').then(i => callback(null, i.default));
-            }
-          }
-        ]
-      },
-      {
-        path: 'metric/:metricKey',
-        getComponent(_, callback) {
-          import('./details/MeasureDetailsContainer').then(i => callback(null, i.default));
-        },
-        childRoutes: [
-          {
-            indexRoute: {
-              onEnter(nextState, replace) {
-                const { params, location } = nextState;
-                replace({
-                  pathname: `/component_measures/metric/${params.metricKey}/list`,
-                  query: location.query
-                });
-              }
-            }
-          },
-          {
-            path: 'list',
-            getComponent(_, callback) {
-              import('./details/drilldown/ListViewContainer').then(i => callback(null, i.default));
-            }
-          },
-          {
-            path: 'tree',
-            getComponent(_, callback) {
-              import('./details/drilldown/TreeViewContainer').then(i => callback(null, i.default));
-            }
-          },
-          {
-            path: 'history',
-            onEnter(nextState, replace) {
-              replace({
-                pathname: '/project/activity',
-                query: {
-                  id: nextState.location.query.id,
-                  graph: 'custom',
-                  custom_metrics: nextState.params.metricKey
-                }
-              });
-            }
-          },
-          {
-            path: 'treemap',
-            getComponent(_, callback) {
-              import('./details/treemap/MeasureTreemapContainer').then(i =>
-                callback(null, i.default)
-              );
-            }
-          }
-        ]
-      }
-    ]
-  }
-];
-
-export default routes;
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
deleted file mode 100644 (file)
index 2bbd93d..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { getComponentTree } from '../../../api/components';
-import { enhanceWithMeasure } from '../utils';
-import { startFetching, stopFetching } from './statusActions';
-import complementary from '../config/complementary';
-import { getMeasuresAppList } from '../../../store/rootReducer';
-
-export const UPDATE_STORE = 'measuresApp/drilldown/list/UPDATE_STORE';
-
-function updateStore(state) {
-  return { type: UPDATE_STORE, state };
-}
-
-function getComplementary(metric) {
-  const comp = complementary[metric] || [];
-  return [metric, ...comp];
-}
-
-function makeRequest(baseComponent, metric, options, periodIndex = 1) {
-  const asc = metric.direction === 1;
-  const ps = 100;
-  const finalOptions = { asc, ps, metricSortFilter: 'withMeasuresOnly' };
-
-  if (metric.key.indexOf('new_') === 0) {
-    Object.assign(options, {
-      s: 'metricPeriod,name',
-      metricSort: metric.key,
-      metricPeriodSort: periodIndex
-    });
-  } else {
-    Object.assign(options, {
-      s: 'metric,name',
-      metricSort: metric.key
-    });
-  }
-
-  Object.assign(finalOptions, options);
-  return getComponentTree('leaves', baseComponent.key, getComplementary(metric.key), finalOptions);
-}
-
-function fetchLeaves(baseComponent, metric, pageIndex = 1, periodIndex = 1) {
-  const options = { p: pageIndex };
-
-  return makeRequest(baseComponent, metric, options, periodIndex).then(r => {
-    const nextComponents = enhanceWithMeasure(r.components, metric.key, periodIndex);
-
-    return {
-      components: nextComponents,
-      pageIndex: r.paging.pageIndex,
-      total: r.paging.total
-    };
-  });
-}
-
-/**
- * Fetch the first page of components for a given base component
- * @param baseComponent
- * @param metric
- * @param periodIndex
- */
-export function fetchList(baseComponent, metric, periodIndex = 1) {
-  return (dispatch, getState) => {
-    const list = getMeasuresAppList(getState());
-    if (list.baseComponent === baseComponent && list.metric === metric) {
-      return Promise.resolve();
-    }
-
-    dispatch(startFetching());
-    return fetchLeaves(baseComponent, metric, 1, periodIndex).then(r => {
-      dispatch(
-        updateStore({
-          ...r,
-          baseComponent,
-          metric
-        })
-      );
-      dispatch(stopFetching());
-    });
-  };
-}
-
-export function fetchMore(periodIndex) {
-  return (dispatch, getState) => {
-    const { baseComponent, metric, pageIndex, components } = getMeasuresAppList(getState());
-    dispatch(startFetching());
-    return fetchLeaves(baseComponent, metric, pageIndex + 1, periodIndex).then(r => {
-      const nextComponents = [...components, ...r.components];
-      dispatch(updateStore({ ...r, components: nextComponents }));
-      dispatch(stopFetching());
-    });
-  };
-}
-
-/**
- * Select specified component from the list
- * @param component A component to select
- */
-export function selectComponent(component) {
-  return dispatch => {
-    dispatch(updateStore({ selected: component }));
-  };
-}
-
-/**
- * Select next element from the list of components
- */
-export function selectNext() {
-  return (dispatch, getState) => {
-    const { components, selected } = getMeasuresAppList(getState());
-    const selectedIndex = components.indexOf(selected);
-    if (selectedIndex < components.length - 1) {
-      const nextSelected = components[selectedIndex + 1];
-      dispatch(selectComponent(nextSelected));
-    }
-  };
-}
-
-/**
- * Select previous element from the list of components
- */
-export function selectPrevious() {
-  return (dispatch, getState) => {
-    const { components, selected } = getMeasuresAppList(getState());
-    const selectedIndex = components.indexOf(selected);
-    if (selectedIndex > 0) {
-      const nextSelected = components[selectedIndex - 1];
-      dispatch(selectComponent(nextSelected));
-    }
-  };
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/store/listViewReducer.js b/server/sonar-web/src/main/js/apps/component-measures/store/listViewReducer.js
deleted file mode 100644 (file)
index ee8f9ae..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { DISPLAY_HOME } from './../app/actions';
-import { UPDATE_STORE } from './listViewActions';
-
-const initialState = {
-  components: [],
-  total: 0
-};
-
-export default function drilldownReducer(state = initialState, action = {}) {
-  switch (action.type) {
-    case DISPLAY_HOME:
-      return initialState;
-    case UPDATE_STORE:
-      return { ...state, ...action.state };
-    default:
-      return state;
-  }
-}
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
deleted file mode 100644 (file)
index 079a7e4..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { 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
deleted file mode 100644 (file)
index d07feba..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-export const START_FETCHING = 'measuresApp/status/START_FETCHING';
-export const STOP_FETCHING = 'measuresApp/status/STOP_FETCHING';
-
-export function startFetching() {
-  return { type: START_FETCHING };
-}
-
-export function stopFetching() {
-  return { type: STOP_FETCHING };
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/store/statusReducer.js b/server/sonar-web/src/main/js/apps/component-measures/store/statusReducer.js
deleted file mode 100644 (file)
index 1a993be..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { START_FETCHING, STOP_FETCHING } from './statusActions';
-
-const initialState = {
-  fetching: false
-};
-
-export default function drilldownReducer(state = initialState, action = {}) {
-  switch (action.type) {
-    case START_FETCHING:
-      return { ...state, fetching: true };
-    case STOP_FETCHING:
-      return { ...state, fetching: false };
-    default:
-      return state;
-  }
-}
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
deleted file mode 100644 (file)
index 34fffe1..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { initial } from 'lodash';
-import { getComponentTree } from '../../../api/components';
-import { enhanceWithMeasure } from '../utils';
-import { startFetching, stopFetching } from './statusActions';
-import complementary from '../config/complementary';
-import { getMeasuresAppTree } from '../../../store/rootReducer';
-
-/*
- * Actions
- */
-
-export const UPDATE_STORE = 'measuresApp/drilldown/tree/UPDATE_STORE';
-export const INIT = 'measuresApp/drilldown/tree/INIT';
-
-/*
- * Action Creators
- */
-
-/**
- * Internal
- * Update store
- * @param state
- * @returns {{type: string, state: *}}
- */
-function updateStore(state) {
-  return { type: UPDATE_STORE, state };
-}
-
-/**
- * Init tree view drilldown for the given root component and given metric
- * @param rootComponent
- * @param metric
- * @param periodIndex
- * @returns {{type: string, rootComponent: *, metric: *}}
- */
-function init(rootComponent, metric, periodIndex = 1) {
-  return { type: INIT, rootComponent, metric, periodIndex };
-}
-
-/*
- * Workflow
- */
-
-function getComplementary(metric) {
-  const comp = complementary[metric] || [];
-  return [metric, ...comp];
-}
-
-function makeRequest(rootComponent, baseComponent, metric, options, periodIndex = 1) {
-  const asc = metric.direction === 1;
-  const ps = 100;
-  const finalOptions = { asc, ps, metricSortFilter: 'withMeasuresOnly' };
-
-  if (metric.key.indexOf('new_') === 0) {
-    Object.assign(options, {
-      s: 'metricPeriod,name',
-      metricSort: metric.key,
-      metricPeriodSort: periodIndex
-    });
-  } else {
-    Object.assign(options, {
-      s: 'metric,name',
-      metricSort: metric.key
-    });
-  }
-
-  if (rootComponent.qualifier === 'DEV' && baseComponent.qualifier !== 'DEV') {
-    Object.assign(options, { developerId: rootComponent.id });
-  }
-
-  Object.assign(finalOptions, options);
-
-  const finalKey = baseComponent.refKey || baseComponent.key;
-
-  return getComponentTree('children', finalKey, getComplementary(metric.key), finalOptions);
-}
-
-function fetchComponents(rootComponent, baseComponent, metric, pageIndex = 1, periodIndex = 1) {
-  const options = { p: pageIndex };
-
-  return makeRequest(rootComponent, baseComponent, metric, options, periodIndex).then(r => {
-    const nextComponents = enhanceWithMeasure(r.components, metric.key, periodIndex);
-
-    return {
-      baseComponent,
-      components: nextComponents,
-      pageIndex: r.paging.pageIndex,
-      total: r.paging.total
-    };
-  });
-}
-
-/**
- * Fetch the first page of components for a given base component
- * @param baseComponent
- */
-function fetchList(baseComponent) {
-  return (dispatch, getState) => {
-    const { metric, periodIndex, rootComponent } = getMeasuresAppTree(getState());
-
-    dispatch(startFetching());
-    return fetchComponents(rootComponent, baseComponent, metric, 1, periodIndex).then(r => {
-      dispatch(
-        updateStore({
-          ...r,
-          baseComponent,
-          breadcrumbs: [baseComponent]
-        })
-      );
-      dispatch(stopFetching());
-    });
-  };
-}
-
-/**
- * Init tree view with root component and metric.
- * Fetch the first page of components if needed.
- * @param rootComponent
- * @param metric
- * @param periodIndex
- * @returns {function()}
- */
-export function start(rootComponent, metric, periodIndex = 1) {
-  return (dispatch, getState) => {
-    const tree = getMeasuresAppTree(getState());
-    if (rootComponent === tree.rootComponent && metric === tree.metric) {
-      return Promise.resolve();
-    }
-
-    dispatch(init(rootComponent, metric, periodIndex));
-    dispatch(fetchList(rootComponent));
-  };
-}
-
-/**
- * Drilldown to the component
- * @param component
- */
-export function drilldown(component) {
-  return (dispatch, getState) => {
-    const { metric, rootComponent, breadcrumbs, periodIndex } = getMeasuresAppTree(getState());
-    dispatch(startFetching());
-    return fetchComponents(rootComponent, component, metric, 1, periodIndex).then(r => {
-      dispatch(
-        updateStore({
-          ...r,
-          breadcrumbs: [...breadcrumbs, component],
-          selected: undefined
-        })
-      );
-      dispatch(stopFetching());
-    });
-  };
-}
-
-/**
- * Go up using breadcrumbs
- * @param component
- */
-export function useBreadcrumbs(component) {
-  return (dispatch, getState) => {
-    const { metric, rootComponent, breadcrumbs, periodIndex } = getMeasuresAppTree(getState());
-    const index = breadcrumbs.indexOf(component);
-    dispatch(startFetching());
-    return fetchComponents(rootComponent, component, metric, 1, periodIndex).then(r => {
-      dispatch(
-        updateStore({
-          ...r,
-          breadcrumbs: breadcrumbs.slice(0, index + 1),
-          selected: undefined
-        })
-      );
-      dispatch(stopFetching());
-    });
-  };
-}
-
-export function fetchMore() {
-  return (dispatch, getState) => {
-    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];
-      dispatch(updateStore({ ...r, components: nextComponents }));
-      dispatch(stopFetching());
-    });
-  };
-}
-
-/**
- * Select given component from the list
- * @param component
- */
-export function selectComponent(component) {
-  return (dispatch, getState) => {
-    const { breadcrumbs } = getMeasuresAppTree(getState());
-    const nextBreadcrumbs = [...breadcrumbs, component];
-    dispatch(
-      updateStore({
-        selected: component,
-        breadcrumbs: nextBreadcrumbs
-      })
-    );
-  };
-}
-
-/**
- * Select next element from the list of components
- */
-export function selectNext() {
-  return (dispatch, getState) => {
-    const { components, selected, breadcrumbs } = getMeasuresAppTree(getState());
-    const selectedIndex = components.indexOf(selected);
-    if (selectedIndex < components.length - 1) {
-      const nextSelected = components[selectedIndex + 1];
-      const nextBreadcrumbs = [...initial(breadcrumbs), nextSelected];
-      dispatch(
-        updateStore({
-          selected: nextSelected,
-          breadcrumbs: nextBreadcrumbs
-        })
-      );
-    }
-  };
-}
-
-/**
- * Select previous element from the list of components
- */
-export function selectPrevious() {
-  return (dispatch, getState) => {
-    const { components, selected, breadcrumbs } = getMeasuresAppTree(getState());
-    const selectedIndex = components.indexOf(selected);
-    if (selectedIndex > 0) {
-      const nextSelected = components[selectedIndex - 1];
-      const nextBreadcrumbs = [...initial(breadcrumbs), nextSelected];
-      dispatch(
-        updateStore({
-          selected: nextSelected,
-          breadcrumbs: nextBreadcrumbs
-        })
-      );
-    }
-  };
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/store/treeViewReducer.js b/server/sonar-web/src/main/js/apps/component-measures/store/treeViewReducer.js
deleted file mode 100644 (file)
index 71050fd..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { pick } from 'lodash';
-import { DISPLAY_HOME } from './../app/actions';
-import { UPDATE_STORE, INIT } from './treeViewActions';
-
-const initialState = {
-  components: [],
-  breadcrumbs: [],
-  total: 0
-};
-
-export default function drilldownReducer(state = initialState, action = {}) {
-  switch (action.type) {
-    case DISPLAY_HOME:
-      return initialState;
-    case UPDATE_STORE:
-      return { ...state, ...action.state };
-    case INIT:
-      return { ...state, ...pick(action, ['rootComponent', 'metric', 'periodIndex']) };
-    default:
-      return state;
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/styles.css b/server/sonar-web/src/main/js/apps/component-measures/styles.css
deleted file mode 100644 (file)
index b72fcf3..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-.home-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: flex-start;
-  margin-bottom: 20px;
-}
-
-.measures-domains {
-}
-
-.measures-domains > li {
-  margin-bottom: 20px;
-}
-
-.measures-domains > li > div {
-  border: 1px solid #e6e6e6;
-  background-color: #fff;
-}
-
-.measures-domains-leak-header {
-  line-height: 22px;
-  padding: 0 10px;
-  border: 1px solid #eae3c7;
-  background-color: #fbf3d5;
-  white-space: nowrap;
-}
-
-.main-domain-measures {
-  display: flex;
-  flex-wrap: wrap;
-  justify-content: space-around;
-  float: left;
-  width: 480px;
-  margin-right: 60px;
-}
-
-.main-domain-measures > li {
-  padding: 12px 0;
-}
-
-.main-domain-measures > li > a {
-  display: flex;
-  flex-direction: column-reverse;
-  width: 160px;
-  border: none;
-  text-align: center;
-}
-
-.main-domain-measures .domain-measures-value {
-  height: 40px;
-  box-sizing: border-box;
-  color: #444;
-  font-size: 30px;
-  font-weight: 300;
-}
-
-.main-domain-measures .domain-measures-value .rating,
-.measure-details-value .rating {
-  vertical-align: top;
-  width: 40px;
-  height: 40px;
-  line-height: 40px;
-  border-radius: 40px;
-  font-size: 24px;
-}
-
-.main-domain-measures .domain-measures-name {
-  margin-top: 8px;
-}
-
-.main-domain-measures .domain-measures-name > span:last-child {
-  border-bottom: 1px solid #cae3f2;
-}
-
-.main-domain-measures .domain-measures-leak {
-  margin: 0 20px;
-  border: 1px solid #eae3c7;
-  background-color: #fbf3d5;
-}
-
-.domain-measures {
-  overflow: hidden;
-  line-height: 1.4;
-}
-
-.domain-measures > li > a {
-  display: flex;
-  justify-content: space-between;
-  border: none;
-}
-
-.domain-measures > li:nth-child(odd) > a {
-  background-color: #f8f8f8;
-}
-
-.domain-measures > li > a:hover {
-  background-color: #ecf6fe !important;
-}
-
-.domain-measures .domain-measures-name,
-.domain-measures .domain-measures-value {
-  padding: 7px 10px;
-  box-sizing: border-box;
-}
-
-.domain-measures .domain-measures-name {
-  width: calc(100% - 160px);
-  line-height: 24px;
-}
-
-.domain-measures .domain-measures-name > span {
-  border-bottom: 1px solid #cae3f2;
-}
-
-.domain-measures .domain-measures-value {
-  min-width: 80px;
-  color: #444;
-  text-align: right;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-
-.domain-measures .domain-measures-leak {
-  background-color: #fbf3d5;
-  transition: background-color 0.3s ease;
-}
-
-.domain-measures .domain-measures > li:nth-child(odd) .domain-measures-leak {
-  background-color: #f5eed0;
-}
-
-.measure-details {
-  margin-top: 10px;
-}
-
-.measure-details-header {
-  position: relative;
-  margin-top: 10px;
-  margin-bottom: 30px;
-}
-
-.measure-details-metric,
-.measure-details-value {
-}
-
-.measure-details-metric {
-  display: inline-block;
-  margin-bottom: 10px;
-}
-
-.measure-details-metric > a:not(.button) {
-  border: none;
-  color: #444;
-}
-
-.measure-details-metric > a:not(.button):hover {
-  color: #236a97;
-}
-
-.measure-details-value {
-  font-size: 24px;
-}
-
-.measure-details-value-absolute {
-  display: inline-block;
-  vertical-align: middle;
-  padding: 5px 0;
-  font-weight: 300;
-}
-
-.measure-details-value-leak {
-  display: inline-block;
-  vertical-align: middle;
-  padding: 4px 10px;
-  border: 1px solid #eae3c7;
-  background-color: #fbf3d5;
-  font-weight: 300;
-}
-
-.measure-details-value-absolute + .measure-details-value-leak {
-  margin-left: 20px;
-}
-
-.measure-details-secondary {
-  display: inline-block;
-  vertical-align: middle;
-  width: 260px;
-  margin-left: 20px;
-}
-
-.measure-details-drilldown {
-  margin-top: 20px;
-}
-
-.measure-details-drilldown-mode {
-  display: flex;
-  margin-bottom: 10px;
-  border-bottom: 1px solid #e6e6e6;
-}
-
-.measure-details-drilldown-mode > li {
-  margin-bottom: -1px;
-}
-
-.measure-details-drilldown-mode > li + li {
-  margin-left: 2px;
-}
-
-.measure-details-drilldown-mode > li > a {
-  display: inline-block;
-  padding: 5px 10px;
-  border-bottom: 2px solid transparent;
-  color: #444;
-}
-
-.measure-details-drilldown-mode > li > a:hover,
-.measure-details-drilldown-mode > li > a.active {
-  border-bottom-color: #4b9fd5;
-}
-
-.measure-details-drilldown-mode > li > a.active .measure-tab-icon path {
-  fill: #4b9fd5;
-}
-
-.measure-details-plain-list {
-}
-
-.measure-details-components {
-  width: 300px;
-  padding: 10px;
-  box-sizing: border-box;
-}
-
-.measure-details-components > li > a {
-  display: flex;
-  padding-top: 5px;
-  padding-bottom: 5px;
-  border: none;
-  color: #444;
-}
-
-.measure-details-components > li > a:hover,
-.measure-details-components > li > a.selected {
-  background-color: #cae3f2 !important;
-}
-
-.measure-details-component-name,
-.measure-details-component-value {
-  padding-right: 10px;
-  box-sizing: border-box;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-
-.measure-details-component-name {
-  width: calc(100% - 60px);
-  padding-left: 10px;
-}
-
-.measure-details-component-value {
-  width: 60px;
-  text-align: right;
-}
-
-.measure-details-viewer {
-  min-height: 100vh;
-}
-
-.measure-details-viewer-header {
-  margin-bottom: 10px;
-  line-height: 24px;
-}
-
-.measure-details-viewer-header .button-group {
-  vertical-align: top;
-}
-
-.measure-details-header-container {
-  display: inline-block;
-  line-height: 16px;
-  padding-right: 10px;
-}
-
-.measure-tab-icon {
-  display: inline-block;
-  width: 14px;
-  height: 14px;
-  margin-right: 6px;
-}
-
-.measure-tab-icon path {
-  fill: #aeaeae;
-  transition: fill 0.3s ease;
-}
-
-.measure-details-components-up-icon path {
-  fill: #aeaeae;
-}
-
-.measure-details-history {
-  padding: 10px 0;
-}
-
-.measure-details-bubble-chart {
-  position: relative;
-  margin: 40px 0 10px;
-  padding: 30px 0 30px 60px;
-  border: 1px solid #e6e6e6;
-  background-color: #fff;
-}
-
-.measure-details-bubble-chart-axis {
-  position: absolute;
-  color: #777;
-  font-size: 12px;
-}
-
-.measure-details-bubble-chart-axis.x {
-  left: 50%;
-  bottom: 10px;
-  width: 500px;
-  margin-left: -250px;
-  text-align: center;
-}
-
-.measure-details-bubble-chart-axis.y {
-  top: 50%;
-  left: -20px;
-  transform: rotate(-90deg);
-}
-
-.measure-details-bubble-chart-axis.size {
-  left: 50%;
-  top: 10px;
-  width: 500px;
-  margin-left: -250px;
-  text-align: center;
-}
-
-.measure-details-treemap {
-  margin: 20px 0;
-}
-
-.measure-details-treemap-legend {
-  margin-bottom: 10px;
-}
-
-.component-measures-breadcrumbs {
-  display: flex;
-  flex-wrap: wrap;
-}
-
-.component-measures-breadcrumbs > li {
-  padding: 5px 5px 3px;
-}
-
-.component-measures-breadcrumbs > li:first-child {
-  padding-left: 0;
-}
-
-.component-measures-breadcrumbs > li::after {
-  position: relative;
-  top: -1px;
-  padding-left: 10px;
-  color: #777;
-  font-size: 11px;
-  content: ">";
-}
-
-.component-measures-breadcrumbs > li:last-child::after {
-  display: none;
-}
-
-.home-measures-list {
-  border: 1px solid #e6e6e6;
-  background-color: #fff;
-}
-
-.nav-pills > ul {
-  display: flex;
-  flex-wrap: wrap;
-}
-
-.nav-pills > ul > li > a {
-  display: inline-block;
-  vertical-align: middle;
-  padding: 3px 10px;
-  border: 1px solid transparent;
-  border-radius: 24px;
-  color: #236a97;
-  transition: none;
-}
-
-.nav-pills > ul > li > a:hover {
-  border-color: #236a97;
-}
-
-.nav-pills > ul > li.active > a,
-.nav-pills > ul > li > a.active {
-  background-color: #236a97;
-  color: #fff;
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/utils.js b/server/sonar-web/src/main/js/apps/component-measures/utils.js
deleted file mode 100644 (file)
index 20595c7..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import bubbles from './config/bubbles';
-import {
-  formatMeasure,
-  formatMeasureVariation,
-  getRatingTooltip as nextGetRatingTooltip,
-  isDiffMetric
-} from '../../helpers/measures';
-
-export function getLeakValue(measure, periodIndex = 1) {
-  if (!measure) {
-    return null;
-  }
-
-  const period = measure.periods
-    ? measure.periods.find(period => period.index === periodIndex)
-    : null;
-
-  return period ? period.value : null;
-}
-
-export function getSingleMeasureValue(measures) {
-  if (!measures || !measures.length) {
-    return null;
-  }
-
-  return measures[0].value;
-}
-
-export function getSingleLeakValue(measures, periodIndex = 1) {
-  if (!measures || !measures.length) {
-    return null;
-  }
-
-  const measure = measures[0];
-
-  const period = measure.periods
-    ? measure.periods.find(period => period.index === periodIndex)
-    : null;
-
-  return period ? period.value : null;
-}
-
-export function formatLeak(value, metric, options) {
-  if (isDiffMetric(metric.key)) {
-    return formatMeasure(value, metric.type, options);
-  } else {
-    return formatMeasureVariation(value, metric.type, options);
-  }
-}
-
-export function enhanceWithLeak(measures, periodIndex = 1) {
-  function enhanceSingle(measure) {
-    return { ...measure, leak: getLeakValue(measure, periodIndex) };
-  }
-
-  if (Array.isArray(measures)) {
-    return measures.map(enhanceSingle);
-  } else {
-    return enhanceSingle(measures);
-  }
-}
-
-export function enhanceWithSingleMeasure(components, periodIndex = 1) {
-  return components.map(component => {
-    return {
-      ...component,
-      value: getSingleMeasureValue(component.measures),
-      leak: getSingleLeakValue(component.measures, periodIndex)
-    };
-  });
-}
-
-export function enhanceWithMeasure(components, metric, periodIndex = 1) {
-  return components.map(component => {
-    const measuresWithLeak = enhanceWithLeak(component.measures, periodIndex);
-    const measure = measuresWithLeak.find(measure => measure.metric === metric);
-    const value = measure ? measure.value : null;
-    const leak = measure ? measure.leak : null;
-    return { ...component, value, leak, measures: measuresWithLeak };
-  });
-}
-
-export function hasBubbleChart(domainName) {
-  return !!bubbles[domainName];
-}
-
-export function hasTreemap(metric) {
-  return ['PERCENT', 'RATING', 'LEVEL'].indexOf(metric.type) !== -1;
-}
-
-export function filterOutEmptyMeasures(components) {
-  return components.filter(component => component.value !== null || component.leak !== null);
-}
-
-export function getRatingTooltip(metricKey, value) {
-  const finalMetricKey = metricKey.indexOf('new_') === 0 ? metricKey.substr(4) : metricKey;
-  const KNOWN_RATINGS = ['sqale_rating', 'reliability_rating', 'security_rating'];
-  if (KNOWN_RATINGS.includes(finalMetricKey)) {
-    return nextGetRatingTooltip(finalMetricKey, value);
-  }
-  return null;
-}
index ec90cafe30f3d25a0ec7d269cc758c874161f8ff..25af253cd1c37daad4a982aab7d89c301e3a8c30 100644 (file)
@@ -31,11 +31,11 @@ class BugsAndVulnerabilities extends React.PureComponent {
   renderHeader() {
     const { component } = this.props;
     const bugsDomainUrl = {
-      pathname: '/component_measures/domain/Reliability',
+      pathname: '/component_measures_old/domain/Reliability',
       query: { id: component.key }
     };
     const vulnerabilitiesDomainUrl = {
-      pathname: '/component_measures/domain/Security',
+      pathname: '/component_measures_old/domain/Security',
       query: { id: component.key }
     };
 
index b5599d43c00b9822ca61e50ee86111cca7b8f9f5..1deeeab4ddbcf47712940e0b4abf7911b736cffc 100644 (file)
@@ -56,7 +56,7 @@ export default function enhance(ComposedComponent) {
     renderHeader = (domain, label) => {
       const { component } = this.props;
       const domainUrl = {
-        pathname: `/component_measures/domain/${domain}`,
+        pathname: `/component_measures_old/domain/${domain}`,
         query: { id: component.key }
       };
 
index 47ff132eadd6b5e5e69afd748ca328535b1c39b5..905f06b0d6834f37cf0ef84848c969d86c927882 100644 (file)
@@ -22,7 +22,7 @@ import React from 'react';
 import classNames from 'classnames';
 import { Link } from 'react-router';
 import { DrilldownLink } from '../../../components/shared/drilldown-link';
-import Measure from '../../component-measures/components/Measure';
+import Measure from '../../component-measures-old/components/Measure';
 import { getPeriodValue, isDiffMetric, formatMeasure } from '../../../helpers/measures';
 import { translate } from '../../../helpers/l10n';
 import { getComponentIssuesUrl } from '../../../helpers/urls';
index 2675af498751776088366c5d7b7556011c9b620a..4189c2e1a64e7aa3799ca7349528e525e9cacbb0 100644 (file)
@@ -19,7 +19,7 @@
  */
 //@flow
 import React from 'react';
-import Measure from '../../component-measures/components/Measure';
+import Measure from '../../component-measures-old/components/Measure';
 import BugIcon from '../../../components/icons-components/BugIcon';
 import CodeSmellIcon from '../../../components/icons-components/CodeSmellIcon';
 import Rating from '../../../components/ui/Rating';
index 7a1c8a31c6c9d0514f225952e14cb513344c17a5..546b511eb0ef01424b0dee4122fcf035abb6d956 100644 (file)
@@ -20,7 +20,7 @@
 //@flow
 import React from 'react';
 import ProjectCardLanguages from './ProjectCardLanguages';
-import Measure from '../../component-measures/components/Measure';
+import Measure from '../../component-measures-old/components/Measure';
 import Rating from '../../../components/ui/Rating';
 import CoverageRating from '../../../components/ui/CoverageRating';
 import DuplicationsRating from '../../../components/ui/DuplicationsRating';
index 0f5fb66e39a554cb159dcda3a905a18c414d73f2..c74c18a8b36364f24d5271a1c9f2ef4ca82e7536 100644 (file)
@@ -78,14 +78,14 @@ describe('#getComponentIssuesUrl', () => {
 describe('#getComponentDrilldownUrl', () => {
   it('should return component drilldown url', () => {
     expect(getComponentDrilldownUrl(SIMPLE_COMPONENT_KEY, METRIC)).toEqual({
-      pathname: '/component_measures/metric/' + METRIC,
+      pathname: '/component_measures_old/metric/' + METRIC,
       query: { id: SIMPLE_COMPONENT_KEY }
     });
   });
 
   it('should not encode component key', () => {
     expect(getComponentDrilldownUrl(COMPLEX_COMPONENT_KEY, METRIC)).toEqual({
-      pathname: '/component_measures/metric/' + METRIC,
+      pathname: '/component_measures_old/metric/' + METRIC,
       query: { id: COMPLEX_COMPONENT_KEY }
     });
   });
index 27c2ec6ee6ce22006bda5fc3e497d6d19d3e0111..84bf3e4fd637a8f7d2bd095295548dc05d808cf1 100644 (file)
@@ -63,7 +63,7 @@ export function getComponentIssuesUrlAsString(componentKey, query) {
  */
 export function getComponentDrilldownUrl(componentKey, metric) {
   return {
-    pathname: `/component_measures/metric/${metric}`,
+    pathname: `/component_measures_old/metric/${metric}`,
     query: { id: componentKey }
   };
 }
index a0f81547c53cdfc035912477711486829380b1f0..76355147ac91e533b54b1130cf0a9770e1ca4a2e 100644 (file)
@@ -28,7 +28,7 @@ import notifications, * as fromNotifications from './notifications/duck';
 import organizations, * as fromOrganizations from './organizations/duck';
 import organizationsMembers, * as fromOrganizationsMembers from './organizationsMembers/reducer';
 import globalMessages, * as fromGlobalMessages from './globalMessages/duck';
-import measuresApp, * as fromMeasuresApp from '../apps/component-measures/store/rootReducer';
+import measuresApp, * as fromMeasuresApp from '../apps/component-measures-old/store/rootReducer';
 import permissionsApp, * as fromPermissionsApp from '../apps/permissions/shared/store/rootReducer';
 import projectAdminApp, * as fromProjectAdminApp from '../apps/project-admin/store/rootReducer';
 import projectsApp, * as fromProjectsApp from '../apps/projects/store/reducer';