]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-11668 Jump to measures list view from dashboard
authorJeremy Davis <jeremy.davis@sonarsource.com>
Wed, 13 Mar 2019 16:26:07 +0000 (17:26 +0100)
committerSonarTech <sonartech@sonarsource.com>
Mon, 18 Mar 2019 19:20:58 +0000 (20:20 +0100)
server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.tsx
server/sonar-web/src/main/js/apps/component-measures/components/MeasureViewSelect.tsx
server/sonar-web/src/main/js/apps/component-measures/style.css
server/sonar-web/src/main/js/components/shared/DrilldownLink.tsx
server/sonar-web/src/main/js/components/shared/__tests__/DrilldownLink-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/DrilldownLink-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/urls.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 7b3f6325b36a66be37e18a91a3217e2fdf3d072e..55d400e4ec375c2f8cf4728489f0a1ca1a9e8f52 100644 (file)
@@ -35,6 +35,7 @@ import { isDiffMetric, getPeriodValue } from '../../../helpers/measures';
 import { RequestData } from '../../../helpers/request';
 import { getProjectUrl } from '../../../helpers/urls';
 import { getMeasures } from '../../../api/measures';
+import { translate } from '../../../helpers/l10n';
 
 interface Props {
   branchLike?: T.BranchLike;
@@ -335,8 +336,9 @@ export default class MeasureContent extends React.PureComponent<Props, State> {
                     {!isFile &&
                       metric && (
                         <>
+                          <div>{translate('component_measures.view_as')}</div>
                           <MeasureViewSelect
-                            className="measure-view-select big-spacer-right"
+                            className="measure-view-select spacer-left big-spacer-right"
                             handleViewChange={this.updateView}
                             metric={metric}
                             view={view}
index 236c1217645b13572ed5a6249d38d31b019c34b1..31ec863137ff354f8b9c210a6015670855f78834 100644 (file)
@@ -73,10 +73,6 @@ export default class MeasureViewSelect extends React.PureComponent<Props> {
     );
   };
 
-  renderValue = (value: { icon: JSX.Element }) => {
-    return value.icon;
-  };
-
   render() {
     return (
       <Select
@@ -88,7 +84,7 @@ export default class MeasureViewSelect extends React.PureComponent<Props> {
         options={this.getOptions()}
         searchable={false}
         value={this.props.view}
-        valueRenderer={this.renderValue}
+        valueRenderer={this.renderOption}
       />
     );
   }
index c09c06c3d1a22a6d5d3354be8cbd2afb069b1ff8..a7eaa81ac1a188626f7245e279b5a1dc37798597 100644 (file)
 }
 
 .measure-view-select {
-  width: 50px;
+  width: 102px;
 }
 
 .measure-view-select .Select-menu-outer {
index 019a32e601c4af0f180e9077fdd37c1a0c3fe1db..0d69d1afa7cfd62536de19a93eab3c17d601d171 100644 (file)
@@ -47,6 +47,29 @@ const ISSUE_MEASURES = [
   'new_vulnerabilities'
 ];
 
+const issueParamsPerMetric: { [key: string]: { [key: string]: string } } = {
+  blocker_violations: { resolved: 'false', severities: 'BLOCKER' },
+  new_blocker_violations: { resolved: 'false', severities: 'BLOCKER' },
+  critical_violations: { resolved: 'false', severities: 'CRITICAL' },
+  new_critical_violations: { resolved: 'false', severities: 'CRITICAL' },
+  major_violations: { resolved: 'false', severities: 'MAJOR' },
+  new_major_violations: { resolved: 'false', severities: 'MAJOR' },
+  minor_violations: { resolved: 'false', severities: 'MINOR' },
+  new_minor_violations: { resolved: 'false', severities: 'MINOR' },
+  info_violations: { resolved: 'false', severities: 'INFO' },
+  new_info_violations: { resolved: 'false', severities: 'INFO' },
+  open_issues: { resolved: 'false', statuses: 'OPEN' },
+  reopened_issues: { resolved: 'false', statuses: 'REOPENED' },
+  confirmed_issues: { resolved: 'false', statuses: 'CONFIRMED' },
+  false_positive_issues: { resolutions: 'FALSE-POSITIVE' },
+  code_smells: { resolved: 'false', types: 'CODE_SMELL' },
+  new_code_smells: { resolved: 'false', types: 'CODE_SMELL' },
+  bugs: { resolved: 'false', types: 'BUG' },
+  new_bugs: { resolved: 'false', types: 'BUG' },
+  vulnerabilities: { resolved: 'false', types: 'VULNERABILITY' },
+  new_vulnerabilities: { resolved: 'false', types: 'VULNERABILITY' }
+};
+
 interface Props {
   branchLike?: T.BranchLike;
   children?: React.ReactNode;
@@ -62,60 +85,14 @@ export default class DrilldownLink extends React.PureComponent<Props> {
   };
 
   propsToIssueParams = () => {
-    const params: { [key: string]: string | boolean } = {};
+    const params: { [key: string]: string | boolean } = {
+      ...(issueParamsPerMetric[this.props.metric] || { resolved: 'false' })
+    };
 
     if (this.props.sinceLeakPeriod) {
       params.sinceLeakPeriod = true;
     }
 
-    switch (this.props.metric) {
-      case 'blocker_violations':
-      case 'new_blocker_violations':
-        Object.assign(params, { resolved: 'false', severities: 'BLOCKER' });
-        break;
-      case 'critical_violations':
-      case 'new_critical_violations':
-        Object.assign(params, { resolved: 'false', severities: 'CRITICAL' });
-        break;
-      case 'major_violations':
-      case 'new_major_violations':
-        Object.assign(params, { resolved: 'false', severities: 'MAJOR' });
-        break;
-      case 'minor_violations':
-      case 'new_minor_violations':
-        Object.assign(params, { resolved: 'false', severities: 'MINOR' });
-        break;
-      case 'info_violations':
-      case 'new_info_violations':
-        Object.assign(params, { resolved: 'false', severities: 'INFO' });
-        break;
-      case 'open_issues':
-        Object.assign(params, { resolved: 'false', statuses: 'OPEN' });
-        break;
-      case 'reopened_issues':
-        Object.assign(params, { resolved: 'false', statuses: 'REOPENED' });
-        break;
-      case 'confirmed_issues':
-        Object.assign(params, { resolved: 'false', statuses: 'CONFIRMED' });
-        break;
-      case 'false_positive_issues':
-        Object.assign(params, { resolutions: 'FALSE-POSITIVE' });
-        break;
-      case 'code_smells':
-      case 'new_code_smells':
-        Object.assign(params, { resolved: 'false', types: 'CODE_SMELL' });
-        break;
-      case 'bugs':
-      case 'new_bugs':
-        Object.assign(params, { resolved: 'false', types: 'BUG' });
-        break;
-      case 'vulnerabilities':
-      case 'new_vulnerabilities':
-        Object.assign(params, { resolved: 'false', types: 'VULNERABILITY' });
-        break;
-      default:
-        Object.assign(params, { resolved: 'false' });
-    }
     return params;
   };
 
@@ -140,7 +117,8 @@ export default class DrilldownLink extends React.PureComponent<Props> {
     const url = getComponentDrilldownUrl({
       componentKey: this.props.component,
       metric: this.props.metric,
-      branchLike: this.props.branchLike
+      branchLike: this.props.branchLike,
+      listView: true
     });
     return (
       <Link className={this.props.className} to={url}>
diff --git a/server/sonar-web/src/main/js/components/shared/__tests__/DrilldownLink-test.tsx b/server/sonar-web/src/main/js/components/shared/__tests__/DrilldownLink-test.tsx
new file mode 100644 (file)
index 0000000..7cea95b
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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 * as React from 'react';
+import { shallow } from 'enzyme';
+import DrilldownLink from '../DrilldownLink';
+
+it('should render correctly', () => {
+  const wrapper = shallowRender();
+  expect(wrapper).toMatchSnapshot();
+});
+it('should render issuesLink correctly', () => {
+  const wrapper = shallowRender({ metric: 'new_violations' });
+  expect(wrapper).toMatchSnapshot();
+});
+
+describe('propsToIssueParams', () => {
+  it('should render correct default parameters', () => {
+    const wrapper = shallowRender();
+    expect(wrapper.instance().propsToIssueParams()).toEqual({ resolved: 'false' });
+  });
+
+  it(`should render correct params`, () => {
+    const wrapper = shallowRender({ metric: 'false_positive_issues', sinceLeakPeriod: true });
+    expect(wrapper.instance().propsToIssueParams()).toEqual({
+      resolutions: 'FALSE-POSITIVE',
+      sinceLeakPeriod: true
+    });
+  });
+});
+
+const shallowRender = (props: Partial<DrilldownLink['props']> = {}, label = 'label') => {
+  return shallow<DrilldownLink>(
+    <DrilldownLink component="project123" metric="other" {...props}>
+      {label}
+    </DrilldownLink>
+  );
+};
diff --git a/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/DrilldownLink-test.tsx.snap b/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/DrilldownLink-test.tsx.snap
new file mode 100644 (file)
index 0000000..43494b4
--- /dev/null
@@ -0,0 +1,38 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<Link
+  onlyActiveOnIndex={false}
+  style={Object {}}
+  to={
+    Object {
+      "pathname": "/component_measures",
+      "query": Object {
+        "id": "project123",
+        "metric": "other",
+        "view": "list",
+      },
+    }
+  }
+>
+  label
+</Link>
+`;
+
+exports[`should render issuesLink correctly 1`] = `
+<Link
+  onlyActiveOnIndex={false}
+  style={Object {}}
+  to={
+    Object {
+      "pathname": "/project/issues",
+      "query": Object {
+        "id": "project123",
+        "resolved": "false",
+      },
+    }
+  }
+>
+  label
+</Link>
+`;
index 72db686a0c9017e4fdac9c4da35a455d945d4f97..8b9f7a35a0c515590840e9ffc0513cf36c02cf1a 100644 (file)
@@ -114,12 +114,16 @@ export function getComponentDrilldownUrl(options: {
   branchLike?: T.BranchLike;
   selectionKey?: string;
   treemapView?: boolean;
+  listView?: boolean;
 }): Location {
-  const { componentKey, metric, branchLike, selectionKey, treemapView } = options;
+  const { componentKey, metric, branchLike, selectionKey, treemapView, listView } = options;
   const query: Query = { id: componentKey, metric, ...getBranchLikeQuery(branchLike) };
   if (treemapView) {
     query.view = 'treemap';
   }
+  if (listView) {
+    query.view = 'list';
+  }
   if (selectionKey) {
     query.selected = selectionKey;
   }
index 6759d6c8aff0977d2423374dd2102ffb66868805..e094ae316879e95b7b399081be5dcb98598fa980 100644 (file)
@@ -2576,6 +2576,7 @@ component_measures.show_metric_history=Show history of this metric
 component_measures.tab.tree=Tree
 component_measures.tab.list=List
 component_measures.tab.treemap=Treemap
+component_measures.view_as=View as
 component_measures.legend.color_x=Color: {0}
 component_measures.legend.size_x=Size: {0}
 component_measures.legend.worse_of_x_y=Worse of {0} and {1}
@@ -2655,7 +2656,7 @@ organization.avatar=Avatar
 organization.avatar.description=Url of a small image that represents the organization (preferably 30px height).
 organization.avatar.preview=Preview
 organization.bind_to_x=Bind this organization to {0}
-organization.go_to_settings_to_bind=Go to Organization Settings to bind it.
+organization.go_to_settings_to_bind=Go to Organization Settings to bind it
 organization.bound=This organization is bound.
 organization.bound_to_x=This organization is bound to {0}
 organization.not_bound_to_x=This organization is not bound to {0}