diff options
author | Grégoire Aubert <gregoire.aubert@sonarsource.com> | 2017-05-31 09:14:53 +0200 |
---|---|---|
committer | Grégoire Aubert <gregoire.aubert@sonarsource.com> | 2017-06-09 08:26:48 +0200 |
commit | 496722a869978d384b7b0d9bbbe77663417ee9a2 (patch) | |
tree | bcb151c44d091268450ce0ab4ccbc384e716b3c4 /server/sonar-web/src | |
parent | 054a6910c49b67d45f1152e8689dd507d5a5d1be (diff) | |
download | sonarqube-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')
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%)); + } } } } |