]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-17845 [1096026, 1099611] Multiple links have the same programmatic link text...
authorKevin Silva <kevin.silva@sonarsource.com>
Tue, 10 Jan 2023 13:41:42 +0000 (14:41 +0100)
committersonartech <sonartech@sonarsource.com>
Mon, 16 Jan 2023 20:03:43 +0000 (20:03 +0000)
server/sonar-web/src/main/js/apps/coding-rules/components/SimilarRulesFilter.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/SimilarRulesFilter-test.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/SimilarRulesFilter-test.tsx.snap
server/sonar-web/src/main/js/apps/coding-rules/styles.css
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 0c3f8e462eab5e38cbc199595d8d9e013d7446e1..73fc930e32f1ed126128091b69db06195e53c529 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+import classNames from 'classnames';
 import * as React from 'react';
+import { Button, ButtonPlain } from '../../../components/controls/buttons';
 import Dropdown from '../../../components/controls/Dropdown';
 import DropdownIcon from '../../../components/icons/DropdownIcon';
 import FilterIcon from '../../../components/icons/FilterIcon';
 import IssueTypeIcon from '../../../components/icons/IssueTypeIcon';
 import TagsIcon from '../../../components/icons/TagsIcon';
 import SeverityHelper from '../../../components/shared/SeverityHelper';
-import { translate } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { Rule } from '../../../types/types';
 import { Query } from '../query';
 
@@ -34,32 +36,23 @@ interface Props {
 }
 
 export default class SimilarRulesFilter extends React.PureComponent<Props> {
-  handleLanguageClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
-    event.preventDefault();
-    event.currentTarget.blur();
+  handleLanguageClick = () => {
     if (this.props.rule.lang) {
       this.props.onFilterChange({ languages: [this.props.rule.lang] });
     }
   };
 
-  handleTypeClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
-    event.preventDefault();
-    event.currentTarget.blur();
+  handleTypeClick = () => {
     this.props.onFilterChange({ types: [this.props.rule.type] });
   };
 
-  handleSeverityClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
-    event.preventDefault();
-    event.currentTarget.blur();
+  handleSeverityClick = () => {
     if (this.props.rule.severity) {
       this.props.onFilterChange({ severities: [this.props.rule.severity] });
     }
   };
 
-  handleTagClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
-    event.preventDefault();
-    event.currentTarget.blur();
-    const { tag } = event.currentTarget.dataset;
+  handleTagClick = (tag: string) => {
     if (tag) {
       this.props.onFilterChange({ tags: [tag] });
     }
@@ -75,70 +68,82 @@ export default class SimilarRulesFilter extends React.PureComponent<Props> {
         className="display-inline-block"
         overlay={
           <>
-            <h2 className="menu-header" id="filter-similar-rules">
+            <h3 className="coding-rules-filter-title">
               {translate('coding_rules.filter_similar_rules')}
-            </h2>
-            <ul className="menu" aria-labelledby="filter-similar-rules">
-              <li>
-                <a
-                  data-test="coding-rules__similar-language"
-                  href="#"
-                  onClick={this.handleLanguageClick}
-                >
-                  {rule.langName}
-                </a>
-              </li>
-
+            </h3>
+            <ul className="menu">
+              {rule.langName && (
+                <li>
+                  <ButtonPlain
+                    data-test="coding-rules__similar-language"
+                    aria-label={translateWithParameters(
+                      'coding_rules.filter_by_language',
+                      rule.langName
+                    )}
+                    onClick={this.handleLanguageClick}
+                  >
+                    {rule.langName}
+                  </ButtonPlain>
+                </li>
+              )}
               <li>
-                <a
-                  className="display-flex-center"
+                <ButtonPlain
+                  aria-label={translateWithParameters(
+                    'coding_rules.filter_by_type',
+                    translate('issue.type', rule.type)
+                  )}
                   data-test="coding-rules__similar-type"
-                  href="#"
                   onClick={this.handleTypeClick}
                 >
                   <IssueTypeIcon query={rule.type} />
                   <span className="little-spacer-left">{translate('issue.type', rule.type)}</span>
-                </a>
+                </ButtonPlain>
               </li>
 
               {severity && (
                 <li>
-                  <a
+                  <ButtonPlain
                     data-test="coding-rules__similar-severity"
-                    href="#"
+                    aria-label={translateWithParameters(
+                      'coding_rules.filter_by_severity',
+                      severity
+                    )}
                     onClick={this.handleSeverityClick}
                   >
-                    <SeverityHelper className="display-flex-center" severity={rule.severity} />
-                  </a>
+                    <SeverityHelper className="display-flex-center" severity={severity} />
+                  </ButtonPlain>
                 </li>
               )}
 
-              {allTags.length > 0 && <li className="divider" />}
-              {allTags.map((tag) => (
-                <li key={tag}>
-                  <a
+              {allTags.map((tag, index) => (
+                <li
+                  className={classNames('coding-rules-similar-tag', {
+                    'coding-rules-similar-tag-divider': index === 0,
+                  })}
+                  key={tag}
+                >
+                  <ButtonPlain
                     data-tag={tag}
                     data-test="coding-rules__similar-tag"
-                    href="#"
-                    onClick={this.handleTagClick}
+                    aria-label={translateWithParameters('coding_rules.filter_by_tag', tag)}
+                    onClick={() => this.handleTagClick(tag)}
                   >
                     <TagsIcon className="little-spacer-right text-middle" />
                     <span className="text-middle">{tag}</span>
-                  </a>
+                  </ButtonPlain>
                 </li>
               ))}
             </ul>
           </>
         }
       >
-        <a
-          className="js-rule-filter link-no-underline spacer-left dropdown-toggle"
-          href="#"
+        <Button
+          className="js-rule-filter spacer-left"
           title={translate('coding_rules.filter_similar_rules')}
         >
           <FilterIcon />
           <DropdownIcon />
-        </a>
+        </Button>
       </Dropdown>
     );
   }
index e93d5ac58d0bb50063078c52fb50b8a4adef97a0..41629801e7f21e0e23ef3f78043e3b2e0703e46a 100644 (file)
@@ -62,6 +62,6 @@ function mountRenderAction(actionName: string, props: Partial<SimilarRulesFilter
     <SimilarRulesFilter onFilterChange={jest.fn()} rule={mockRule()} {...props} />
   );
   return mount(wrapper.find('Dropdown').prop<React.ReactElement>('overlay'))
-    .find(`a[data-test="coding-rules__similar-${actionName}"]`)
+    .find(`button[data-test="coding-rules__similar-${actionName}"]`)
     .first();
 }
index 2585ebc6e1db55117953cba21a1d481089988f80..63f445a90aad02a03824b43f05b8237af747df95 100644 (file)
@@ -5,30 +5,27 @@ exports[`should render correctly 1`] = `
   className="display-inline-block"
   overlay={
     <React.Fragment>
-      <h2
-        className="menu-header"
-        id="filter-similar-rules"
+      <h3
+        className="coding-rules-filter-title"
       >
         coding_rules.filter_similar_rules
-      </h2>
+      </h3>
       <ul
-        aria-labelledby="filter-similar-rules"
         className="menu"
       >
         <li>
-          <a
+          <ButtonPlain
+            aria-label="coding_rules.filter_by_language.JavaScript"
             data-test="coding-rules__similar-language"
-            href="#"
             onClick={[Function]}
           >
             JavaScript
-          </a>
+          </ButtonPlain>
         </li>
         <li>
-          <a
-            className="display-flex-center"
+          <ButtonPlain
+            aria-label="coding_rules.filter_by_type.issue.type.CODE_SMELL"
             data-test="coding-rules__similar-type"
-            href="#"
             onClick={[Function]}
           >
             <IssueTypeIcon
@@ -39,28 +36,27 @@ exports[`should render correctly 1`] = `
             >
               issue.type.CODE_SMELL
             </span>
-          </a>
+          </ButtonPlain>
         </li>
         <li>
-          <a
+          <ButtonPlain
+            aria-label="coding_rules.filter_by_severity.MAJOR"
             data-test="coding-rules__similar-severity"
-            href="#"
             onClick={[Function]}
           >
             <SeverityHelper
               className="display-flex-center"
               severity="MAJOR"
             />
-          </a>
+          </ButtonPlain>
         </li>
         <li
-          className="divider"
-        />
-        <li>
-          <a
+          className="coding-rules-similar-tag coding-rules-similar-tag-divider"
+        >
+          <ButtonPlain
+            aria-label="coding_rules.filter_by_tag.x"
             data-tag="x"
             data-test="coding-rules__similar-tag"
-            href="#"
             onClick={[Function]}
           >
             <TagsIcon
@@ -71,13 +67,15 @@ exports[`should render correctly 1`] = `
             >
               x
             </span>
-          </a>
+          </ButtonPlain>
         </li>
-        <li>
-          <a
+        <li
+          className="coding-rules-similar-tag"
+        >
+          <ButtonPlain
+            aria-label="coding_rules.filter_by_tag.a"
             data-tag="a"
             data-test="coding-rules__similar-tag"
-            href="#"
             onClick={[Function]}
           >
             <TagsIcon
@@ -88,13 +86,15 @@ exports[`should render correctly 1`] = `
             >
               a
             </span>
-          </a>
+          </ButtonPlain>
         </li>
-        <li>
-          <a
+        <li
+          className="coding-rules-similar-tag"
+        >
+          <ButtonPlain
+            aria-label="coding_rules.filter_by_tag.b"
             data-tag="b"
             data-test="coding-rules__similar-tag"
-            href="#"
             onClick={[Function]}
           >
             <TagsIcon
@@ -105,19 +105,18 @@ exports[`should render correctly 1`] = `
             >
               b
             </span>
-          </a>
+          </ButtonPlain>
         </li>
       </ul>
     </React.Fragment>
   }
 >
-  <a
-    className="js-rule-filter link-no-underline spacer-left dropdown-toggle"
-    href="#"
+  <Button
+    className="js-rule-filter spacer-left"
     title="coding_rules.filter_similar_rules"
   >
     <FilterIcon />
     <DropdownIcon />
-  </a>
+  </Button>
 </Dropdown>
 `;
index 969fcb856de38fb6e4d9a72d3080cc9e235f6e39..f7cab25e4cb5affe6aaa67ea29c78b777c8dacec 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 .coding-rules-extended-view .coding-rules-list {
   display: none;
 }
   display: block;
 }
 
+.coding-rules-similar-tag-divider {
+  margin-top: 6px;
+  border-top: 1px solid var(--barBorderColor);
+}
+
+.coding-rules-filter-title {
+  padding: var(--gridSize);
+  font-size: 12px;
+  color: var(--neutral600);
+  white-space: nowrap;
+  line-height: unset;
+}
+
 /*
  * Detail
  */
 }
 
 .coding-rule-table td {
-  vertical-align: top;
+  vertical-align: middle;
 }
 
 .coding-rule-table + .coding-rule-table {
index 74aa32dccf885ca82cec41fd4ee32690dbe3ccf1..b4f051af2a08b31a1b4335b1caadde2c1bdf6e17 100644 (file)
@@ -1958,6 +1958,10 @@ coding_rules.type.tooltip.VULNERABILITY=Vulnerability Detection Rule
 coding_rules.type.tooltip.SECURITY_HOTSPOT=Security Hotspot Detection Rule
 coding_rules.update_custom_rule=Update Custom Rule
 coding_rules.filter_similar_rules=Filter Similar Rules
+coding_rules.filter_by_language=Filter by {0} language
+coding_rules.filter_by_type=Filter by {0} type
+coding_rules.filter_by_severity=Filter by {0} severity
+coding_rules.filter_by_tag=Filter by {0} tag
 
 coding_rules.filters.activation=Activation
 coding_rules.filters.activation.active=Active