diff options
author | Grégoire Aubert <gregoire.aubert@sonarsource.com> | 2018-08-21 11:31:32 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2018-09-19 10:51:41 +0200 |
commit | 1b6dcc529ae3ef54db0cfe7ac80c926d20799d56 (patch) | |
tree | fe41e3815cf2d343ac34a3d6a45643707508e4c9 /server | |
parent | 0ba8c56c9a7cddf225720f224e66b267f9bbf528 (diff) | |
download | sonarqube-1b6dcc529ae3ef54db0cfe7ac80c926d20799d56.tar.gz sonarqube-1b6dcc529ae3ef54db0cfe7ac80c926d20799d56.zip |
SONAR-11164 Add measures page for short-lived branches and PR
Diffstat (limited to 'server')
13 files changed, 267 insertions, 108 deletions
diff --git a/server/sonar-web/src/main/js/apps/component-measures/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/component-measures/__tests__/utils-test.ts index 74987c7eaa5..a3d14ff95c4 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/__tests__/utils-test.ts +++ b/server/sonar-web/src/main/js/apps/component-measures/__tests__/utils-test.ts @@ -102,7 +102,7 @@ describe('groupByDomains', () => { describe('parseQuery', () => { it('should correctly parse the url query', () => { expect(utils.parseQuery({})).toEqual({ - metric: 'project_overview', + metric: utils.DEFAULT_METRIC, selected: '', view: utils.DEFAULT_VIEW }); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/App.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/App.tsx index ff78d3a724a..236c96619a2 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/App.tsx @@ -22,10 +22,21 @@ import * as key from 'keymaster'; import { InjectedRouter } from 'react-router'; import Helmet from 'react-helmet'; import MeasureContentContainer from './MeasureContentContainer'; +import MeasuresEmpty from './MeasuresEmpty'; import MeasureOverviewContainer from './MeasureOverviewContainer'; import Sidebar from '../sidebar/Sidebar'; import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper'; -import { isProjectOverview, hasBubbleChart, parseQuery, serializeQuery, Query } from '../utils'; +import { + isProjectOverview, + hasBubbleChart, + parseQuery, + serializeQuery, + Query, + hasFullMeasures, + getMeasuresPageMetricKeys, + groupByDomains, + sortMeasures +} from '../utils'; import { isSameBranchLike, getBranchLikeQuery } from '../../../helpers/branches'; import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; import { @@ -33,14 +44,13 @@ import { translateWithParameters, translate } from '../../../helpers/l10n'; -import { getDisplayMetrics } from '../../../helpers/measures'; import { RawQuery } from '../../../helpers/query'; import { BranchLike, ComponentMeasure, + CurrentUser, MeasureEnhanced, Metric, - CurrentUser, Period } from '../../../app/types'; import '../../../components/search-navigator.css'; @@ -117,8 +127,8 @@ export default class App extends React.PureComponent<Props, State> { fetchMeasures = ({ branchLike, component, fetchMeasures, metrics }: Props) => { this.setState({ loading: true }); - const filteredKeys = getDisplayMetrics(Object.values(metrics)).map(metric => metric.key); + const filteredKeys = getMeasuresPageMetricKeys(metrics, branchLike); fetchMeasures(component.key, filteredKeys, branchLike).then( ({ measures, leakPeriod }) => { if (this.mounted) { @@ -139,6 +149,34 @@ export default class App extends React.PureComponent<Props, State> { ); }; + getHelmetTitle = (query: Query, displayOverview: boolean, metric?: Metric) => { + if (displayOverview && query.metric) { + return isProjectOverview(query.metric) + ? translate('component_measures.overview.project_overview.facet') + : translateWithParameters( + 'component_measures.domain_x_overview', + getLocalizedMetricDomain(query.metric) + ); + } + return metric ? metric.name : translate('layout.measures'); + }; + + getSelectedMetric = (query: Query, displayOverview: boolean) => { + if (displayOverview) { + return undefined; + } + const metric = this.props.metrics[query.metric]; + if (!metric) { + const domainMeasures = groupByDomains(this.state.measures); + const firstMeasure = + domainMeasures[0] && sortMeasures(domainMeasures[0].name, domainMeasures[0].measures)[0]; + if (firstMeasure && typeof firstMeasure !== 'string') { + return firstMeasure.metric; + } + } + return metric; + }; + updateQuery = (newQuery: Partial<Query>) => { const query = serializeQuery({ ...parseQuery(this.props.location.query), @@ -154,16 +192,51 @@ export default class App extends React.PureComponent<Props, State> { }); }; - getHelmetTitle = (metric?: Metric) => { - if (metric && hasBubbleChart(metric.key)) { - return isProjectOverview(metric.key) - ? translate('component_measures.overview.project_overview.facet') - : translateWithParameters( - 'component_measures.domain_x_overview', - getLocalizedMetricDomain(metric.key) - ); + renderContent = (displayOverview: boolean, query: Query, metric?: Metric) => { + const { branchLike, component, fetchMeasures, metrics } = this.props; + const { leakPeriod, measures } = this.state; + + if (measures.length === 0) { + return <MeasuresEmpty />; } - return metric ? metric.name : translate('layout.measures'); + + if (displayOverview) { + return ( + <MeasureOverviewContainer + branchLike={branchLike} + className="layout-page-main" + currentUser={this.props.currentUser} + domain={query.metric} + leakPeriod={leakPeriod} + metrics={metrics} + rootComponent={component} + router={this.props.router} + selected={query.selected} + updateQuery={this.updateQuery} + /> + ); + } + + if (!metric) { + return <MeasuresEmpty />; + } + + return ( + <MeasureContentContainer + branchLike={branchLike} + className="layout-page-main" + currentUser={this.props.currentUser} + fetchMeasures={fetchMeasures} + leakPeriod={leakPeriod} + metric={metric} + metrics={metrics} + rootComponent={component} + router={this.props.router} + selected={query.selected} + updateQuery={this.updateQuery} + view={query.view} + /> + ); }; render() { @@ -171,14 +244,16 @@ export default class App extends React.PureComponent<Props, State> { if (isLoading) { return <i className="spinner spinner-margin" />; } - const { branchLike, component, fetchMeasures, metrics } = this.props; - const { leakPeriod } = this.state; + const { branchLike } = this.props; + const { measures } = this.state; const query = parseQuery(this.props.location.query); - const metric = metrics[query.metric]; + const hasOverview = hasFullMeasures(branchLike); + const displayOverview = hasOverview && hasBubbleChart(query.metric); + const metric = this.getSelectedMetric(query, displayOverview); return ( <div className="layout-page" id="component-measures"> <Suggestions suggestions="component_measures" /> - <Helmet title={this.getHelmetTitle(metric)} /> + <Helmet title={this.getHelmetTitle(query, displayOverview, metric)} /> <ScreenPositionHelper className="layout-page-side-outer"> {({ top }) => ( @@ -186,8 +261,9 @@ export default class App extends React.PureComponent<Props, State> { <div className="layout-page-side-inner"> <div className="layout-page-filters"> <Sidebar - measures={this.state.measures} - selectedMetric={query.metric} + hasOverview={hasOverview} + measures={measures} + selectedMetric={metric ? metric.key : query.metric} updateQuery={this.updateQuery} /> </div> @@ -196,37 +272,7 @@ export default class App extends React.PureComponent<Props, State> { )} </ScreenPositionHelper> - {metric && ( - <MeasureContentContainer - branchLike={branchLike} - className="layout-page-main" - currentUser={this.props.currentUser} - fetchMeasures={fetchMeasures} - leakPeriod={leakPeriod} - metric={metric} - metrics={metrics} - rootComponent={component} - router={this.props.router} - selected={query.selected} - updateQuery={this.updateQuery} - view={query.view} - /> - )} - {!metric && - hasBubbleChart(query.metric) && ( - <MeasureOverviewContainer - branchLike={branchLike} - className="layout-page-main" - currentUser={this.props.currentUser} - domain={query.metric} - leakPeriod={leakPeriod} - metrics={metrics} - rootComponent={component} - router={this.props.router} - selected={query.selected} - updateQuery={this.updateQuery} - /> - )} + {this.renderContent(displayOverview, query, metric)} </div> ); } diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.tsx index 61840e12d62..2d524d52332 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.tsx @@ -28,7 +28,8 @@ import Tooltip from '../../../components/controls/Tooltip'; import { getLocalizedMetricName, translate } from '../../../helpers/l10n'; import { getMeasureHistoryUrl } from '../../../helpers/urls'; import { isDiffMetric } from '../../../helpers/measures'; -import { MeasureEnhanced, Metric, ComponentMeasure, BranchLike, Period } from '../../../app/types'; +import { BranchLike, ComponentMeasure, MeasureEnhanced, Metric, Period } from '../../../app/types'; +import { hasFullMeasures } from '../utils'; interface Props { branchLike?: BranchLike; @@ -42,7 +43,9 @@ interface Props { export default function MeasureHeader(props: Props) { const { branchLike, component, leakPeriod, measure, metric, secondaryMeasure } = props; const isDiff = isDiffMetric(metric.key); - const hasHistory = component.qualifier !== 'FIL' && component.qualifier !== 'UTS'; + const hasHistory = + component.qualifier !== 'FIL' && component.qualifier !== 'UTS' && hasFullMeasures(branchLike); + const displayLeak = hasFullMeasures(branchLike); return ( <div className="measure-details-header big-spacer-bottom"> <div className="measure-details-primary"> @@ -79,9 +82,10 @@ export default function MeasureHeader(props: Props) { )} </div> <div className="measure-details-primary-actions"> - {leakPeriod && ( - <LeakPeriodLegend className="spacer-left" component={component} period={leakPeriod} /> - )} + {displayLeak && + leakPeriod && ( + <LeakPeriodLegend className="spacer-left" component={component} period={leakPeriod} /> + )} </div> </div> {secondaryMeasure && diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasuresEmpty.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/MeasuresEmpty.tsx new file mode 100644 index 00000000000..ea25a2d2f69 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasuresEmpty.tsx @@ -0,0 +1,29 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info 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 * as React from 'react'; +import { translate } from '../../../helpers/l10n'; + +export default function MeasuresEmpty() { + return ( + <div className="layout-page-main"> + <div className="note text-center">{translate('component_measures.empty')}</div> + </div> + ); +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.tsx index f0202595073..c6505527b5e 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.tsx @@ -21,6 +21,7 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import App from '../App'; +import { waitAndUpdate } from '../../../../helpers/testUtils'; const COMPONENT = { key: 'foo', name: 'Foo', qualifier: 'TRK' }; @@ -48,21 +49,24 @@ const PROPS = { component: COMPONENT, currentUser: { isLoggedIn: false }, location: { pathname: '/component_measures', query: { metric: 'coverage' } }, - fetchMeasures: jest.fn().mockResolvedValue({ component: COMPONENT, measures: [] }), + fetchMeasures: jest.fn().mockResolvedValue({ + component: COMPONENT, + measures: [{ metric: 'coverage', value: '80.0' }] + }), fetchMetrics: jest.fn(), metrics: METRICS, metricsKey: ['lines_to_cover', 'coverage', 'duplicated_lines_density', 'new_bugs'], router: { push: jest.fn() } as any }; -it('should render correctly', () => { +it('should render correctly', async () => { const wrapper = shallow(<App {...PROPS} />); expect(wrapper.find('.spinner')).toHaveLength(1); - wrapper.setState({ loading: false }); + await waitAndUpdate(wrapper); expect(wrapper).toMatchSnapshot(); }); -it('should render a measure overview', () => { +it('should render a measure overview', async () => { const wrapper = shallow( <App {...PROPS} @@ -70,6 +74,6 @@ it('should render a measure overview', () => { /> ); expect(wrapper.find('.spinner')).toHaveLength(1); - wrapper.setState({ loading: false }); + await waitAndUpdate(wrapper); expect(wrapper.find('MeasureOverviewContainer')).toHaveLength(1); }); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/MeasureHeader-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/MeasureHeader-test.tsx index 965af1b5474..2df222654bd 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/MeasureHeader-test.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/MeasureHeader-test.tsx @@ -81,10 +81,24 @@ it('should render correctly for leak', () => { ).toMatchSnapshot(); }); -it('should render with branch', () => { - const shortBranch = { isMain: false, name: 'feature', mergeBranch: '', type: 'SHORT' }; +it('should render with long living branch', () => { + const longBranch = { isMain: false, name: 'branch-6.7', type: 'LONG' }; expect( - shallow(<MeasureHeader branchLike={shortBranch} {...PROPS} />).find('Link') + shallow(<MeasureHeader branchLike={longBranch} {...PROPS} />).find('Link') + ).toMatchSnapshot(); +}); + +it('should render with short living branch', () => { + const shortBranch = { isMain: false, name: 'feature', mergeBranch: 'master', type: 'SHORT' }; + expect( + shallow( + <MeasureHeader + {...PROPS} + branchLike={shortBranch} + measure={LEAK_MEASURE} + metric={LEAK_METRIC} + /> + ) ).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.tsx.snap index 2ccafb98328..c74f60aa659 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.tsx.snap @@ -128,7 +128,7 @@ exports[`should render correctly for leak 1`] = ` </div> `; -exports[`should render with branch 1`] = ` +exports[`should render with long living branch 1`] = ` <Link className="js-show-history spacer-left button button-small" onlyActiveOnIndex={false} @@ -137,7 +137,7 @@ exports[`should render with branch 1`] = ` Object { "pathname": "/project/activity", "query": Object { - "branch": "feature", + "branch": "branch-6.7", "custom_metrics": "reliability_rating", "graph": "custom", "id": "foo", @@ -149,6 +149,41 @@ exports[`should render with branch 1`] = ` </Link> `; +exports[`should render with short living branch 1`] = ` +<div + className="measure-details-header big-spacer-bottom" +> + <div + className="measure-details-primary" + > + <div + className="measure-details-metric" + > + <IssueTypeIcon + className="little-spacer-right text-text-bottom" + query="new_reliability_rating" + /> + Reliability Rating on New Code + <span + className="measure-details-value spacer-left" + > + <strong> + <Measure + className="domain-measures-leak" + metricKey="new_reliability_rating" + metricType="RATING" + value="3.0" + /> + </strong> + </span> + </div> + <div + className="measure-details-primary-actions" + /> + </div> +</div> +`; + exports[`should work with measure without value 1`] = ` <div className="measure-details-header big-spacer-bottom" diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.tsx b/server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.tsx index 3257089235c..2b62fbeccbb 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.tsx @@ -41,6 +41,7 @@ import { MeasureEnhanced } from '../../../app/types'; interface Props { domain: { name: string; measures: MeasureEnhanced[] }; + hasOverview: boolean; onChange: (metric: string) => void; onToggle: (property: string) => void; open: boolean; @@ -48,24 +49,28 @@ interface Props { } export default class DomainFacet extends React.PureComponent<Props> { + getValues = () => { + const { domain, selected } = this.props; + const measureSelected = domain.measures.find(measure => measure.metric.key === selected); + const overviewSelected = domain.name === selected && this.hasOverview(domain.name); + if (measureSelected) { + return [getLocalizedMetricName(measureSelected.metric)]; + } + return overviewSelected ? [translate('component_measures.domain_overview')] : []; + }; + handleHeaderClick = () => { this.props.onToggle(this.props.domain.name); }; hasFacetSelected = (domain: { name: string }, measures: MeasureEnhanced[], selected: string) => { const measureSelected = measures.find(measure => measure.metric.key === selected); - const overviewSelected = domain.name === selected && hasBubbleChart(domain.name); + const overviewSelected = domain.name === selected && this.hasOverview(domain.name); return measureSelected || overviewSelected; }; - getValues = () => { - const { domain, selected } = this.props; - const measureSelected = domain.measures.find(measure => measure.metric.key === selected); - const overviewSelected = domain.name === selected && hasBubbleChart(domain.name); - if (measureSelected) { - return [getLocalizedMetricName(measureSelected.metric)]; - } - return overviewSelected ? [translate('component_measures.domain_overview')] : []; + hasOverview = (domain: string) => { + return this.props.hasOverview && hasBubbleChart(domain); }; renderItemFacetStat = (item: MeasureEnhanced) => { @@ -115,7 +120,7 @@ export default class DomainFacet extends React.PureComponent<Props> { renderOverviewFacet = () => { const { domain, selected } = this.props; - if (!hasBubbleChart(domain.name)) { + if (!this.hasOverview(domain.name)) { return null; } return ( diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.tsx b/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.tsx index 027d3593f4f..09683497982 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.tsx @@ -24,9 +24,10 @@ import { getDefaultView, groupByDomains, KNOWN_DOMAINS, PROJECT_OVERVEW, Query } import { MeasureEnhanced } from '../../../app/types'; interface Props { + hasOverview: boolean; measures: MeasureEnhanced[]; selectedMetric: string; - updateQuery: (query: Query) => void; + updateQuery: (query: Partial<Query>) => void; } interface State { @@ -73,16 +74,20 @@ export default class Sidebar extends React.PureComponent<Props, State> { this.props.updateQuery({ metric, ...this.resetSelection(metric) }); render() { + const { hasOverview } = this.props; return ( <div> - <ProjectOverviewFacet - onChange={this.changeMetric} - selected={this.props.selectedMetric} - value={PROJECT_OVERVEW} - /> + {hasOverview && ( + <ProjectOverviewFacet + onChange={this.changeMetric} + selected={this.props.selectedMetric} + value={PROJECT_OVERVEW} + /> + )} {groupByDomains(this.props.measures).map(domain => ( <DomainFacet domain={domain} + hasOverview={hasOverview} key={domain.name} onChange={this.changeMetric} onToggle={this.toggleFacet} diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/DomainFacet-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/DomainFacet-test.tsx index 590536b454c..1c90ccf475e 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/DomainFacet-test.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/DomainFacet-test.tsx @@ -51,10 +51,11 @@ const DOMAIN = { }; const PROPS = { + domain: DOMAIN, + hasOverview: true, onChange: () => {}, onToggle: () => {}, open: true, - domain: DOMAIN, selected: 'foo' }; @@ -71,6 +72,16 @@ it('should render closed', () => { expect(wrapper.find('FacetItemsList')).toHaveLength(0); }); +it('should render without overview', () => { + const wrapper = shallow(<DomainFacet {...PROPS} hasOverview={false} />); + expect( + wrapper + .find('FacetItem') + .filterWhere(node => node.getElement().key === 'Reliability') + .exists() + ).toBe(false); +}); + it('should not display subtitles of new measures if there is none', () => { const domain = { name: 'Reliability', @@ -82,17 +93,7 @@ it('should not display subtitles of new measures if there is none', () => { ] }; - expect( - shallow( - <DomainFacet - domain={domain} - onChange={() => {}} - onToggle={() => {}} - open={true} - selected={'foo'} - /> - ) - ).toMatchSnapshot(); + expect(shallow(<DomainFacet {...PROPS} domain={domain} />)).toMatchSnapshot(); }); it('should not display subtitles of new measures if there is none, even on last line', () => { @@ -106,15 +107,5 @@ it('should not display subtitles of new measures if there is none, even on last ] }; - expect( - shallow( - <DomainFacet - domain={domain} - onChange={() => {}} - onToggle={() => {}} - open={true} - selected={'foo'} - /> - ) - ).toMatchSnapshot(); + expect(shallow(<DomainFacet {...PROPS} domain={domain} />)).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/Sidebar-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/Sidebar-test.tsx index 9b629994ac3..4814927ffe5 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/Sidebar-test.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/Sidebar-test.tsx @@ -61,6 +61,7 @@ const MEASURES = [ ]; const PROPS = { + hasOverview: true, measures: MEASURES, selectedMetric: 'duplicated_lines_density', updateQuery: () => {} diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap index 09f7788831c..d626c8f7948 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap @@ -49,6 +49,7 @@ exports[`should display two facets 1`] = ` "name": "Coverage", } } + hasOverview={true} key="Coverage" onChange={[Function]} onToggle={[Function]} @@ -80,6 +81,7 @@ exports[`should display two facets 1`] = ` "name": "Duplications", } } + hasOverview={true} key="Duplications" onChange={[Function]} onToggle={[Function]} diff --git a/server/sonar-web/src/main/js/apps/component-measures/utils.ts b/server/sonar-web/src/main/js/apps/component-measures/utils.ts index 74befd184f0..26b41a1a503 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/utils.ts +++ b/server/sonar-web/src/main/js/apps/component-measures/utils.ts @@ -25,10 +25,13 @@ import { ComponentMeasure, ComponentMeasureEnhanced, Metric, - MeasureEnhanced + MeasureEnhanced, + BranchLike } from '../../app/types'; import { enhanceMeasure } from '../../components/measure/utils'; import { cleanQuery, parseAsString, RawQuery, serializeString } from '../../helpers/query'; +import { isLongLivingBranch, isMainBranch } from '../../helpers/branches'; +import { getDisplayMetrics } from '../../helpers/measures'; export const PROJECT_OVERVEW = 'project_overview'; export const DEFAULT_VIEW = 'list'; @@ -146,13 +149,33 @@ export function hasTreemap(metric: string, type: string): boolean { } export function hasBubbleChart(domainName: string): boolean { - return bubbles[domainName] != null; + return bubbles[domainName] !== undefined; } export function hasFacetStat(metric: string): boolean { return metric !== 'alert_status'; } +export function hasFullMeasures(branch?: BranchLike) { + return !branch || isLongLivingBranch(branch) || isMainBranch(branch); +} + +export function getMeasuresPageMetricKeys(metrics: { [key: string]: Metric }, branch?: BranchLike) { + if (!hasFullMeasures(branch)) { + return [ + 'new_coverage', + 'new_lines_to_cover', + 'new_uncovered_lines', + 'new_line_coverage', + 'new_conditions_to_cover', + 'new_uncovered_conditions', + 'new_branch_coverage' + ]; + } + + return getDisplayMetrics(Object.values(metrics)).map(metric => metric.key); +} + export function getBubbleMetrics(domain: string, metrics: { [key: string]: Metric }) { const conf = bubbles[domain]; return { @@ -182,7 +205,7 @@ const parseView = (metric: string, rawView?: string) => { }; export interface Query { - metric?: string; + metric: string; selected?: string; view: string; } |