]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9245 Update sorting select for leak in projects page
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Wed, 7 Jun 2017 06:52:06 +0000 (08:52 +0200)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Fri, 9 Jun 2017 06:26:48 +0000 (08:26 +0200)
server/sonar-web/src/main/js/apps/projects/components/AllProjects.js
server/sonar-web/src/main/js/apps/projects/components/ProjectsOptionBar.js
server/sonar-web/src/main/js/apps/projects/components/ProjectsSortingSelect.js
server/sonar-web/src/main/js/apps/projects/components/ProjectsSortingSelectOption.js
server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectOptionBar-test.js
server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsSortingSelect-test.js
server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectOptionBar-test.js.snap
server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectsSortingSelect-test.js.snap
server/sonar-web/src/main/js/apps/projects/styles.css
server/sonar-web/src/main/js/apps/projects/utils.js
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 3adb8c5e0e83ef89c5ff5e7056b48cfc2bb25753..dd440f839273ec3ff4f8c0769ac31a87fcbe4374 100644 (file)
@@ -38,7 +38,8 @@ type Props = {
   optionBarOpen: boolean,
   optionBarToggle: (open: boolean) => void,
   organization?: { key: string },
-  router: { push: ({ pathname: string, query?: {} }) => void }
+  router: { push: ({ pathname: string, query?: {} }) => void },
+  user?: { isLoggedIn: boolean }
 };
 
 type State = {
@@ -132,6 +133,7 @@ export default class AllProjects extends React.PureComponent {
           onToggleOptionBar={this.props.optionBarToggle}
           open={optionBarOpen}
           selectedSort={selectedSort}
+          user={this.props.user}
           view={view}
           visualization={visualization}
         />
index ada472b4beb887ac4581f75efb6a5ebbe4293b84..b076abcb98dbc126db2ec990f9d969939db745ef 100644 (file)
@@ -33,6 +33,7 @@ type Props = {
   projects: Array<*>,
   projectsAppState: { loading: boolean, total?: number },
   selectedSort: string,
+  user?: { isLoggedIn: boolean },
   view: string,
   visualization?: string
 };
@@ -47,18 +48,19 @@ export default class ProjectsOptionBar extends React.PureComponent {
   };
 
   renderSortingSelect() {
-    const { projectsAppState, projects, view } = this.props;
+    const { projectsAppState, projects, user, view } = this.props;
     const limitReached =
       projects != null &&
       projectsAppState.total != null &&
       projects.length < projectsAppState.total;
-
+    const defaultOption = user && user.isLoggedIn ? 'name' : 'analysis_date';
     if (view === 'visualizations' && !limitReached) {
       return (
         <Tooltip overlay={translate('projects.sort.disabled')}>
           <div>
             <ProjectsSortingSelect
               className="projects-topbar-item js-projects-sorting-select disabled"
+              defaultOption={defaultOption}
               onChange={this.props.onSortChange}
               selectedSort={this.props.selectedSort}
               view={this.props.view}
@@ -70,6 +72,7 @@ export default class ProjectsOptionBar extends React.PureComponent {
     return (
       <ProjectsSortingSelect
         className="projects-topbar-item js-projects-sorting-select"
+        defaultOption={defaultOption}
         onChange={this.props.onSortChange}
         selectedSort={this.props.selectedSort}
         view={this.props.view}
index 4a5556bd91d66daebf33cea1388a3f7f6c35c9c3..51d6f1fdd5e8282a9c9e1ae8fae9523239e880c0 100644 (file)
@@ -19,6 +19,7 @@
  */
 // @flow
 import React from 'react';
+import { sortBy } from 'lodash';
 import Select from 'react-select';
 import ProjectsSortingSelectOption from './ProjectsSortingSelectOption';
 import SortAscIcon from '../../../components/icons-components/SortAscIcon';
@@ -27,13 +28,14 @@ import Tooltip from '../../../components/controls/Tooltip';
 import { translate } from '../../../helpers/l10n';
 import { SORTING_METRICS, SORTING_LEAK_METRICS, parseSorting } from '../utils';
 
-export type Option = { label: string, value: string, complement?: string, short?: string };
+export type Option = { label: string, value: string, class?: string, short?: string };
 
 type Props = {
   className?: string,
   onChange: (sort: string, desc: boolean) => void,
   selectedSort: string,
-  view: string
+  view: string,
+  defaultOption: string
 };
 
 type State = {
@@ -58,11 +60,16 @@ export default class ProjectsSortingSelect extends React.PureComponent {
 
   getOptions = () => {
     const sortMetrics = this.props.view === 'leak' ? SORTING_LEAK_METRICS : SORTING_METRICS;
-    return sortMetrics.map((opt: { value: string, complement?: string }) => ({
+    return sortBy(
+      sortMetrics,
+      opt => (opt.value === this.props.defaultOption ? 0 : 1)
+    ).map((opt: { value: string, class?: string }) => ({
       value: opt.value,
-      label: translate('projects.sorting', opt.value),
-      complement: opt.complement && translate('projects.sorting', opt.complement),
-      short: opt.complement && translate('projects.sorting', opt.value, 'short')
+      label: translate('projects.sorting', opt.value) +
+        (opt.value === this.props.defaultOption
+          ? ` (${translate('projects.sorting.default')})`
+          : ''),
+      class: opt.class
     }));
   };
 
@@ -84,8 +91,8 @@ export default class ProjectsSortingSelect extends React.PureComponent {
           className="little-spacer-left input-large"
           clearable={false}
           onChange={this.handleSortChange}
-          options={this.getOptions()}
           optionComponent={ProjectsSortingSelectOption}
+          options={this.getOptions()}
           searchable={false}
           value={this.state.sortValue}
         />
index f3613f1153e8a31eb8339d2efbca9c263eb9b4ff..9789a3d30fbd5c179fda84e1e5b3dd12356595bb 100644 (file)
@@ -19,6 +19,7 @@
  */
 //@flow
 import React from 'react';
+import classNames from 'classnames';
 import type { Option } from './ProjectsSortingSelect';
 
 type Props = {
@@ -54,16 +55,12 @@ export default class ProjectsSortingSelectOption extends React.PureComponent {
     const { option } = this.props;
     return (
       <div
-        className={this.props.className}
+        className={classNames(this.props.className, option.class)}
         onMouseDown={this.handleMouseDown}
         onMouseEnter={this.handleMouseEnter}
         onMouseMove={this.handleMouseMove}
         title={option.label}>
         {option.short ? option.short : this.props.children}
-        {option.complement &&
-          <div className="pull-right text-muted-2">
-            {option.complement}
-          </div>}
       </div>
     );
   }
index 446bf98b57aa2f5121f9c0c1948d2c8fb6902e8e..14d16176c639e0fe7d5d418f46b3ad30cd707c27 100644 (file)
@@ -35,6 +35,7 @@ it('should render option bar open', () => {
         visualization="risk"
         projects={[1, 2, 3]}
         projectsAppState={{ total: 3 }}
+        user={{ isLoggedIn: true }}
       />
     )
   ).toMatchSnapshot();
@@ -52,3 +53,26 @@ it('should call close method correctly', () => {
   click(wrapper.find('.projects-topbar-button'));
   expect(toggle.mock.calls).toMatchSnapshot();
 });
+
+it('should render switch the default sorting option for anonymous users', () => {
+  expect(
+    shallow(
+      <ProjectsOptionBar
+        open={true}
+        view="overall"
+        visualization="risk"
+        user={{ isLoggedIn: true }}
+      />
+    ).find('ProjectsSortingSelect')
+  ).toMatchSnapshot();
+  expect(
+    shallow(
+      <ProjectsOptionBar
+        open={true}
+        view="leak"
+        visualization="risk"
+        user={{ isLoggedIn: false }}
+      />
+    ).find('ProjectsSortingSelect')
+  ).toMatchSnapshot();
+});
index 472558d00850afafe5684d34cfd7f9cb672564e5..4906bf180b2c437a194bb908320bc7f8bcbe7d05 100644 (file)
@@ -22,17 +22,27 @@ import { shallow } from 'enzyme';
 import ProjectsSortingSelect from '../ProjectsSortingSelect';
 
 it('should render correctly for overall view', () => {
-  expect(shallow(<ProjectsSortingSelect selectedSort="name" view="overall" />)).toMatchSnapshot();
+  expect(
+    shallow(<ProjectsSortingSelect selectedSort="name" view="overall" defaultOption="name" />)
+  ).toMatchSnapshot();
 });
 
 it('should render correctly for leak view', () => {
   expect(
-    shallow(<ProjectsSortingSelect selectedSort="new_coverage" view="leak" />)
+    shallow(
+      <ProjectsSortingSelect
+        selectedSort="new_coverage"
+        view="leak"
+        defaultOption="analysis_date"
+      />
+    )
   ).toMatchSnapshot();
 });
 
 it('should handle the descending sort direction', () => {
   expect(
-    shallow(<ProjectsSortingSelect selectedSort="-vulnerability" view="overall" />)
+    shallow(
+      <ProjectsSortingSelect selectedSort="-vulnerability" view="overall" defaultOption="name" />
+    )
   ).toMatchSnapshot();
 });
index 12099c9db00645ba3617ef3f9e05939f3e01b303..15051129d68d09b763d772ff5a4df5b89cea7a8b 100644 (file)
@@ -39,6 +39,7 @@ exports[`should render disabled sorting options for visualizations 1`] = `
           <div>
             <ProjectsSortingSelect
               className="projects-topbar-item js-projects-sorting-select disabled"
+              defaultOption="analysis_date"
               view="visualizations"
             />
           </div>
@@ -74,6 +75,7 @@ exports[`should render option bar closed 1`] = `
         />
         <ProjectsSortingSelect
           className="projects-topbar-item js-projects-sorting-select"
+          defaultOption="analysis_date"
           view="overall"
         />
       </div>
@@ -108,6 +110,7 @@ exports[`should render option bar open 1`] = `
         />
         <ProjectsSortingSelect
           className="projects-topbar-item js-projects-sorting-select"
+          defaultOption="name"
           view="leak"
         />
       </div>
@@ -115,3 +118,19 @@ exports[`should render option bar open 1`] = `
   </div>
 </div>
 `;
+
+exports[`should render switch the default sorting option for anonymous users 1`] = `
+<ProjectsSortingSelect
+  className="projects-topbar-item js-projects-sorting-select"
+  defaultOption="name"
+  view="overall"
+/>
+`;
+
+exports[`should render switch the default sorting option for anonymous users 2`] = `
+<ProjectsSortingSelect
+  className="projects-topbar-item js-projects-sorting-select"
+  defaultOption="analysis_date"
+  view="leak"
+/>
+`;
index c5ef95acbd7d8a5928d45c35d8c7df42935ea389..7a004599bfb717e45a80995852d0183b0e625510 100644 (file)
@@ -40,51 +40,43 @@ exports[`should handle the descending sort direction 1`] = `
     options={
       Array [
         Object {
-          "complement": undefined,
-          "label": "projects.sorting.name",
-          "short": undefined,
+          "class": undefined,
+          "label": "projects.sorting.name (projects.sorting.default)",
           "value": "name",
         },
         Object {
-          "complement": undefined,
+          "class": undefined,
           "label": "projects.sorting.analysis_date",
-          "short": undefined,
           "value": "analysis_date",
         },
         Object {
-          "complement": undefined,
+          "class": undefined,
           "label": "projects.sorting.reliability",
-          "short": undefined,
           "value": "reliability",
         },
         Object {
-          "complement": undefined,
+          "class": undefined,
           "label": "projects.sorting.security",
-          "short": undefined,
           "value": "security",
         },
         Object {
-          "complement": undefined,
+          "class": undefined,
           "label": "projects.sorting.maintainability",
-          "short": undefined,
           "value": "maintainability",
         },
         Object {
-          "complement": undefined,
+          "class": undefined,
           "label": "projects.sorting.coverage",
-          "short": undefined,
           "value": "coverage",
         },
         Object {
-          "complement": undefined,
+          "class": undefined,
           "label": "projects.sorting.duplications",
-          "short": undefined,
           "value": "duplications",
         },
         Object {
-          "complement": undefined,
+          "class": undefined,
           "label": "projects.sorting.size",
-          "short": undefined,
           "value": "size",
         },
       ]
@@ -157,51 +149,43 @@ exports[`should render correctly for leak view 1`] = `
     options={
       Array [
         Object {
-          "complement": undefined,
-          "label": "projects.sorting.name",
-          "short": undefined,
-          "value": "name",
+          "class": undefined,
+          "label": "projects.sorting.analysis_date (projects.sorting.default)",
+          "value": "analysis_date",
         },
         Object {
-          "complement": undefined,
-          "label": "projects.sorting.analysis_date",
-          "short": undefined,
-          "value": "analysis_date",
+          "class": undefined,
+          "label": "projects.sorting.name",
+          "value": "name",
         },
         Object {
-          "complement": "projects.sorting.on_new_code",
+          "class": "projects-leak-sorting-option",
           "label": "projects.sorting.new_reliability",
-          "short": "projects.sorting.new_reliability.short",
           "value": "new_reliability",
         },
         Object {
-          "complement": "projects.sorting.on_new_code",
+          "class": "projects-leak-sorting-option",
           "label": "projects.sorting.new_security",
-          "short": "projects.sorting.new_security.short",
           "value": "new_security",
         },
         Object {
-          "complement": "projects.sorting.on_new_code",
+          "class": "projects-leak-sorting-option",
           "label": "projects.sorting.new_maintainability",
-          "short": "projects.sorting.new_maintainability.short",
           "value": "new_maintainability",
         },
         Object {
-          "complement": "projects.sorting.on_new_code",
+          "class": "projects-leak-sorting-option",
           "label": "projects.sorting.new_coverage",
-          "short": "projects.sorting.new_coverage.short",
           "value": "new_coverage",
         },
         Object {
-          "complement": "projects.sorting.on_new_lines",
+          "class": "projects-leak-sorting-option",
           "label": "projects.sorting.new_duplications",
-          "short": "projects.sorting.new_duplications.short",
           "value": "new_duplications",
         },
         Object {
-          "complement": undefined,
+          "class": "projects-leak-sorting-option",
           "label": "projects.sorting.new_lines",
-          "short": undefined,
           "value": "new_lines",
         },
       ]
@@ -274,51 +258,43 @@ exports[`should render correctly for overall view 1`] = `
     options={
       Array [
         Object {
-          "complement": undefined,
-          "label": "projects.sorting.name",
-          "short": undefined,
+          "class": undefined,
+          "label": "projects.sorting.name (projects.sorting.default)",
           "value": "name",
         },
         Object {
-          "complement": undefined,
+          "class": undefined,
           "label": "projects.sorting.analysis_date",
-          "short": undefined,
           "value": "analysis_date",
         },
         Object {
-          "complement": undefined,
+          "class": undefined,
           "label": "projects.sorting.reliability",
-          "short": undefined,
           "value": "reliability",
         },
         Object {
-          "complement": undefined,
+          "class": undefined,
           "label": "projects.sorting.security",
-          "short": undefined,
           "value": "security",
         },
         Object {
-          "complement": undefined,
+          "class": undefined,
           "label": "projects.sorting.maintainability",
-          "short": undefined,
           "value": "maintainability",
         },
         Object {
-          "complement": undefined,
+          "class": undefined,
           "label": "projects.sorting.coverage",
-          "short": undefined,
           "value": "coverage",
         },
         Object {
-          "complement": undefined,
+          "class": undefined,
           "label": "projects.sorting.duplications",
-          "short": undefined,
           "value": "duplications",
         },
         Object {
-          "complement": undefined,
+          "class": undefined,
           "label": "projects.sorting.size",
-          "short": undefined,
           "value": "size",
         },
       ]
index aeffc580da6fddfae0248373df05fa26026318b7..f9b1b627502ca7dc0b8132cdd86feb6ca5c83666 100644 (file)
   border: 1px solid #eae3c7;
 }
 
+.projects-leak-sorting-option {
+  background-color: #fbf3d5;
+  margin-bottom: 2px;
+}
+
+.projects-leak-sorting-option.is-focused {
+  background-color: #eae3c7;
+}
 
 .project-card-measures .project-card-measure {
   width: 120px;
index 85d898e64a09af72a81c0d0884015509999ec95b..008bdf5cb6ae3fdde438afb4c4cc3f0e547d240f 100644 (file)
@@ -61,12 +61,12 @@ export const SORTING_METRICS = [
 export const SORTING_LEAK_METRICS = [
   { value: 'name' },
   { value: 'analysis_date' },
-  { value: 'new_reliability', complement: 'on_new_code' },
-  { value: 'new_security', complement: 'on_new_code' },
-  { value: 'new_maintainability', complement: 'on_new_code' },
-  { value: 'new_coverage', complement: 'on_new_code' },
-  { value: 'new_duplications', complement: 'on_new_lines' },
-  { value: 'new_lines' }
+  { value: 'new_reliability', class: 'projects-leak-sorting-option' },
+  { value: 'new_security', class: 'projects-leak-sorting-option' },
+  { value: 'new_maintainability', class: 'projects-leak-sorting-option' },
+  { value: 'new_coverage', class: 'projects-leak-sorting-option' },
+  { value: 'new_duplications', class: 'projects-leak-sorting-option' },
+  { value: 'new_lines', class: 'projects-leak-sorting-option' }
 ];
 
 export const SORTING_SWITCH = {
index 0538087e63808f6b64ba3d8164ee0b9368b69b55..8b342021a24601b99ca3258f3d7f4858ba747322 100644 (file)
@@ -869,7 +869,8 @@ projects.perspective=Perspective
 projects.sort_by=Sort by
 projects.sort_ascending=Result sorted in ascending order
 projects.sort_descending=Result sorted in descending order
-projects.sorting.name=Name (default)
+projects.sorting.default=default
+projects.sorting.name=Name
 projects.sorting.analysis_date=Last analysis date
 projects.sorting.reliability=Reliability
 projects.sorting.security=Security
@@ -877,16 +878,11 @@ projects.sorting.maintainability=Maintainability
 projects.sorting.coverage=Coverage
 projects.sorting.duplications=Duplications
 projects.sorting.size=Size
-projects.sorting.new_reliability=Reliability on New Code
-projects.sorting.new_security=Security on New Code
-projects.sorting.new_maintainability=Maintainability on New Code
-projects.sorting.new_coverage=Coverage on New Code
-projects.sorting.new_duplications=Duplications on New Lines
-projects.sorting.new_reliability.short=Reliability
-projects.sorting.new_security.short=Security
-projects.sorting.new_maintainability.short=Maintainability
-projects.sorting.new_coverage.short=Coverage
-projects.sorting.new_duplications.short=Duplications
+projects.sorting.new_reliability=Reliability
+projects.sorting.new_security=Security
+projects.sorting.new_maintainability=Maintainability
+projects.sorting.new_coverage=Coverage
+projects.sorting.new_duplications=Duplications
 projects.sorting.new_lines=New Lines
 projects.sorting.on_new_code=on New Code
 projects.sorting.on_new_lines=on New Lines