aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-05-31 09:14:53 +0200
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-06-09 08:26:48 +0200
commit496722a869978d384b7b0d9bbbe77663417ee9a2 (patch)
treebcb151c44d091268450ce0ab4ccbc384e716b3c4 /server/sonar-web/src
parent054a6910c49b67d45f1152e8689dd507d5a5d1be (diff)
downloadsonarqube-496722a869978d384b7b0d9bbbe77663417ee9a2.tar.gz
sonarqube-496722a869978d384b7b0d9bbbe77663417ee9a2.zip
SONAR-9260 Add the new No Data filter to Coverage and Duplication facets on projects page
Diffstat (limited to 'server/sonar-web/src')
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.js20
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.js20
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/Filter.js46
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.js1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.js1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.js1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/LanguagesFilter-test.js.snap6
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/TagsFilter-test.js.snap7
-rw-r--r--server/sonar-web/src/main/js/apps/projects/store/utils.js6
-rw-r--r--server/sonar-web/src/main/js/apps/projects/styles.css2
-rw-r--r--server/sonar-web/src/main/less/components/search-navigator.less92
11 files changed, 120 insertions, 82 deletions
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.js b/server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.js
index f4a101535e3..2440b2e7541 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.js
+++ b/server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.js
@@ -38,20 +38,23 @@ export default class CoverageFilter extends React.PureComponent {
};
getFacetValueForOption(facet, option) {
- const map = ['80.0-*', '70.0-80.0', '50.0-70.0', '30.0-50.0', '*-30.0'];
+ const map = ['80.0-*', '70.0-80.0', '50.0-70.0', '30.0-50.0', '*-30.0', 'NO_DATA'];
return facet[map[option - 1]];
}
renderOption(option, selected) {
return (
<span>
- <CoverageRating
- value={getCoverageRatingAverageValue(option)}
- size="small"
- muted={!selected}
- />
+ {option < 6 &&
+ <CoverageRating
+ value={getCoverageRatingAverageValue(option)}
+ size="small"
+ muted={!selected}
+ />}
<span className="spacer-left">
- {getCoverageRatingLabel(option)}
+ {option < 6
+ ? getCoverageRatingLabel(option)
+ : <span className="big-spacer-left">{translate('no_data')}</span>}
</span>
</span>
);
@@ -62,13 +65,14 @@ export default class CoverageFilter extends React.PureComponent {
<FilterContainer
property={this.props.property}
className={this.props.className}
- options={[1, 2, 3, 4, 5]}
+ options={[1, 2, 3, 4, 5, 6]}
query={this.props.query}
renderOption={this.renderOption}
isFavorite={this.props.isFavorite}
organization={this.props.organization}
getFacetValueForOption={this.getFacetValueForOption}
highlightUnder={1}
+ highlightUnderMax={5}
header={<FilterHeader name={translate('metric_domain.Coverage')} />}
/>
);
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.js b/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.js
index 609b3388a05..371da910a82 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.js
+++ b/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.js
@@ -41,20 +41,23 @@ export default class DuplicationsFilter extends React.PureComponent {
};
getFacetValueForOption(facet, option) {
- const map = ['*-3.0', '3.0-5.0', '5.0-10.0', '10.0-20.0', '20.0-*'];
+ const map = ['*-3.0', '3.0-5.0', '5.0-10.0', '10.0-20.0', '20.0-*', 'NO_DATA'];
return facet[map[option - 1]];
}
renderOption(option, selected) {
return (
<span>
- <DuplicationsRating
- value={getDuplicationsRatingAverageValue(option)}
- size="small"
- muted={!selected}
- />
+ {option < 6 &&
+ <DuplicationsRating
+ value={getDuplicationsRatingAverageValue(option)}
+ size="small"
+ muted={!selected}
+ />}
<span className="spacer-left">
- {getDuplicationsRatingLabel(option)}
+ {option < 6
+ ? getDuplicationsRatingLabel(option)
+ : <span className="big-spacer-left">{translate('no_data')}</span>}
</span>
</span>
);
@@ -65,13 +68,14 @@ export default class DuplicationsFilter extends React.PureComponent {
<FilterContainer
property={this.props.property}
className={this.props.className}
- options={[1, 2, 3, 4, 5]}
+ options={[1, 2, 3, 4, 5, 6]}
query={this.props.query}
renderOption={this.renderOption}
isFavorite={this.props.isFavorite}
organization={this.props.organization}
getFacetValueForOption={this.getFacetValueForOption}
highlightUnder={1}
+ highlightUnderMax={5}
header={<FilterHeader name={translate('metric_domain.Duplications')} />}
/>
);
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/Filter.js b/server/sonar-web/src/main/js/apps/projects/filters/Filter.js
index 68073fa0823..bdc9fc66948 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/Filter.js
+++ b/server/sonar-web/src/main/js/apps/projects/filters/Filter.js
@@ -43,6 +43,7 @@ export default class Filter extends React.PureComponent {
halfWidth: React.PropTypes.bool,
highlightUnder: React.PropTypes.number,
+ highlightUnderMax: React.PropTypes.number,
header: React.PropTypes.object,
footer: React.PropTypes.object
@@ -59,10 +60,15 @@ export default class Filter extends React.PureComponent {
highlightUnder(option) {
return (
- this.props.highlightUnder != null && option !== null && option > this.props.highlightUnder
+ this.props.highlightUnder != null &&
+ option !== null &&
+ option > this.props.highlightUnder &&
+ (this.props.highlightUnderMax == null || option < this.props.highlightUnderMax)
);
}
+ blurOnClick = (evt: Event & { currentTarget: HTMLElement }) => evt.currentTarget.blur();
+
getPath(option) {
const { property, value } = this.props;
let urlOption;
@@ -101,8 +107,7 @@ export default class Filter extends React.PureComponent {
'projects-facet',
{
active: this.isSelected(option),
- 'search-navigator-facet-half': this.props.halfWidth,
- 'search-navigator-facet-highlight-under': this.highlightUnder(option)
+ 'search-navigator-facet-half': this.props.halfWidth
},
this.props.optionClassName
);
@@ -115,7 +120,12 @@ export default class Filter extends React.PureComponent {
const isUnderSelectedOption = this.highlightUnder(value) && option > value;
return (
- <Link key={option} className={className} to={path} data-key={option}>
+ <Link
+ key={option}
+ className={className}
+ to={path}
+ data-key={option}
+ onClick={this.blurOnClick}>
<span className="facet-name">
{this.props.renderOption(option, this.isSelected(option) || isUnderSelectedOption)}
</span>
@@ -129,13 +139,29 @@ export default class Filter extends React.PureComponent {
}
renderOptions() {
- const { options } = this.props;
+ const { options, highlightUnder } = this.props;
if (options && options.length > 0) {
- return (
- <div className="search-navigator-facet-list">
- {options.map(option => this.renderOption(option))}
- </div>
- );
+ if (highlightUnder != null) {
+ const max = this.props.highlightUnderMax || options.length;
+ const beforeHighlight = options.slice(0, highlightUnder);
+ const insideHighlight = options.slice(highlightUnder, max);
+ const afterHighlight = options.slice(max);
+ return (
+ <div className="search-navigator-facet-list">
+ {beforeHighlight.map(option => this.renderOption(option))}
+ <div className="search-navigator-facet-highlight-under-container">
+ {insideHighlight.map(option => this.renderOption(option))}
+ </div>
+ {afterHighlight.map(option => this.renderOption(option))}
+ </div>
+ );
+ } else {
+ return (
+ <div className="search-navigator-facet-list">
+ {options.map(option => this.renderOption(option))}
+ </div>
+ );
+ }
} else {
return (
<div className="search-navigator-facet-empty">
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.js b/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.js
index 4218dbc3f26..c266641d6b7 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.js
+++ b/server/sonar-web/src/main/js/apps/projects/filters/LanguagesFilter.js
@@ -81,7 +81,6 @@ export default class LanguagesFilter extends React.PureComponent {
isFavorite={this.props.isFavorite}
organization={this.props.organization}
getFacetValueForOption={this.getFacetValueForOption}
- highlightUnder={1}
header={<FilterHeader name={translate('projects.facets.languages')} />}
footer={
<SearchableFilterFooter
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.js b/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.js
index 0df57464933..348a3b199d6 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.js
+++ b/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.js
@@ -48,7 +48,6 @@ export default class QualityGateFilter extends React.PureComponent {
isFavorite={this.props.isFavorite}
organization={this.props.organization}
getFacetValueForOption={this.getFacetValueForOption}
- highlightUnder={1}
header={<FilterHeader name={translate('projects.facets.quality_gate')} />}
/>
);
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.js b/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.js
index 05f795cbd50..28add5b703b 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.js
+++ b/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.js
@@ -104,7 +104,6 @@ export default class TagsFilter extends React.PureComponent {
isFavorite={this.props.isFavorite}
organization={this.props.organization}
getFacetValueForOption={this.getFacetValueForOption}
- highlightUnder={1}
header={<FilterHeader name={translate('projects.facets.tags')} />}
footer={
<SearchableFilterFooter
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/LanguagesFilter-test.js.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/LanguagesFilter-test.js.snap
index 1605a2de810..fdfa7f616bf 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/LanguagesFilter-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/LanguagesFilter-test.js.snap
@@ -80,7 +80,6 @@ exports[`should render maximum 10 languages in the searchbox results 1`] = `
name="projects.facets.languages"
/>
}
- highlightUnder={1}
isFavorite={true}
options={
Array [
@@ -160,7 +159,6 @@ exports[`should render the languages facet with the selected languages 1`] = `
name="projects.facets.languages"
/>
}
- highlightUnder={1}
isFavorite={true}
options={
Array [
@@ -202,6 +200,7 @@ exports[`should render the languages facet with the selected languages 2`] = `
<Link
className="facet search-navigator-facet projects-facet active"
data-key="java"
+ onClick={[Function]}
onlyActiveOnIndex={false}
style={Object {}}
to={
@@ -235,6 +234,7 @@ exports[`should render the languages facet with the selected languages 2`] = `
<Link
className="facet search-navigator-facet projects-facet active"
data-key="cs"
+ onClick={[Function]}
onlyActiveOnIndex={false}
style={Object {}}
to={
@@ -268,6 +268,7 @@ exports[`should render the languages facet with the selected languages 2`] = `
<Link
className="facet search-navigator-facet projects-facet"
data-key="js"
+ onClick={[Function]}
onlyActiveOnIndex={false}
style={Object {}}
to={
@@ -382,7 +383,6 @@ exports[`should render the languages without the ones in the facet 1`] = `
name="projects.facets.languages"
/>
}
- highlightUnder={1}
options={
Array [
"java",
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/TagsFilter-test.js.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/TagsFilter-test.js.snap
index 1cadc1ba2e8..94e9405e998 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/TagsFilter-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/TagsFilter-test.js.snap
@@ -83,7 +83,6 @@ exports[`should render maximum 10 tags in the searchbox results 1`] = `
name="projects.facets.tags"
/>
}
- highlightUnder={1}
isFavorite={true}
options={
Array [
@@ -151,7 +150,6 @@ exports[`should render the tags facet with the selected tags 1`] = `
name="projects.facets.tags"
/>
}
- highlightUnder={1}
isFavorite={true}
options={
Array [
@@ -193,6 +191,7 @@ exports[`should render the tags facet with the selected tags 2`] = `
<Link
className="facet search-navigator-facet projects-facet active"
data-key="lang"
+ onClick={[Function]}
onlyActiveOnIndex={false}
style={Object {}}
to={
@@ -220,6 +219,7 @@ exports[`should render the tags facet with the selected tags 2`] = `
<Link
className="facet search-navigator-facet projects-facet active"
data-key="sonar"
+ onClick={[Function]}
onlyActiveOnIndex={false}
style={Object {}}
to={
@@ -247,6 +247,7 @@ exports[`should render the tags facet with the selected tags 2`] = `
<Link
className="facet search-navigator-facet projects-facet"
data-key="csharp"
+ onClick={[Function]}
onlyActiveOnIndex={false}
style={Object {}}
to={
@@ -331,7 +332,6 @@ exports[`should render the tags without the ones in the facet 1`] = `
name="projects.facets.tags"
/>
}
- highlightUnder={1}
options={
Array [
"lang",
@@ -399,7 +399,6 @@ exports[`should render the tags without the ones in the facet 2`] = `
name="projects.facets.tags"
/>
}
- highlightUnder={1}
options={
Array [
"lang",
diff --git a/server/sonar-web/src/main/js/apps/projects/store/utils.js b/server/sonar-web/src/main/js/apps/projects/store/utils.js
index 2fdac846544..4c383fe8d0c 100644
--- a/server/sonar-web/src/main/js/apps/projects/store/utils.js
+++ b/server/sonar-web/src/main/js/apps/projects/store/utils.js
@@ -24,7 +24,7 @@ const getAsNumericRating = value => {
return null;
}
const num = Number(value);
- return num > 0 && num < 6 ? num : null;
+ return num > 0 && num < 7 ? num : null;
};
const getAsLevel = value => {
@@ -142,6 +142,8 @@ const convertCoverage = (metric, coverage) => {
return metric + ' < 50';
case 5:
return metric + ' < 30';
+ case 6:
+ return metric + '= NO_DATA';
default:
return '';
}
@@ -159,6 +161,8 @@ const convertDuplications = (metric, duplications) => {
return metric + ' >= 10';
case 5:
return metric + ' >= 20';
+ case 6:
+ return metric + '= NO_DATA';
default:
return '';
}
diff --git a/server/sonar-web/src/main/js/apps/projects/styles.css b/server/sonar-web/src/main/js/apps/projects/styles.css
index 11b1a7b4665..0cb08e097d1 100644
--- a/server/sonar-web/src/main/js/apps/projects/styles.css
+++ b/server/sonar-web/src/main/js/apps/projects/styles.css
@@ -267,7 +267,7 @@
}
.search-navigator-facet.active .projects-facet-bar-inner,
-.search-navigator-facet-highlight-under.active ~ .search-navigator-facet .projects-facet-bar-inner {
+.search-navigator-facet-highlight-under-container .search-navigator-facet.active ~ .search-navigator-facet .projects-facet-bar-inner {
background-color: #4b9fd5;
}
diff --git a/server/sonar-web/src/main/less/components/search-navigator.less b/server/sonar-web/src/main/less/components/search-navigator.less
index 23c8a7b3ff4..c108d700e3c 100644
--- a/server/sonar-web/src/main/less/components/search-navigator.less
+++ b/server/sonar-web/src/main/less/components/search-navigator.less
@@ -262,66 +262,70 @@
}
}
-.search-navigator-facet-highlight-under {
- margin-bottom: 0;
-
- &:hover, &.active {
- border-bottom: none;
- padding-bottom: 4px;
- border-radius: 2px 2px 0 0;
-
- & ~ .search-navigator-facet {
- padding-left: 5px;
- padding-right: 5px;
- border-left: 1px solid @blue;
- border-right: 1px solid @blue;
- border-radius: 0;
-
- .facet-stat {
- right: -1px;
+.search-navigator-facet-highlight-under-container {
+ margin-bottom: 1px;
+
+ .search-navigator-facet {
+ margin-bottom: 0;
+
+ &:hover, &.active {
+ border-bottom: none;
+ padding-bottom: 4px;
+ border-radius: 2px 2px 0 0;
+
+ & ~ .search-navigator-facet {
+ padding-left: 5px;
+ padding-right: 5px;
+ border-left: 1px solid @blue;
+ border-right: 1px solid @blue;
+ border-radius: 0;
+
+ .facet-stat {
+ right: -1px;
+ }
+
+ &:last-of-type {
+ padding-bottom: 3px;
+ border-bottom: 1px solid @blue;
+ border-radius: 0 0 2px 2px;
+ }
}
&:last-of-type {
padding-bottom: 3px;
border-bottom: 1px solid @blue;
- border-radius: 0 0 2px 2px;
+ border-radius: 2px;
}
}
- &:last-of-type {
- padding-bottom: 3px;
- border-bottom: 1px solid @blue;
- border-radius: 2px;
- }
- }
-
- .selectFacet(@bgColor) {
- background-color: @bgColor;
- text-decoration: none;
-
- .facet-name {
+ .selectFacet(@bgColor) {
background-color: @bgColor;
- }
+ text-decoration: none;
- .facet-stat {
- border-color: @blue;
- background-color: @bgColor;
+ .facet-name {
+ background-color: @bgColor;
+ }
+
+ .facet-stat {
+ border-color: @blue;
+ background-color: @bgColor;
- &:before {
- background-image: linear-gradient(to right, fade(@bgColor, 0%), @bgColor 75%);
+ &:before {
+ background-image: linear-gradient(to right, fade(@bgColor, 0%), @bgColor 75%);
+ }
}
- }
- .facet-toggle {
- display: inline;
+ .facet-toggle {
+ display: inline;
+ }
}
- }
- &.active ~ .search-navigator-facet {
- .selectFacet(@lightBlue);
+ &.active ~ .search-navigator-facet {
+ .selectFacet(@lightBlue);
- &:hover, &:hover ~ .search-navigator-facet {
- .selectFacet(darken(@lightBlue, 10%));
+ &:hover, &:hover ~ .search-navigator-facet {
+ .selectFacet(darken(@lightBlue, 10%));
+ }
}
}
}