aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Davis <jeremy.davis@sonarsource.com>2022-08-03 16:12:20 +0200
committersonartech <sonartech@sonarsource.com>2022-08-05 20:03:27 +0000
commitc92a1586c459a2e351cec20cdf40b474f56a94c3 (patch)
tree3f6ded6b29ac9bfbe3c3a2f7101f4d0ed3f45545
parentaaacc791345ceefcf458bb4b368280df864dba5b (diff)
downloadsonarqube-c92a1586c459a2e351cec20cdf40b474f56a94c3.tar.gz
sonarqube-c92a1586c459a2e351cec20cdf40b474f56a94c3.zip
SONAR-16731 [891608] Purpose of link is not clear in context
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/PageSidebar-test.tsx83
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/Filter.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/IssuesFilter.tsx25
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.tsx12
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/NewLinesFilter.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/QualifierFilter.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.tsx10
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/SecurityReviewFilter.tsx20
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/SizeFilter.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/Filter-test.tsx1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/CoverageFilter-test.tsx.snap1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/DuplicationsFilter-test.tsx.snap1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/Filter-test.tsx.snap21
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/IssuesFilter-test.tsx.snap1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/LanguagesFilter-test.tsx.snap5
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewLinesFilter-test.tsx.snap1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualifierFilter-test.tsx.snap1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualityGateFilter-test.tsx.snap1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SecurityReviewFilter-test.tsx.snap1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SizeFilter-test.tsx.snap1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/TagsFilter-test.tsx.snap7
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties25
25 files changed, 248 insertions, 46 deletions
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageSidebar-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageSidebar-test.tsx
index 2940711cbbc..b5f1e51794c 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageSidebar-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageSidebar-test.tsx
@@ -17,55 +17,72 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { shallow } from 'enzyme';
+import { screen } from '@testing-library/react';
import * as React from 'react';
+import { CurrentUserContext } from '../../../../app/components/current-user/CurrentUserContext';
+import { mockCurrentUser } from '../../../../helpers/testMocks';
+import { renderComponent } from '../../../../helpers/testReactTestingUtils';
+import { CurrentUser } from '../../../../types/users';
import PageSidebar, { PageSidebarProps } from '../PageSidebar';
-it('should render correctly', () => {
- const sidebar = shallowRender({
- query: { size: '3' },
- view: 'overall'
+it('should render the right facets for overview', () => {
+ renderPageSidebar({
+ query: { size: '3' }
});
- expect(sidebar).toMatchSnapshot();
+ expect(screen.getByRole('heading', { level: 3, name: 'metric_domain.Size' })).toBeInTheDocument();
+
+ expect(
+ screen.getByRole('heading', { level: 3, name: 'projects.facets.qualifier' })
+ ).toBeInTheDocument();
+
+ expect(
+ screen.queryByRole('heading', { level: 3, name: 'projects.facets.new_lines' })
+ ).not.toBeInTheDocument();
});
-it('should render correctly with no applications', () => {
- const sidebar = shallowRender({
+it('should not show the qualifier facet with no applications', () => {
+ renderPageSidebar({
applicationsEnabled: false,
- query: { size: '3' },
- view: 'overall'
+ query: { size: '3' }
});
- expect(sidebar).toMatchSnapshot();
+ expect(
+ screen.queryByRole('heading', { level: 3, name: 'projects.facets.qualifier' })
+ ).not.toBeInTheDocument();
});
-it('should render `leak` view correctly', () => {
- const sidebar = shallowRender({
+it('should show "new lines" instead of "size" when in `leak` view', () => {
+ renderPageSidebar({
query: { view: 'leak' },
view: 'leak'
});
- expect(sidebar).toMatchSnapshot();
-});
-it('should render `leak` view correctly with no applications', () => {
- const sidebar = shallowRender({
- applicationsEnabled: false,
- query: { view: 'leak' },
- view: 'leak'
- });
- expect(sidebar).toMatchSnapshot();
+ expect(
+ screen.queryByRole('heading', { level: 3, name: 'metric_domain.Size' })
+ ).not.toBeInTheDocument();
+
+ expect(
+ screen.getByRole('heading', { level: 3, name: 'projects.facets.new_lines' })
+ ).toBeInTheDocument();
});
-function shallowRender(overrides: Partial<PageSidebarProps> = {}) {
- return shallow(
- <PageSidebar
- applicationsEnabled={true}
- onClearAll={jest.fn()}
- onQueryChange={jest.fn()}
- query={{ view: 'overall' }}
- view="overall"
- {...overrides}
- />
- );
+function renderPageSidebar(overrides: Partial<PageSidebarProps> = {}, currentUser?: CurrentUser) {
+ return renderComponent(
+ <CurrentUserContext.Provider
+ value={{
+ currentUser: currentUser ?? mockCurrentUser(),
+ updateCurrentUserHomepage: jest.fn(),
+ updateDismissedNotices: jest.fn()
+ }}>
+ <PageSidebar
+ applicationsEnabled={true}
+ onClearAll={jest.fn()}
+ onQueryChange={jest.fn()}
+ query={{ view: 'overall' }}
+ view="overall"
+ {...overrides}
+ />
+ </CurrentUserContext.Provider>
+ ).container;
}
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.tsx
index a93ca431ea0..54717829ac2 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import CoverageRating from '../../../components/ui/CoverageRating';
-import { translate } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
import { getCoverageRatingAverageValue, getCoverageRatingLabel } from '../../../helpers/ratings';
import { RawQuery } from '../../../types/types';
import { Facet } from '../types';
@@ -35,6 +35,8 @@ export interface Props {
value?: any;
}
+const NO_DATA_OPTION = 6;
+
export default function CoverageFilter(props: Props) {
const { property = 'coverage' } = props;
@@ -50,6 +52,7 @@ export default function CoverageFilter(props: Props) {
onQueryChange={props.onQueryChange}
options={[1, 2, 3, 4, 5, 6]}
property={property}
+ renderAccessibleLabel={renderAccessibleLabel}
renderOption={renderOption}
value={props.value}
/>
@@ -61,10 +64,19 @@ function getFacetValueForOption(facet: Facet, option: number): number {
return facet[map[option - 1]];
}
+function renderAccessibleLabel(option: number) {
+ return option < NO_DATA_OPTION
+ ? translate('projects.facets.coverage.label', option.toString())
+ : translateWithParameters(
+ 'projects.facets.label_no_data_x',
+ translate('metric_domain.Coverage')
+ );
+}
+
function renderOption(option: number, selected: boolean) {
return (
<div className="display-flex-center">
- {option < 6 && (
+ {option < NO_DATA_OPTION && (
<CoverageRating
muted={!selected}
size="small"
@@ -72,7 +84,7 @@ function renderOption(option: number, selected: boolean) {
/>
)}
<span className="spacer-left">
- {option < 6 ? (
+ {option < NO_DATA_OPTION ? (
getCoverageRatingLabel(option)
) : (
<span className="big-spacer-left">{translate('no_data')}</span>
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.tsx
index c3821b81ed4..0520515fa44 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import DuplicationsRating from '../../../components/ui/DuplicationsRating';
-import { translate } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
import {
getDuplicationsRatingAverageValue,
getDuplicationsRatingLabel
@@ -38,6 +38,8 @@ export interface Props {
value?: any;
}
+const NO_DATA_OPTION = 6;
+
export default function DuplicationsFilter(props: Props) {
const { property = 'duplications' } = props;
return (
@@ -52,6 +54,7 @@ export default function DuplicationsFilter(props: Props) {
onQueryChange={props.onQueryChange}
options={[1, 2, 3, 4, 5, 6]}
property={property}
+ renderAccessibleLabel={renderAccessibleLabel}
renderOption={renderOption}
value={props.value}
/>
@@ -63,10 +66,19 @@ function getFacetValueForOption(facet: Facet, option: number) {
return facet[map[option - 1]];
}
+function renderAccessibleLabel(option: number) {
+ return option < NO_DATA_OPTION
+ ? translate('projects.facets.duplication.label', option.toString())
+ : translateWithParameters(
+ 'projects.facets.label_no_data_x',
+ translate('metric_domain.Duplications')
+ );
+}
+
function renderOption(option: number, selected: boolean) {
return (
<div className="display-flex-center">
- {option < 6 && (
+ {option < NO_DATA_OPTION && (
<DuplicationsRating
muted={!selected}
size="small"
@@ -74,7 +86,7 @@ function renderOption(option: number, selected: boolean) {
/>
)}
<span className="spacer-left">
- {option < 6 ? (
+ {option < NO_DATA_OPTION ? (
getDuplicationsRatingLabel(option)
) : (
<span className="big-spacer-left">{translate('no_data')}</span>
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/Filter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/Filter.tsx
index 7f5c5db9fce..1693fd2494f 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/Filter.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/filters/Filter.tsx
@@ -31,6 +31,7 @@ interface Props {
className?: string;
onQueryChange: (change: RawQuery) => void;
options: Option[];
+ renderAccessibleLabel: (option: Option) => string;
renderOption: (option: Option, isSelected: boolean) => React.ReactNode;
value?: Option | Option[];
@@ -126,7 +127,13 @@ export default class Filter extends React.PureComponent<Props> {
option > value;
return (
- <a className={className} data-key={option} href="#" key={option} onClick={this.handleClick}>
+ <a
+ aria-label={this.props.renderAccessibleLabel(option)}
+ className={className}
+ data-key={option}
+ href="#"
+ key={option}
+ onClick={this.handleClick}>
<span className="facet-name">
{this.props.renderOption(option, this.isSelected(option) || isUnderSelectedOption)}
</span>
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/IssuesFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/IssuesFilter.tsx
index 28ec1bbf4cb..57d9ac71690 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/IssuesFilter.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/filters/IssuesFilter.tsx
@@ -19,7 +19,8 @@
*/
import * as React from 'react';
import Rating from '../../../components/ui/Rating';
-import { translate } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { formatMeasure } from '../../../helpers/measures';
import { RawQuery } from '../../../types/types';
import { Facet } from '../types';
import Filter from './Filter';
@@ -37,6 +38,27 @@ interface Props {
}
export default function IssuesFilter(props: Props) {
+ const { name } = props;
+
+ const renderAccessibleLabel = React.useCallback(
+ (option: number) => {
+ if (option === 1) {
+ return translateWithParameters(
+ 'projects.facets.rating_label_single_x',
+ translate('metric_domain', name),
+ formatMeasure(option, 'RATING')
+ );
+ }
+
+ return translateWithParameters(
+ 'projects.facets.rating_label_multi_x',
+ translate('metric_domain', name),
+ formatMeasure(option, 'RATING')
+ );
+ },
+ [name]
+ );
+
return (
<Filter
className={props.className}
@@ -51,6 +73,7 @@ export default function IssuesFilter(props: Props) {
onQueryChange={props.onQueryChange}
options={[1, 2, 3, 4, 5]}
property={props.property}
+ renderAccessibleLabel={renderAccessibleLabel}
renderOption={renderOption}
value={props.value}
/>
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.tsx
index 141fd43f77b..4967425be1b 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.tsx
@@ -20,7 +20,7 @@
import { difference, sortBy } from 'lodash';
import * as React from 'react';
import withLanguagesContext from '../../../app/components/languages/withLanguagesContext';
-import { translate } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
import { Languages } from '../../../types/languages';
import { Dict, RawQuery } from '../../../types/types';
import { Facet } from '../types';
@@ -52,6 +52,15 @@ export class LanguagesFilter extends React.Component<Props> {
getSortedOptions = (facet: Facet = {}) =>
sortBy(Object.keys(facet), [(option: string) => -facet[option], (option: string) => option]);
+ renderAccessibleLabel = (option: string) => {
+ const { languages } = this.props;
+ return translateWithParameters(
+ 'projects.facets.label_text_x',
+ translate('projects.facets.languages'),
+ languages[option]?.name || option
+ );
+ };
+
renderOption = (option: string) => (
<SearchableFilterOption option={this.props.languages[option]} optionKey={option} />
);
@@ -75,6 +84,7 @@ export class LanguagesFilter extends React.Component<Props> {
onQueryChange={this.props.onQueryChange}
options={this.getSortedOptions(this.props.facet)}
property={property}
+ renderAccessibleLabel={this.renderAccessibleLabel}
renderOption={this.renderOption}
value={this.props.value}
/>
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/NewLinesFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/NewLinesFilter.tsx
index 106ab095f92..4ca2c1d8264 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/NewLinesFilter.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/filters/NewLinesFilter.tsx
@@ -47,6 +47,7 @@ export default function NewLinesFilter(props: Props) {
onQueryChange={props.onQueryChange}
options={[1, 2, 3, 4, 5]}
property={property}
+ renderAccessibleLabel={renderAccessibleLabel}
renderOption={renderOption}
value={props.value}
/>
@@ -61,3 +62,7 @@ function getFacetValueForOption(facet: Facet, option: number) {
function renderOption(option: number) {
return <span>{getSizeRatingLabel(option)}</span>;
}
+
+function renderAccessibleLabel(option: number) {
+ return translate('projects.facets.new_lines.label', option.toString());
+}
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/QualifierFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/QualifierFilter.tsx
index 26be7822881..8b45934dc73 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/QualifierFilter.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/filters/QualifierFilter.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import QualifierIcon from '../../../components/icons/QualifierIcon';
-import { translate } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
import { ComponentQualifier } from '../../../types/component';
import { RawQuery } from '../../../types/types';
import { Facet } from '../types';
@@ -46,12 +46,21 @@ export default function QualifierFilter(props: QualifierFilterProps) {
onQueryChange={props.onQueryChange}
options={options}
property="qualifier"
+ renderAccessibleLabel={renderAccessibleLabel}
renderOption={renderOption}
value={value}
/>
);
}
+function renderAccessibleLabel(option: string) {
+ return translateWithParameters(
+ 'projects.facets.label_text_x',
+ translate('projects.facets.qualifier'),
+ translate('qualifier', option)
+ );
+}
+
function renderOption(option: string, selected: boolean) {
return (
<span className="display-flex-center">
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.tsx
index c0d5e024c73..4501f9e2de0 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.tsx
@@ -20,7 +20,7 @@
import * as React from 'react';
import HelpTooltip from '../../../components/controls/HelpTooltip';
import Level from '../../../components/ui/Level';
-import { translate } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
import { RawQuery } from '../../../types/types';
import { Facet } from '../types';
import Filter from './Filter';
@@ -33,6 +33,13 @@ export interface Props {
value?: any;
}
+function renderAccessibleLabel(option: string) {
+ return translateWithParameters(
+ 'projects.facets.qualitygate_label_x',
+ translate('metric.level', option)
+ );
+}
+
export default function QualityGateFilter(props: Props) {
const hasWarnStatus = props.facet && props.facet['WARN'] !== undefined;
const options = hasWarnStatus ? ['OK', 'WARN', 'ERROR'] : ['OK', 'ERROR'];
@@ -46,6 +53,7 @@ export default function QualityGateFilter(props: Props) {
options={options}
property="gate"
renderOption={renderOption}
+ renderAccessibleLabel={renderAccessibleLabel}
value={props.value}
/>
);
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/SecurityReviewFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/SecurityReviewFilter.tsx
index 0afe3b293cb..dfe0491984c 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/SecurityReviewFilter.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/filters/SecurityReviewFilter.tsx
@@ -20,7 +20,8 @@
import * as React from 'react';
import SecurityHotspotIcon from '../../../components/icons/SecurityHotspotIcon';
import Rating from '../../../components/ui/Rating';
-import { translate } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { formatMeasure } from '../../../helpers/measures';
import { Dict, RawQuery } from '../../../types/types';
import { Facet } from '../types';
import Filter from './Filter';
@@ -65,12 +66,29 @@ export default function SecurityReviewFilter(props: Props) {
onQueryChange={props.onQueryChange}
options={[1, 2, 3, 4, 5]}
property={property}
+ renderAccessibleLabel={renderAccessibleLabel}
renderOption={renderOption}
value={props.value}
/>
);
}
+function renderAccessibleLabel(option: number) {
+ if (option === 1) {
+ return translateWithParameters(
+ 'projects.facets.rating_label_single_x',
+ translate('metric_domain.SecurityReview'),
+ formatMeasure(option, 'RATING')
+ );
+ }
+
+ return translateWithParameters(
+ 'projects.facets.rating_label_multi_x',
+ translate('metric_domain.SecurityReview'),
+ formatMeasure(option, 'RATING')
+ );
+}
+
function renderOption(option: number, selected: boolean) {
return (
<span>
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/SizeFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/SizeFilter.tsx
index 529d33ce4d2..0eb7ad04860 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/SizeFilter.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/filters/SizeFilter.tsx
@@ -49,6 +49,7 @@ export default function SizeFilter(props: Props) {
onQueryChange={props.onQueryChange}
options={[1, 2, 3, 4, 5]}
property={property}
+ renderAccessibleLabel={renderAccessibleLabel}
renderOption={renderOption}
value={props.value}
/>
@@ -68,3 +69,7 @@ function renderOption(option: number, selected: boolean) {
</div>
);
}
+
+function renderAccessibleLabel(option: number) {
+ return translate('projects.facets.size.label', option.toString());
+}
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.tsx
index b4844f47deb..ea0e9da5dc0 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.tsx
@@ -20,7 +20,7 @@
import { debounce, difference, size, sortBy } from 'lodash';
import * as React from 'react';
import { searchProjectTags } from '../../../api/components';
-import { translate } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
import { Dict, RawQuery } from '../../../types/types';
import { Facet } from '../types';
import Filter from './Filter';
@@ -45,6 +45,14 @@ interface State {
const LIST_SIZE = 10;
+function renderAccessibleLabel(option: string) {
+ return translateWithParameters(
+ 'projects.facets.label_text_x',
+ translate('projects.facets.tags'),
+ option
+ );
+}
+
export default class TagsFilter extends React.PureComponent<Props, State> {
mounted = false;
@@ -119,6 +127,7 @@ export default class TagsFilter extends React.PureComponent<Props, State> {
onQueryChange={this.props.onQueryChange}
options={this.getSortedOptions(this.props.facet)}
property={property}
+ renderAccessibleLabel={renderAccessibleLabel}
renderOption={this.renderOption}
value={this.props.value}
/>
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/Filter-test.tsx b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/Filter-test.tsx
index c6c80b6a102..14b9a2c55e3 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/Filter-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/Filter-test.tsx
@@ -67,6 +67,7 @@ function shallowRender(overrides: Partial<Filter['props']> = {}) {
options={[1, 2, 3]}
property="foo"
renderOption={option => option}
+ renderAccessibleLabel={option => option.toString()}
{...overrides}
/>
);
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/CoverageFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/CoverageFilter-test.tsx.snap
index a77a3e20f95..04f540477f7 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/CoverageFilter-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/CoverageFilter-test.tsx.snap
@@ -22,6 +22,7 @@ exports[`renders 1`] = `
]
}
property="coverage"
+ renderAccessibleLabel={[Function]}
renderOption={[Function]}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/DuplicationsFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/DuplicationsFilter-test.tsx.snap
index 4672e648690..b20207155db 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/DuplicationsFilter-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/DuplicationsFilter-test.tsx.snap
@@ -22,6 +22,7 @@ exports[`renders 1`] = `
]
}
property="duplications"
+ renderAccessibleLabel={[Function]}
renderOption={[Function]}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/Filter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/Filter-test.tsx.snap
index d0d09c08b8c..c63c31cecea 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/Filter-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/Filter-test.tsx.snap
@@ -9,6 +9,7 @@ exports[`highlights under 1`] = `
className="search-navigator-facet-list projects-facet-list"
>
<a
+ aria-label="1"
className="facet search-navigator-facet projects-facet"
data-key={1}
href="#"
@@ -25,6 +26,7 @@ exports[`highlights under 1`] = `
className="search-navigator-facet-highlight-under-container"
>
<a
+ aria-label="2"
className="facet search-navigator-facet projects-facet"
data-key={2}
href="#"
@@ -38,6 +40,7 @@ exports[`highlights under 1`] = `
</span>
</a>
<a
+ aria-label="3"
className="facet search-navigator-facet projects-facet"
data-key={3}
href="#"
@@ -64,6 +67,7 @@ exports[`hightlights under selected 1`] = `
className="search-navigator-facet-list projects-facet-list"
>
<a
+ aria-label="1"
className="facet search-navigator-facet projects-facet"
data-key={1}
href="#"
@@ -80,6 +84,7 @@ exports[`hightlights under selected 1`] = `
className="search-navigator-facet-highlight-under-container"
>
<a
+ aria-label="2"
className="facet search-navigator-facet projects-facet active"
data-key={2}
href="#"
@@ -93,6 +98,7 @@ exports[`hightlights under selected 1`] = `
</span>
</a>
<a
+ aria-label="3"
className="facet search-navigator-facet projects-facet"
data-key={3}
href="#"
@@ -119,6 +125,7 @@ exports[`renders 1`] = `
className="search-navigator-facet-list projects-facet-list"
>
<a
+ aria-label="1"
className="facet search-navigator-facet projects-facet"
data-key={1}
href="#"
@@ -132,6 +139,7 @@ exports[`renders 1`] = `
</span>
</a>
<a
+ aria-label="2"
className="facet search-navigator-facet projects-facet"
data-key={2}
href="#"
@@ -145,6 +153,7 @@ exports[`renders 1`] = `
</span>
</a>
<a
+ aria-label="3"
className="facet search-navigator-facet projects-facet"
data-key={3}
href="#"
@@ -170,6 +179,7 @@ exports[`renders facet bar chart 1`] = `
className="search-navigator-facet-list projects-facet-list"
>
<a
+ aria-label="a"
className="facet search-navigator-facet projects-facet"
data-key="a"
href="#"
@@ -200,6 +210,7 @@ exports[`renders facet bar chart 1`] = `
</span>
</a>
<a
+ aria-label="b"
className="facet search-navigator-facet projects-facet"
data-key="b"
href="#"
@@ -230,6 +241,7 @@ exports[`renders facet bar chart 1`] = `
</span>
</a>
<a
+ aria-label="c"
className="facet search-navigator-facet projects-facet"
data-key="c"
href="#"
@@ -273,6 +285,7 @@ exports[`renders header and footer 1`] = `
className="search-navigator-facet-list projects-facet-list"
>
<a
+ aria-label="1"
className="facet search-navigator-facet projects-facet"
data-key={1}
href="#"
@@ -286,6 +299,7 @@ exports[`renders header and footer 1`] = `
</span>
</a>
<a
+ aria-label="2"
className="facet search-navigator-facet projects-facet"
data-key={2}
href="#"
@@ -299,6 +313,7 @@ exports[`renders header and footer 1`] = `
</span>
</a>
<a
+ aria-label="3"
className="facet search-navigator-facet projects-facet"
data-key={3}
href="#"
@@ -325,6 +340,7 @@ exports[`renders multiple selected 1`] = `
className="search-navigator-facet-list projects-facet-list"
>
<a
+ aria-label="1"
className="facet search-navigator-facet projects-facet active"
data-key={1}
href="#"
@@ -338,6 +354,7 @@ exports[`renders multiple selected 1`] = `
</span>
</a>
<a
+ aria-label="2"
className="facet search-navigator-facet projects-facet active"
data-key={2}
href="#"
@@ -351,6 +368,7 @@ exports[`renders multiple selected 1`] = `
</span>
</a>
<a
+ aria-label="3"
className="facet search-navigator-facet projects-facet"
data-key={3}
href="#"
@@ -389,6 +407,7 @@ exports[`renders selected 1`] = `
className="search-navigator-facet-list projects-facet-list"
>
<a
+ aria-label="1"
className="facet search-navigator-facet projects-facet"
data-key={1}
href="#"
@@ -402,6 +421,7 @@ exports[`renders selected 1`] = `
</span>
</a>
<a
+ aria-label="2"
className="facet search-navigator-facet projects-facet active"
data-key={2}
href="#"
@@ -415,6 +435,7 @@ exports[`renders selected 1`] = `
</span>
</a>
<a
+ aria-label="3"
className="facet search-navigator-facet projects-facet"
data-key={3}
href="#"
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/IssuesFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/IssuesFilter-test.tsx.snap
index 64e83a0b6a2..d8e685cdb57 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/IssuesFilter-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/IssuesFilter-test.tsx.snap
@@ -19,6 +19,7 @@ exports[`renders 1`] = `
]
}
property="bugs"
+ renderAccessibleLabel={[Function]}
renderOption={[Function]}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/LanguagesFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/LanguagesFilter-test.tsx.snap
index c366f8e6858..4e2ba5f9db3 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/LanguagesFilter-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/LanguagesFilter-test.tsx.snap
@@ -53,6 +53,7 @@ exports[`should render the languages facet with the selected languages 1`] = `
]
}
property="languages"
+ renderAccessibleLabel={[Function]}
renderOption={[Function]}
value={
Array [
@@ -75,6 +76,7 @@ exports[`should render the languages facet with the selected languages 2`] = `
className="search-navigator-facet-list projects-facet-list"
>
<a
+ aria-label="projects.facets.label_text_x.projects.facets.languages.Java"
className="facet search-navigator-facet projects-facet active"
data-key="java"
href="#"
@@ -101,6 +103,7 @@ exports[`should render the languages facet with the selected languages 2`] = `
</span>
</a>
<a
+ aria-label="projects.facets.label_text_x.projects.facets.languages.C#"
className="facet search-navigator-facet projects-facet active"
data-key="cs"
href="#"
@@ -127,6 +130,7 @@ exports[`should render the languages facet with the selected languages 2`] = `
</span>
</a>
<a
+ aria-label="projects.facets.label_text_x.projects.facets.languages.JavaScript"
className="facet search-navigator-facet projects-facet"
data-key="js"
href="#"
@@ -234,6 +238,7 @@ exports[`should render the languages without the ones in the facet 1`] = `
]
}
property="languages"
+ renderAccessibleLabel={[Function]}
renderOption={[Function]}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewLinesFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewLinesFilter-test.tsx.snap
index 6d4b91aa8b8..0997f882a49 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewLinesFilter-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/NewLinesFilter-test.tsx.snap
@@ -21,6 +21,7 @@ exports[`renders 1`] = `
]
}
property="new_lines"
+ renderAccessibleLabel={[Function]}
renderOption={[Function]}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualifierFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualifierFilter-test.tsx.snap
index 78a419e37a4..a4f41ad201c 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualifierFilter-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualifierFilter-test.tsx.snap
@@ -15,6 +15,7 @@ exports[`renders 1`] = `
]
}
property="qualifier"
+ renderAccessibleLabel={[Function]}
renderOption={[Function]}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualityGateFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualityGateFilter-test.tsx.snap
index f886d4bf11d..dccd1856c4e 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualityGateFilter-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/QualityGateFilter-test.tsx.snap
@@ -15,6 +15,7 @@ exports[`renders 1`] = `
]
}
property="gate"
+ renderAccessibleLabel={[Function]}
renderOption={[Function]}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SecurityReviewFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SecurityReviewFilter-test.tsx.snap
index d035ae827e5..9345ad925c2 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SecurityReviewFilter-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SecurityReviewFilter-test.tsx.snap
@@ -30,6 +30,7 @@ exports[`renders 1`] = `
]
}
property="security_review"
+ renderAccessibleLabel={[Function]}
renderOption={[Function]}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SizeFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SizeFilter-test.tsx.snap
index 24fa109ec75..bd9faa3be3e 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SizeFilter-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SizeFilter-test.tsx.snap
@@ -20,6 +20,7 @@ exports[`renders 1`] = `
]
}
property="size"
+ renderAccessibleLabel={[Function]}
renderOption={[Function]}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/TagsFilter-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/TagsFilter-test.tsx.snap
index 8c1830ec284..f9c28886877 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/TagsFilter-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/TagsFilter-test.tsx.snap
@@ -86,6 +86,7 @@ exports[`should render maximum 10 tags in the searchbox results 1`] = `
]
}
property="tags"
+ renderAccessibleLabel={[Function]}
renderOption={[Function]}
value={
Array [
@@ -137,6 +138,7 @@ exports[`should render the tags facet with the selected tags 1`] = `
]
}
property="tags"
+ renderAccessibleLabel={[Function]}
renderOption={[Function]}
value={
Array [
@@ -159,6 +161,7 @@ exports[`should render the tags facet with the selected tags 2`] = `
className="search-navigator-facet-list projects-facet-list"
>
<a
+ aria-label="projects.facets.label_text_x.projects.facets.tags.lang"
className="facet search-navigator-facet projects-facet active"
data-key="lang"
href="#"
@@ -179,6 +182,7 @@ exports[`should render the tags facet with the selected tags 2`] = `
</span>
</a>
<a
+ aria-label="projects.facets.label_text_x.projects.facets.tags.sonar"
className="facet search-navigator-facet projects-facet active"
data-key="sonar"
href="#"
@@ -199,6 +203,7 @@ exports[`should render the tags facet with the selected tags 2`] = `
</span>
</a>
<a
+ aria-label="projects.facets.label_text_x.projects.facets.tags.csharp"
className="facet search-navigator-facet projects-facet"
data-key="csharp"
href="#"
@@ -276,6 +281,7 @@ exports[`should render the tags without the ones in the facet 1`] = `
]
}
property="tags"
+ renderAccessibleLabel={[Function]}
renderOption={[Function]}
/>
`;
@@ -333,6 +339,7 @@ exports[`should render the tags without the ones in the facet 2`] = `
]
}
property="tags"
+ renderAccessibleLabel={[Function]}
renderOption={[Function]}
/>
`;
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
index 95aef3ccd94..de3dc9b4373 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -1064,6 +1064,31 @@ projects.facets.languages=Languages
projects.facets.new_lines=New Lines
projects.facets.tags=Tags
projects.facets.qualifier=Type
+projects.facets.qualitygate_label_x=Click to filter projects with a {0} quality gate.
+projects.facets.rating_label_single_x=Click to filter projects with a {0} rating of {1}.
+projects.facets.rating_label_multi_x=Click to filter projects with a {0} rating of {1} or worse.
+projects.facets.label_no_data_x=Click to filter projects with no {0} data.
+projects.facets.label_text_x=Click to filter projects by {0}: {1}
+projects.facets.size.label.1=Click to filter projects with fewer than 1k lines of code
+projects.facets.size.label.2=Click to filter projects with 1k lines of code or more
+projects.facets.size.label.3=Click to filter projects with 10k lines of code or more
+projects.facets.size.label.4=Click to filter projects with 100k lines of code or more
+projects.facets.size.label.5=Click to filter projects with more than 500k lines of code
+projects.facets.new_lines.label.1=Click to filter projects with fewer than 1k new lines
+projects.facets.new_lines.label.2=Click to filter projects with 1k new lines or more
+projects.facets.new_lines.label.3=Click to filter projects with 10k new lines or more
+projects.facets.new_lines.label.4=Click to filter projects with 100k new lines or more
+projects.facets.new_lines.label.5=Click to filter projects with more than 500k new lines
+projects.facets.coverage.label.1=Click to filter projects with more than 80% coverage
+projects.facets.coverage.label.2=Click to filter projects with less than 80% coverage
+projects.facets.coverage.label.3=Click to filter projects with less than 70% coverage
+projects.facets.coverage.label.4=Click to filter projects with less than 50% coverage
+projects.facets.coverage.label.5=Click to filter projects with less than 30% coverage
+projects.facets.duplication.label.1=Click to filter projects with less than 3% duplication
+projects.facets.duplication.label.2=Click to filter projects with more than 3% duplication
+projects.facets.duplication.label.3=Click to filter projects with more than 5% duplication
+projects.facets.duplication.label.4=Click to filter projects with more than 10% duplication
+projects.facets.duplication.label.5=Click to filter projects with more than 20% duplication
projects.sort.disabled=Disabled because sorting cannot affect the displayed result with the current project selection.
projects.sort.analysis_date=by last analysis date (oldest first)
projects.sort.-analysis_date=by last analysis date (latest first)