aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/apps/component-measures/components/MeasureTree.js
diff options
context:
space:
mode:
Diffstat (limited to 'server/sonar-web/src/main/js/apps/component-measures/components/MeasureTree.js')
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/MeasureTree.js140
1 files changed, 140 insertions, 0 deletions
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureTree.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureTree.js
new file mode 100644
index 00000000000..8e4ceb16542
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureTree.js
@@ -0,0 +1,140 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+
+import Spinner from './Spinner';
+import ComponentsList from './ComponentsList';
+import NoResults from './NoResults';
+import SourceViewer from '../../code/components/SourceViewer';
+import { getSingleMeasureValue } from '../utils';
+import { getChildren } from '../../../api/components';
+
+export default class MeasureTree extends React.Component {
+ state = {
+ components: [],
+ breadcrumbs: [],
+ selected: null,
+ fetching: true
+ };
+
+ componentDidMount () {
+ this.mounted = true;
+ this.fetchComponents(this.context.component);
+ }
+
+ componentDidUpdate (nextProps, nextState, nextContext) {
+ if ((nextProps.metric !== this.props.metric) ||
+ (nextContext.component !== this.context.component)) {
+ this.fetchComponents(nextContext.component);
+ }
+ }
+
+ componentWillUnmount () {
+ this.mounted = false;
+ }
+
+ fetchComponents (baseComponent) {
+ const { metric } = this.props;
+ const asc = metric.direction === 1;
+
+ const options = {
+ s: 'metric,name',
+ metricSort: metric.key,
+ asc
+ };
+
+ this.setState({ fetching: true });
+
+ getChildren(baseComponent.key, [metric.key], options).then(children => {
+ if (this.mounted) {
+ const componentsWithMappedMeasure = children
+ .map(component => {
+ return {
+ ...component,
+ value: getSingleMeasureValue(component.measures)
+ };
+ })
+ .filter(component => component.value != null);
+
+ const indexInBreadcrumbs = this.state.breadcrumbs.findIndex(component => component === baseComponent);
+ const breadcrumbs = indexInBreadcrumbs !== -1 ?
+ this.state.breadcrumbs.slice(0, indexInBreadcrumbs + 1) :
+ [...this.state.breadcrumbs, baseComponent];
+
+ this.setState({
+ baseComponent,
+ breadcrumbs,
+ components: componentsWithMappedMeasure,
+ selected: null,
+ fetching: false
+ });
+ }
+ });
+ }
+
+ handleFileClick (component) {
+ if (component.qualifier === 'FIL' || component.qualifier === 'UTS') {
+ this.handleFileOpen(component);
+ } else {
+ this.fetchComponents(component);
+ }
+ }
+
+ handleFileOpen (selected) {
+ this.setState({ selected });
+ }
+
+ render () {
+ const { metric } = this.props;
+ const { components, selected, breadcrumbs, fetching } = this.state;
+ const parent = breadcrumbs.length > 1 ? breadcrumbs[breadcrumbs.length - 2] : null;
+
+ if (fetching) {
+ return <Spinner/>;
+ }
+
+ if (!components.length) {
+ return <NoResults/>;
+ }
+
+ return (
+ <div className="measure-details-tree">
+ <div className="measure-details-components">
+ <ComponentsList
+ components={components}
+ selected={selected}
+ parent={parent}
+ metric={metric}
+ onClick={this.handleFileClick.bind(this)}/>
+ </div>
+
+ {selected && (
+ <div className="measure-details-viewer">
+ <SourceViewer component={selected}/>
+ </div>
+ )}
+ </div>
+ );
+ }
+}
+
+MeasureTree.contextTypes = {
+ component: React.PropTypes.object
+};