]> source.dussan.org Git - sonarqube.git/commitdiff
apply feedback for the quality profiles page
authorStas Vilchik <vilchiks@gmail.com>
Wed, 29 Jun 2016 15:15:49 +0000 (17:15 +0200)
committerStas Vilchik <vilchiks@gmail.com>
Thu, 30 Jun 2016 07:47:50 +0000 (09:47 +0200)
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileHeader.js
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileProjects.js
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.js
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesRow.js
server/sonar-web/src/main/js/apps/quality-profiles/details/ProgressBar.js [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesList.js
server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListHeader.js
server/sonar-web/src/main/js/apps/quality-profiles/styles.css
server/sonar-web/src/main/less/init/links.less
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 1062f4cca72251baee2982f10b209876fc2e77dc..62706071207f685f0876f5395ea46e7a814e2cc1 100644 (file)
@@ -26,6 +26,7 @@ import DeleteProfileView from '../views/DeleteProfileView';
 import { ProfileType } from '../propTypes';
 import { translate } from '../../../helpers/l10n';
 import { setDefaultProfile } from '../../../api/quality-profiles';
+import { getRulesUrl } from '../../../helpers/urls';
 
 export default class ProfileHeader extends React.Component {
   static propTypes = {
@@ -84,7 +85,10 @@ export default class ProfileHeader extends React.Component {
         '/api/qualityprofiles/backup?profileKey=' +
         encodeURIComponent(profile.key);
 
-    // TODO fix inline styles
+    const activateMoreUrl = getRulesUrl({
+      qprofile: this.props.profile.key,
+      activation: 'false'
+    });
 
     return (
         <header className="page-header quality-profile-header">
@@ -92,6 +96,12 @@ export default class ProfileHeader extends React.Component {
             <IndexLink to="/" className="text-muted">
               {translate('quality_profiles.page')}
             </IndexLink>
+            {' / '}
+            <Link
+                to={{ pathname: '/', query: { language: profile.language } }}
+                className="text-muted">
+              {profile.languageName}
+            </Link>
           </div>
 
           <h1 className="page-title">
@@ -100,9 +110,6 @@ export default class ProfileHeader extends React.Component {
                 className="link-base-color">
               {profile.name}
             </ProfileLink>
-            <span className="spacer-left small text-muted">
-              {this.props.profile.languageName}
-            </span>
           </h1>
 
           <div className="pull-right">
@@ -110,8 +117,7 @@ export default class ProfileHeader extends React.Component {
               <li>
                 <Link
                     to={{ pathname: '/changelog', query: { key: this.props.profile.key } }}
-                    className="small text-muted"
-                    activeClassName="link-active">
+                    className="button">
                   {translate('changelog')}
                 </Link>
               </li>
@@ -124,6 +130,18 @@ export default class ProfileHeader extends React.Component {
                     <i className="icon-dropdown"/>
                   </button>
                   <ul className="dropdown-menu dropdown-menu-right">
+                    <li>
+                      <Link
+                          to={{ pathname: '/compare', query: { key: profile.key } }}
+                          id="quality-profile-compare">
+                        {translate('compare')}
+                      </Link>
+                    </li>
+                    <li>
+                      <a href={activateMoreUrl}>
+                        {translate('quality_profiles.activate_more_rules')}
+                      </a>
+                    </li>
                     <li>
                       <Link
                           to={{ pathname: '/compare', query: { key: profile.key } }}
index 99b75fea77e50297f0b5b2e12fd537a32900a5f4..108b42c14b71e8dc87e57c9d0f7c67becceb8c3d 100644 (file)
@@ -19,6 +19,7 @@
  */
 import React from 'react';
 import ChangeProjectsView from '../views/ChangeProjectsView';
+import QualifierIcon from '../../../components/shared/qualifier-icon';
 import { ProfileType } from '../propTypes';
 import { getProfileProjects } from '../../../api/quality-profiles';
 import { translate } from '../../../helpers/l10n';
@@ -110,7 +111,7 @@ export default class ProfileProjects extends React.Component {
               <li key={project.uuid}
                   className="spacer-top js-profile-project"
                   data-key={project.key}>
-                <i className="icon-checkbox icon-checkbox-checked"/>
+                <QualifierIcon qualifier="TRK"/>
                 {' '}
                 {project.name}
               </li>
index 539878dec9f7ec52f544c9c52bbefb08a61e1979..dd04d7cffde5ebf9a15d92f3a792cd08f7525684 100644 (file)
@@ -132,6 +132,25 @@ export default class ProfileRules extends React.Component {
     );
   }
 
+  renderActiveTotal () {
+    const rulesUrl = getRulesUrl({
+      qprofile: this.props.profile.key,
+      activation: 'false'
+    });
+
+    if (this.state.total == null) {
+      return null;
+    }
+
+    return (
+        <a href={rulesUrl}>
+          <strong>
+            {formatMeasure(this.state.total, 'SHORT_INT')}
+          </strong>
+        </a>
+    );
+  }
+
   getTooltipForType (type) {
     const { count } = this.state.activatedByType[type];
     const total = this.state.allByType[type].count;
@@ -162,6 +181,26 @@ export default class ProfileRules extends React.Component {
     );
   }
 
+  renderTotalForType (type) {
+    const rulesUrl = getRulesUrl({
+      qprofile: this.props.profile.key,
+      activation: 'false',
+      types: type
+    });
+
+    const { count } = this.state.allByType[type];
+
+    if (count == null) {
+      return null;
+    }
+
+    return (
+        <a href={rulesUrl}>
+          {formatMeasure(count, 'SHORT_INT')}
+        </a>
+    );
+  }
+
   renderDeprecated () {
     const { profile } = this.props;
 
@@ -186,8 +225,6 @@ export default class ProfileRules extends React.Component {
   }
 
   render () {
-    const { total, activatedTotal, allByType, activatedByType } = this.state;
-
     const activateMoreUrl = getRulesUrl({
       qprofile: this.props.profile.key,
       activation: 'false'
@@ -212,21 +249,17 @@ export default class ProfileRules extends React.Component {
             <ul className="quality-profile-rules-distribution">
               <li key="all" className="big-spacer-bottom">
                 <ProfileRulesRow
-                    count={activatedTotal}
-                    total={total}
-                    tooltip={this.getTooltip(activatedTotal, total)}
                     renderTitle={this.renderActiveTitle.bind(this)}
-                    renderCount={this.renderActiveCount.bind(this)}/>
+                    renderCount={this.renderActiveCount.bind(this)}
+                    renderTotal={this.renderActiveTotal.bind(this)}/>
               </li>
 
               {TYPES.map(type => (
                   <li key={type} className="spacer-top">
                     <ProfileRulesRow
-                        count={activatedByType[type].count}
-                        total={allByType[type].count}
-                        tooltip={this.getTooltipForType(type)}
                         renderTitle={this.renderTitleForType.bind(this, type)}
-                        renderCount={this.renderCountForType.bind(this, type)}/>
+                        renderCount={this.renderCountForType.bind(this, type)}
+                        renderTotal={this.renderTotalForType.bind(this, type)}/>
                   </li>
               ))}
             </ul>
index 6baf9ca811e7e3ce42a57d5fb03cfda53b45a671..e945ed924ad0a2ce76b0df769527e160defea2bb 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import React from 'react';
-import ProgressBar from './ProgressBar';
 
 export default class ProfileRulesRow extends React.Component {
   static propTypes = {
-    count: React.PropTypes.number,
-    total: React.PropTypes.number,
-    tooltip: React.PropTypes.string,
     renderTitle: React.PropTypes.func.isRequired,
-    renderCount: React.PropTypes.func.isRequired
+    renderCount: React.PropTypes.func.isRequired,
+    renderTotal: React.PropTypes.func.isRequired
   };
 
   render () {
-    const { total, count, tooltip, renderTitle, renderCount } = this.props;
+    const { renderTitle, renderCount, renderTotal } = this.props;
 
     return (
-        <div title={tooltip} data-toggle="tooltip">
-          <div className="clearfix">
-            <div className="pull-left">
-              {renderTitle()}
-            </div>
-            <div className="pull-right">
-              {renderCount()}
-            </div>
+        <div className="clearfix">
+          <div className="pull-left">
+            {renderTitle()}
           </div>
-          <div className="little-spacer-top" style={{ height: 2 }}>
-            <ProgressBar
-                count={count || 0}
-                total={total || 0}
-                width={300}/>
+          <div className="pull-right">
+            {renderCount()}
+            {' / '}
+            {renderTotal()}
           </div>
         </div>
     );
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProgressBar.js b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProgressBar.js
deleted file mode 100644 (file)
index 5efc85f..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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';
-
-export default class ProgressBar extends React.Component {
-  static propTypes = {
-    width: React.PropTypes.number.isRequired,
-    height: React.PropTypes.number,
-    count: React.PropTypes.number.isRequired,
-    total: React.PropTypes.number.isRequired
-  };
-
-  static defaultProps = {
-    height: 2
-  };
-
-  render () {
-    const { width, height } = this.props;
-    const p = this.props.total > 0 ? this.props.count / this.props.total : 0;
-    const fillWidth = this.props.width * p;
-
-    const commonProps = { x: 0, y: 0, rx: 2, height };
-
-    return (
-        <svg width={width} height={height}>
-          <rect
-              {...commonProps}
-              width={width}
-              fill="#e6e6e6"/>
-          <rect
-              {...commonProps}
-              width={fillWidth}
-              className="bar-chart-bar quality-profile-progress-bar"/>
-        </svg>
-    );
-  }
-}
index b4b10f4e4ae4730d956f17305b5bfee06650dd4e..e153d03a2166b8b85d9df919fada8d39d0656a03 100644 (file)
@@ -21,6 +21,7 @@ import React from 'react';
 import { PropTypes as RouterPropTypes } from 'react-router';
 import groupBy from 'lodash/groupBy';
 import pick from 'lodash/pick';
+import sortBy from 'lodash/sortBy';
 import ProfilesListRow from './ProfilesListRow';
 import ProfilesListHeader from './ProfilesListHeader';
 import RestoreBuiltInProfilesView from '../views/RestoreBuiltInProfilesView';
@@ -64,7 +65,7 @@ export default class ProfilesList extends React.Component {
               {')'}
               {this.props.canAdmin && (
                   <button
-                      className="spacer-left js-restore-built-in"
+                      className="huge-spacer-left js-restore-built-in"
                       data-language={languageKey}
                       onClick={this.handleRestoreBuiltIn.bind(this, languageKey)}>
                     {translate('quality_profiles.restore_built_in_profiles')}
@@ -97,6 +98,8 @@ export default class ProfilesList extends React.Component {
         pick(profilesIndex, language) :
         profilesIndex;
 
+    const languagesToShow = sortBy(Object.keys(profilesToShow));
+
     return (
         <div>
           <ProfilesListHeader
@@ -109,7 +112,7 @@ export default class ProfilesList extends React.Component {
               </div>
           )}
 
-          {Object.keys(profilesToShow).map(languageKey => (
+          {languagesToShow.map(languageKey => (
               <table
                   key={languageKey}
                   data-language={languageKey}
index 532d76e52953760ac7d0a1a702597296f97dce02..010321937ce479969d4595fca12ee41fcc1d8d31 100644 (file)
@@ -35,7 +35,7 @@ export default class ProfilesListHeader extends React.Component {
 
     const label = currentFilter ?
         translateWithParameters(
-            'quality_profiles.x_profiles',
+            'quality_profiles.x_Profiles',
             currentLanguage.name) :
         translate('quality_profiles.all_profiles');
 
index c71d00c68a7f074da21301ee57ce9d9ca32e01e3..9cd46314b1911ab9734f47177615149693b187cf 100644 (file)
 .quality-profile-inheritance {
 }
 
-.quality-profile-progress-bar {
-  transition: width 0.5s ease;
-  animation: appear 0.5s forwards;
-}
-
-@keyframes appear {
-  0% { transform: translateX(-100%); }
-  100% { transform: translateX(0); }
-}
-
 .quality-profile-not-found {
   padding-top: 100px;
   text-align: center;
index 1c0b097155d8e65fb4572d3a2f4b8581c7d37026..4f47e67b8bfbcdfbdbcabf6b62b8e538aa372f5f 100644 (file)
@@ -59,7 +59,7 @@ a {
 a.active-link,
 .link-active {
   .link-no-underline;
-  font-weight: 500;
+  cursor: default;
 }
 
 
index c4854f06fe38404219be26f8cfed7d5e38485472..ac158bc19fea0ac965ae18c1f9f7b30501af16a6 100644 (file)
@@ -1759,8 +1759,8 @@ quality_profile.total_active_rules=Total Active Rules
 quality_profiles.x_overridden_rules={0} overridden rules
 quality_profiles.change_parent=Change Parent
 quality_profiles.all_profiles=All Profiles
-quality_profiles.x_profiles={0} Profiles
-quality_profiles._quality_profiles=quality profiles
+quality_profiles.x_profiles={0} profile(s)
+quality_profiles.x_Profiles={0} Profiles
 quality_profiles.x_projects={0} projects
 quality_profiles.no_results=No profiles found. Try installing a language plugin.
 quality_profiles.projects.select_hint=Click to associate this project with the quality profile
@@ -1768,6 +1768,7 @@ quality_profiles.projects.deselect_hint=Click to remove association between this
 quality_profiles.no_profiles_for_comparison=There are no profiles for comparison
 quality_profile.empty_comparison=The quality profiles are equal.
 quality_profiles.activate_more=Activate More
+quality_profiles.activate_more_rules=Activate More Rules
 quality_profiles.intro1=Quality Profiles are collections of rules to apply during an analysis.
 quality_profiles.intro2=For each language there is a default profile. All projects not explicitly assigned to some other profile will be analyzed with the default.
 quality_profiles.list.profile=Profile
@@ -1780,10 +1781,10 @@ quality_profiles.x_activated_out_of_y={0} rules activated out of {1} available
 quality_profiles.change_projects=Change Projects
 quality_profiles.not_found=The requested quality profile was not found.
 quality_profiles.latest_new_rules=Latest New Rules
-quality_profiles.latest_new_rules.activated={0}, activated on {1} profiles
+quality_profiles.latest_new_rules.activated={0}, activated on {1} profile(s)
 quality_profiles.latest_new_rules.not_activated={0}, not yet activated
 quality_profiles.deprecated_rules=Deprecated Rules
-quality_profiles.x_deprecated_rules_are_still_activated={0} deprecated rules are still activated on {1} quality profiles:
+quality_profiles.x_deprecated_rules_are_still_activated={0} deprecated rule(s) are still activated on {1} quality profile(s):
 quality_profiles.stagnant_profiles=Stagnant Profiles
 quality_profiles.not_updated_more_than_year=The following profiles haven't been updated for more than 1 year: