]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9689 Replaced file navigation button with j/k shortcut in measures page
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Thu, 21 Sep 2017 13:13:58 +0000 (15:13 +0200)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Mon, 25 Sep 2017 11:18:37 +0000 (13:18 +0200)
server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.js
server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.js
server/sonar-web/src/main/js/apps/component-measures/components/PageActions.js
server/sonar-web/src/main/js/apps/component-measures/components/__tests__/MeasureHeader-test.js
server/sonar-web/src/main/js/apps/component-measures/components/__tests__/PageActions-test.js
server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.js.snap
server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/PageActions-test.js.snap
server/sonar-web/src/main/js/apps/component-measures/drilldown/CodeView.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/component-measures/drilldown/FilesView.js
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 47675037a7b96038aa0fa1188095dc88d86a9144..16ba5d4ba82707c00fcfefd412f766e0ffc207a8 100644 (file)
@@ -20,6 +20,7 @@
 // @flow
 import React from 'react';
 import classNames from 'classnames';
+import CodeView from '../drilldown/CodeView';
 import Breadcrumbs from './Breadcrumbs';
 import FilesView from '../drilldown/FilesView';
 import MeasureFavoriteContainer from './MeasureFavoriteContainer';
@@ -27,14 +28,12 @@ import MeasureHeader from './MeasureHeader';
 import MeasureViewSelect from './MeasureViewSelect';
 import MetricNotFound from './MetricNotFound';
 import PageActions from './PageActions';
-import SourceViewer from '../../../components/SourceViewer/SourceViewer';
 import TreeMapView from '../drilldown/TreeMapView';
 import { getComponentTree } from '../../../api/components';
 import { complementary } from '../config/complementary';
 import { enhanceComponent, isFileType, isViewType } from '../utils';
 import { getProjectUrl } from '../../../helpers/urls';
 import { isDiffMetric } from '../../../helpers/measures';
-import { parseDate } from '../../../helpers/dates';
 /*:: import type { Component, ComponentEnhanced, Paging, Period } from '../types'; */
 /*:: import type { MeasureEnhanced } from '../../../components/measure/types'; */
 /*:: import type { Metric } from '../../../store/metrics/actions'; */
@@ -223,24 +222,17 @@ export default class MeasureContent extends React.PureComponent {
   onSelectComponent = (componentKey /*: string */) => this.setState({ selected: componentKey });
 
   renderCode() {
-    const { branch, component, leakPeriod } = this.props;
-    const leakPeriodDate =
-      isDiffMetric(this.props.metric.key) && leakPeriod != null ? parseDate(leakPeriod.date) : null;
-
-    let filterLine;
-    if (leakPeriodDate != null) {
-      filterLine = line => {
-        if (line.scmDate) {
-          const scmDate = parseDate(line.scmDate);
-          return scmDate >= leakPeriodDate;
-        } else {
-          return false;
-        }
-      };
-    }
     return (
       <div className="measure-details-viewer">
-        <SourceViewer branch={branch} component={component.key} filterLine={filterLine} />
+        <CodeView
+          branch={this.props.branch}
+          component={this.props.component}
+          components={this.state.components}
+          leakPeriod={this.props.leakPeriod}
+          metric={this.props.metric}
+          selectedIdx={this.getSelectedIndex()}
+          updateSelected={this.props.updateSelected}
+        />
       </div>
     );
   }
@@ -322,6 +314,7 @@ export default class MeasureContent extends React.PureComponent {
                 loading={this.props.loading}
                 isFile={isFile}
                 paging={this.state.paging}
+                totalLoadedComponents={this.state.components.length}
                 view={view}
               />
             </div>
@@ -337,11 +330,9 @@ export default class MeasureContent extends React.PureComponent {
               branch={branch}
               component={component}
               components={this.state.components}
-              handleSelect={this.props.updateSelected}
               leakPeriod={this.props.leakPeriod}
               measure={measure}
               secondaryMeasure={this.props.secondaryMeasure}
-              selectedIdx={selectedIdx}
             />
             {isFileType(component) ? this.renderCode() : this.renderMeasure()}
           </div>
index 49f039c35d112cc20a1ed178f6a0fbc5a7251374..81853659e39d7ef6036a46a4db37e0ca703cacc8 100644 (file)
@@ -27,8 +27,7 @@ import LanguageDistributionContainer from '../../../components/charts/LanguageDi
 import LeakPeriodLegend from './LeakPeriodLegend';
 import Measure from '../../../components/measure/Measure';
 import Tooltip from '../../../components/controls/Tooltip';
-import { isFileType } from '../utils';
-import { getLocalizedMetricName, translate, translateWithParameters } from '../../../helpers/l10n';
+import { getLocalizedMetricName, translate } from '../../../helpers/l10n';
 import { getMeasureHistoryUrl } from '../../../helpers/urls';
 import { isDiffMetric } from '../../../helpers/measures';
 /*:: import type { Component, Period } from '../types'; */
@@ -39,124 +38,70 @@ import { isDiffMetric } from '../../../helpers/measures';
   component: Component,
   components: Array<Component>,
   leakPeriod?: Period,
-  handleSelect: string => void,
   measure: MeasureEnhanced,
-  secondaryMeasure: ?MeasureEnhanced,
-  selectedIdx: ?number
+  secondaryMeasure: ?MeasureEnhanced
 |}; */
 
-export default class MeasureHeader extends React.PureComponent {
-  /*:: props: Props; */
-
-  handleSelectPrevious = (e /*: Event & { target: HTMLElement } */) => {
-    e.target.blur();
-    if (this.props.selectedIdx != null) {
-      const prevComponent = this.props.components[this.props.selectedIdx - 1];
-      if (prevComponent) {
-        this.props.handleSelect(prevComponent.key);
-      }
-    }
-  };
-
-  handleSelectNext = (e /*: Event & { target: HTMLElement } */) => {
-    e.target.blur();
-    if (this.props.selectedIdx != null) {
-      const prevComponent = this.props.components[this.props.selectedIdx + 1];
-      if (prevComponent) {
-        this.props.handleSelect(prevComponent.key);
-      }
-    }
-  };
-
-  renderFileNav() {
-    const { components, selectedIdx } = this.props;
-    if (selectedIdx == null) {
-      return null;
-    }
-    const hasPrevious = selectedIdx > 0;
-    const hasNext = selectedIdx < components.length - 1;
-    return (
-      <div className="display-inline-block">
-        {components.length > 0 && (
-          <span className="note spacer-right">
-            {translateWithParameters(
-              'component_measures.x_of_y',
-              selectedIdx + 1,
-              components.length
-            )}
+export default function MeasureHeader(props /*: Props*/) {
+  const { branch, component, leakPeriod, measure, secondaryMeasure } = props;
+  const metric = measure.metric;
+  const isDiff = isDiffMetric(metric.key);
+  const hasHistory = !isDiff && ['TRK', 'VW', 'SVW', 'APP'].includes(component.qualifier);
+  return (
+    <div className="measure-details-header big-spacer-bottom">
+      <div className="measure-details-primary">
+        <div className="measure-details-metric">
+          <IssueTypeIcon query={metric.key} className="little-spacer-right text-text-bottom" />
+          {getLocalizedMetricName(metric)}
+          <span className="measure-details-value spacer-left">
+            <strong>
+              {isDiff ? (
+                <Measure className="domain-measures-leak" measure={measure} metric={metric} />
+              ) : (
+                <Measure measure={measure} metric={metric} />
+              )}
+            </strong>
           </span>
-        )}
-        <div className="button-group">
-          {hasPrevious && <button onClick={this.handleSelectPrevious}>&lt;</button>}
-          {hasNext && <button onClick={this.handleSelectNext}>&gt;</button>}
+          {hasHistory && (
+            <Tooltip
+              placement="right"
+              overlay={translate('component_measures.show_metric_history')}>
+              <Link
+                className="js-show-history spacer-left button button-small button-compact"
+                to={getMeasureHistoryUrl(component.key, metric.key, branch)}>
+                <HistoryIcon />
+              </Link>
+            </Tooltip>
+          )}
         </div>
-      </div>
-    );
-  }
-
-  render() {
-    const { branch, component, components, leakPeriod, measure, secondaryMeasure } = this.props;
-    const metric = measure.metric;
-    const isDiff = isDiffMetric(metric.key);
-    const hasHistory = !isDiff && ['TRK', 'VW', 'SVW', 'APP'].includes(component.qualifier);
-    const hasComponents = components && components.length > 1;
-    return (
-      <div className="measure-details-header big-spacer-bottom">
-        <div className="measure-details-primary">
-          <div className="measure-details-metric">
-            <IssueTypeIcon query={metric.key} className="little-spacer-right text-text-bottom" />
-            {getLocalizedMetricName(metric)}
-            <span className="measure-details-value spacer-left">
-              <strong>
-                {isDiff ? (
-                  <Measure className="domain-measures-leak" measure={measure} metric={metric} />
-                ) : (
-                  <Measure measure={measure} metric={metric} />
-                )}
-              </strong>
-            </span>
-            {hasHistory && (
-              <Tooltip
-                placement="right"
-                overlay={translate('component_measures.show_metric_history')}>
-                <Link
-                  className="js-show-history spacer-left button button-small button-compact"
-                  to={getMeasureHistoryUrl(component.key, metric.key, branch)}>
-                  <HistoryIcon />
-                </Link>
-              </Tooltip>
-            )}
-          </div>
-          <div className="measure-details-primary-actions">
-            {hasComponents && isFileType(component) && this.renderFileNav()}
-            {leakPeriod != null && (
-              <LeakPeriodLegend className="spacer-left" component={component} period={leakPeriod} />
-            )}
-          </div>
+        <div className="measure-details-primary-actions">
+          {leakPeriod != null && (
+            <LeakPeriodLegend className="spacer-left" component={component} period={leakPeriod} />
+          )}
         </div>
-        {secondaryMeasure &&
-        secondaryMeasure.metric.key === 'ncloc_language_distribution' && (
-          <div className="measure-details-secondary">
-            <LanguageDistributionContainer
-              alignTicks={true}
-              distribution={secondaryMeasure.value}
-              width={260}
-            />
-          </div>
-        )}
-        {secondaryMeasure &&
-        secondaryMeasure.metric.key === 'function_complexity_distribution' && (
-          <div className="measure-details-secondary">
-            <ComplexityDistribution distribution={secondaryMeasure.value} of="function" />
-          </div>
-        )}
-        {secondaryMeasure &&
-        secondaryMeasure.metric.key === 'file_complexity_distribution' && (
-          <div className="measure-details-secondary">
-            <ComplexityDistribution distribution={secondaryMeasure.value} of="file" />
-          </div>
-        )}
       </div>
-    );
-  }
+      {secondaryMeasure &&
+      secondaryMeasure.metric.key === 'ncloc_language_distribution' && (
+        <div className="measure-details-secondary">
+          <LanguageDistributionContainer
+            alignTicks={true}
+            distribution={secondaryMeasure.value}
+            width={260}
+          />
+        </div>
+      )}
+      {secondaryMeasure &&
+      secondaryMeasure.metric.key === 'function_complexity_distribution' && (
+        <div className="measure-details-secondary">
+          <ComplexityDistribution distribution={secondaryMeasure.value} of="function" />
+        </div>
+      )}
+      {secondaryMeasure &&
+      secondaryMeasure.metric.key === 'file_complexity_distribution' && (
+        <div className="measure-details-secondary">
+          <ComplexityDistribution distribution={secondaryMeasure.value} of="file" />
+        </div>
+      )}
+    </div>
+  );
 }
index eb76a1bd635121a1cce615b2b97a96ff25d65a35..2eb707899326f8facc9195a21ff8cfef843af477 100644 (file)
@@ -29,22 +29,27 @@ import { translate } from '../../../helpers/l10n';
   loading: boolean,
   isFile: ?boolean,
   paging: ?Paging,
+  totalLoadedComponents?: number,
   view?: string
 |}; */
 
 export default function PageActions(props /*: Props */) {
-  const { isFile, paging } = props;
+  const { isFile, paging, totalLoadedComponents } = props;
   const showShortcuts = ['list', 'tree'].includes(props.view);
   return (
     <div className="pull-right">
       {!isFile && showShortcuts && renderShortcuts()}
-      {isFile && renderFileShortcuts()}
+      {isFile && paging && renderFileShortcuts()}
       <div className="measure-details-page-actions">
         <DeferredSpinner loading={props.loading}>
           <i className="spinner-placeholder" />
         </DeferredSpinner>
         {paging != null && (
-          <FilesCounter className="spacer-left" current={props.current} total={paging.total} />
+          <FilesCounter
+            className="spacer-left"
+            current={props.current}
+            total={isFile && totalLoadedComponents != null ? totalLoadedComponents : paging.total}
+          />
         )}
       </div>
     </div>
@@ -73,8 +78,9 @@ function renderFileShortcuts() {
   return (
     <span className="note spacer-right">
       <span>
-        <span className="shortcut-button little-spacer-right">←</span>
-        {translate('component_measures.to_navigate_back')}
+        <span className="shortcut-button little-spacer-right">j</span>
+        <span className="shortcut-button little-spacer-right">k</span>
+        {translate('component_measures.to_navigate_files')}
       </span>
     </span>
   );
index 8164a6037177af9df9684f353875104a41bc1086..4f4e2020f6706d1bd2b82700bd91308750a3ad3b 100644 (file)
@@ -85,7 +85,7 @@ it('should display secondary measure too', () => {
   expect(wrapper.find('Connect(LanguageDistribution)')).toHaveLength(1);
 });
 
-it('shohuld display correctly for open file', () => {
+it('should display correctly for open file', () => {
   const wrapper = shallow(
     <MeasureHeader
       {...PROPS}
index a75ddac8ecbd5eb897ffea17869efcece3233048..1e0cf7083f10b6f6c7f932e097201e1b24f9ddc2 100644 (file)
@@ -22,15 +22,24 @@ import { shallow } from 'enzyme';
 import PageActions from '../PageActions';
 
 it('should display correctly for a project', () => {
-  expect(shallow(<PageActions loading={true} isFile={false} view="list" />)).toMatchSnapshot();
+  expect(
+    shallow(<PageActions loading={true} isFile={false} view="list" totalLoadedComponents={20} />)
+  ).toMatchSnapshot();
 });
 
 it('should display correctly for a file', () => {
-  expect(shallow(<PageActions loading={false} isFile={true} view="tree" />)).toMatchSnapshot();
+  const wrapper = shallow(
+    <PageActions loading={false} isFile={true} view="tree" totalLoadedComponents={10} />
+  );
+  expect(wrapper).toMatchSnapshot();
+  wrapper.setProps({ paging: { total: 100 } });
+  expect(wrapper).toMatchSnapshot();
 });
 
 it('should not display shortcuts for treemap', () => {
-  expect(shallow(<PageActions loading={true} isFile={false} view="treemap" />)).toMatchSnapshot();
+  expect(
+    shallow(<PageActions loading={true} isFile={false} view="treemap" totalLoadedComponents={20} />)
+  ).toMatchSnapshot();
 });
 
 it('should display the total of files', () => {
@@ -41,6 +50,19 @@ it('should display the total of files', () => {
         loading={true}
         isFile={false}
         view="treemap"
+        totalLoadedComponents={20}
+        paging={{ total: 120 }}
+      />
+    )
+  ).toMatchSnapshot();
+  expect(
+    shallow(
+      <PageActions
+        current={12}
+        loading={false}
+        isFile={true}
+        view="list"
+        totalLoadedComponents={20}
         paging={{ total: 120 }}
       />
     )
index 52e73da3bc312295949d25e34fab6c4cc41aa1b7..ec3b0d5395c5a18e2503ad5130711b0ea031435f 100644 (file)
@@ -1,32 +1,9 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`shohuld display correctly for open file 1`] = `
+exports[`should display correctly for open file 1`] = `
 <div
   className="measure-details-primary-actions"
 >
-  <div
-    className="display-inline-block"
-  >
-    <span
-      className="note spacer-right"
-    >
-      component_measures.x_of_y.2.3
-    </span>
-    <div
-      className="button-group"
-    >
-      <button
-        onClick={[Function]}
-      >
-        &lt;
-      </button>
-      <button
-        onClick={[Function]}
-      >
-        &gt;
-      </button>
-    </div>
-  </div>
   <LeakPeriodLegend
     className="spacer-left"
     component={
@@ -47,28 +24,10 @@ exports[`shohuld display correctly for open file 1`] = `
 </div>
 `;
 
-exports[`shohuld display correctly for open file 2`] = `
+exports[`should display correctly for open file 2`] = `
 <div
   className="measure-details-primary-actions"
 >
-  <div
-    className="display-inline-block"
-  >
-    <span
-      className="note spacer-right"
-    >
-      component_measures.x_of_y.2.2
-    </span>
-    <div
-      className="button-group"
-    >
-      <button
-        onClick={[Function]}
-      >
-        &lt;
-      </button>
-    </div>
-  </div>
   <LeakPeriodLegend
     className="spacer-left"
     component={
index da8e15fd76bd253dd9b1367732972b3ac1fbe6e1..c33278f92afb1c05edaa5b4f2e700d7ab15745f6 100644 (file)
@@ -1,6 +1,25 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`should display correctly for a file 1`] = `
+<div
+  className="pull-right"
+>
+  <div
+    className="measure-details-page-actions"
+  >
+    <DeferredSpinner
+      loading={false}
+      timeout={100}
+    >
+      <i
+        className="spinner-placeholder"
+      />
+    </DeferredSpinner>
+  </div>
+</div>
+`;
+
+exports[`should display correctly for a file 2`] = `
 <div
   className="pull-right"
 >
@@ -11,9 +30,14 @@ exports[`should display correctly for a file 1`] = `
       <span
         className="shortcut-button little-spacer-right"
       >
-        ←
+        j
+      </span>
+      <span
+        className="shortcut-button little-spacer-right"
+      >
+        k
       </span>
-      component_measures.to_navigate_back
+      component_measures.to_navigate_files
     </span>
   </span>
   <div
@@ -27,6 +51,10 @@ exports[`should display correctly for a file 1`] = `
         className="spinner-placeholder"
       />
     </DeferredSpinner>
+    <FilesCounter
+      className="spacer-left"
+      total={10}
+    />
   </div>
 </div>
 `;
@@ -106,6 +134,47 @@ exports[`should display the total of files 1`] = `
 </div>
 `;
 
+exports[`should display the total of files 2`] = `
+<div
+  className="pull-right"
+>
+  <span
+    className="note spacer-right"
+  >
+    <span>
+      <span
+        className="shortcut-button little-spacer-right"
+      >
+        j
+      </span>
+      <span
+        className="shortcut-button little-spacer-right"
+      >
+        k
+      </span>
+      component_measures.to_navigate_files
+    </span>
+  </span>
+  <div
+    className="measure-details-page-actions"
+  >
+    <DeferredSpinner
+      loading={false}
+      timeout={100}
+    >
+      <i
+        className="spinner-placeholder"
+      />
+    </DeferredSpinner>
+    <FilesCounter
+      className="spacer-left"
+      current={12}
+      total={20}
+    />
+  </div>
+</div>
+`;
+
 exports[`should not display shortcuts for treemap 1`] = `
 <div
   className="pull-right"
diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/CodeView.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/CodeView.js
new file mode 100644 (file)
index 0000000..8fcc29c
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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 key from 'keymaster';
+import SourceViewer from '../../../components/SourceViewer/SourceViewer';
+import { isDiffMetric } from '../../../helpers/measures';
+import { parseDate } from '../../../helpers/dates';
+/*:: import type { ComponentEnhanced, Paging, Period } from '../types'; */
+/*:: import type { Metric } from '../../../store/metrics/actions'; */
+
+/*:: type Props = {|
+  branch?: string,
+  component: ComponentEnhanced,
+  components: Array<ComponentEnhanced>,
+  leakPeriod?: Period,
+  metric: Metric,
+  selectedIdx: ?number,
+  updateSelected: string => void,
+|}; */
+
+export default class CodeView extends React.PureComponent {
+  /*:: props: Props; */
+
+  componentDidMount() {
+    this.attachShortcuts();
+  }
+
+  componentWillUnmount() {
+    this.detachShortcuts();
+  }
+
+  attachShortcuts() {
+    key('j', 'measures-files', () => {
+      this.selectNext();
+      return false;
+    });
+    key('k', 'measures-files', () => {
+      this.selectPrevious();
+      return false;
+    });
+  }
+
+  detachShortcuts() {
+    ['j', 'k'].map(action => key.unbind(action, 'measures-files'));
+  }
+
+  selectPrevious = () => {
+    const { selectedIdx } = this.props;
+    if (selectedIdx != null && selectedIdx > 0) {
+      const prevComponent = this.props.components[selectedIdx - 1];
+      if (prevComponent) {
+        this.props.updateSelected(prevComponent.key);
+      }
+    }
+  };
+
+  selectNext = () => {
+    const { components, selectedIdx } = this.props;
+    if (selectedIdx != null && selectedIdx < components.length - 1) {
+      const nextComponent = components[selectedIdx + 1];
+      if (nextComponent) {
+        this.props.updateSelected(nextComponent.key);
+      }
+    }
+  };
+
+  render() {
+    const { branch, component, leakPeriod } = this.props;
+    const leakPeriodDate =
+      isDiffMetric(this.props.metric.key) && leakPeriod != null ? parseDate(leakPeriod.date) : null;
+
+    let filterLine;
+    if (leakPeriodDate != null) {
+      filterLine = line => {
+        if (line.scmDate) {
+          const scmDate = parseDate(line.scmDate);
+          return scmDate >= leakPeriodDate;
+        } else {
+          return false;
+        }
+      };
+    }
+    return <SourceViewer branch={branch} component={component.key} filterLine={filterLine} />;
+  }
+}
index e13ec374232f5bd7b214171a79b3ff136ab9d16f..1d7be5e5b3b73fb664429d18ed15c08fa0f80f3f 100644 (file)
@@ -52,18 +52,14 @@ export default class ListView extends React.PureComponent {
 
   componentDidMount() {
     this.attachShortcuts();
+    if (this.props.selectedKey != null) {
+      this.scrollToElement();
+    }
   }
 
   componentDidUpdate(prevProps /*: Props */) {
-    if (
-      this.listContainer &&
-      this.props.selectedKey != null &&
-      prevProps.selectedKey !== this.props.selectedKey
-    ) {
-      const elem = this.listContainer.getElementsByClassName('selected')[0];
-      if (elem) {
-        scrollToElement(elem, { topOffset: 215, bottomOffset: 100 });
-      }
+    if (this.props.selectedKey != null && prevProps.selectedKey !== this.props.selectedKey) {
+      this.scrollToElement();
     }
   }
 
@@ -114,6 +110,15 @@ export default class ListView extends React.PureComponent {
     }
   };
 
+  scrollToElement = () => {
+    if (this.listContainer) {
+      const elem = this.listContainer.getElementsByClassName('selected')[0];
+      if (elem) {
+        scrollToElement(elem, { topOffset: 215, bottomOffset: 100 });
+      }
+    }
+  };
+
   render() {
     return (
       <div ref={elem => (this.listContainer = elem)}>
index ec8038ea2ecc7a4d912217b9573454c7ec8eb242..4ac106215fe768b5242c5446ca86837ad2941f9d 100644 (file)
@@ -2965,7 +2965,7 @@ component_measures.no_history=There is no historical data.
 component_measures.not_found=The requested measure was not found.
 component_measures.to_select_files=to select files
 component_measures.to_navigate=to navigate
-component_measures.to_navigate_back=to navigate back
+component_measures.to_navigate_files=to next/previous file
 
 component_measures.overview.project_overview.facet=Project Overview
 component_measures.overview.project_overview.title=Risk