diff options
author | Pascal Mugnier <pascal.mugnier@sonarsource.com> | 2018-03-27 09:14:32 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2018-03-29 20:20:48 +0200 |
commit | 875989e8d4b6853efbfcfd2d4e8b8dfccde8c0b4 (patch) | |
tree | 99a792aa50dce469316de19076aab433f3eb8784 | |
parent | 7b15de3a21d82c63dd253629823b66d1d12be136 (diff) | |
download | sonarqube-875989e8d4b6853efbfcfd2d4e8b8dfccde8c0b4.tar.gz sonarqube-875989e8d4b6853efbfcfd2d4e8b8dfccde8c0b4.zip |
SONAR-10486 Display badges for applications
11 files changed, 189 insertions, 79 deletions
diff --git a/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx b/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx index e666f5cb5c3..da458f1b014 100644 --- a/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx +++ b/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx @@ -34,6 +34,7 @@ interface Props { metrics: { [key: string]: Metric }; onSonarCloud: boolean; project: string; + qualifier: string; } interface State { @@ -66,7 +67,7 @@ export default class BadgesModal extends React.PureComponent<Props, State> { }; render() { - const { branchLike, project } = this.props; + const { branchLike, project, qualifier } = this.props; const { selectedType, badgeOptions } = this.state; const header = translate('overview.badges.title'); const fullBadgeOptions = { project, ...badgeOptions, ...getBranchLikeQuery(branchLike) }; @@ -76,7 +77,7 @@ export default class BadgesModal extends React.PureComponent<Props, State> { return ( <div className="overview-meta-card"> <Button className="js-project-badges" onClick={this.handleOpen}> - {translate('overview.badges.get_badge')} + {translate('overview.badges.get_badge', qualifier)} </Button> {this.state.open && ( <Modal contentLabel={header} onRequestClose={this.handleClose}> @@ -84,7 +85,9 @@ export default class BadgesModal extends React.PureComponent<Props, State> { <h2>{header}</h2> </header> <div className="modal-body"> - <p className="huge-spacer-bottom">{translate('overview.badges.description')}</p> + <p className="huge-spacer-bottom"> + {translate('overview.badges.description', qualifier)} + </p> <div className="badges-list spacer-bottom"> {badges.map(type => ( <BadgeButton @@ -97,7 +100,7 @@ export default class BadgesModal extends React.PureComponent<Props, State> { ))} </div> <p className="text-center note huge-spacer-bottom"> - {translate('overview.badges', selectedType, 'description')} + {translate('overview.badges', selectedType, 'description', qualifier)} </p> <BadgeParams className="big-spacer-bottom" diff --git a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgesModal-test.tsx b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgesModal-test.tsx index 6d0bfbc613b..5cff7462feb 100644 --- a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgesModal-test.tsx +++ b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgesModal-test.tsx @@ -36,7 +36,13 @@ const shortBranch: ShortLivingBranch = { it('should display the modal after click on sonar cloud', () => { const wrapper = shallow( - <BadgesModal branchLike={shortBranch} metrics={{}} onSonarCloud={true} project="foo" /> + <BadgesModal + branchLike={shortBranch} + metrics={{}} + onSonarCloud={true} + project="foo" + qualifier="TRK" + /> ); expect(wrapper).toMatchSnapshot(); click(wrapper.find('Button')); @@ -45,7 +51,13 @@ it('should display the modal after click on sonar cloud', () => { it('should display the modal after click on sonar qube', () => { const wrapper = shallow( - <BadgesModal branchLike={shortBranch} metrics={{}} onSonarCloud={false} project="foo" /> + <BadgesModal + branchLike={shortBranch} + metrics={{}} + onSonarCloud={false} + project="foo" + qualifier="TRK" + /> ); expect(wrapper).toMatchSnapshot(); click(wrapper.find('Button')); diff --git a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgesModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgesModal-test.tsx.snap index 4c9ba3fb24b..012ed7da821 100644 --- a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgesModal-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgesModal-test.tsx.snap @@ -8,7 +8,7 @@ exports[`should display the modal after click on sonar cloud 1`] = ` className="js-project-badges" onClick={[Function]} > - overview.badges.get_badge + overview.badges.get_badge.TRK </Button> </div> `; @@ -31,7 +31,7 @@ exports[`should display the modal after click on sonar cloud 2`] = ` <p className="huge-spacer-bottom" > - overview.badges.description + overview.badges.description.TRK </p> <div className="badges-list spacer-bottom" @@ -61,7 +61,7 @@ exports[`should display the modal after click on sonar cloud 2`] = ` <p className="text-center note huge-spacer-bottom" > - overview.badges.measure.description + overview.badges.measure.description.TRK </p> <BadgeParams className="big-spacer-bottom" @@ -101,7 +101,7 @@ exports[`should display the modal after click on sonar qube 1`] = ` className="js-project-badges" onClick={[Function]} > - overview.badges.get_badge + overview.badges.get_badge.TRK </Button> </div> `; @@ -124,7 +124,7 @@ exports[`should display the modal after click on sonar qube 2`] = ` <p className="huge-spacer-bottom" > - overview.badges.description + overview.badges.description.TRK </p> <div className="badges-list spacer-bottom" @@ -147,7 +147,7 @@ exports[`should display the modal after click on sonar qube 2`] = ` <p className="text-center note huge-spacer-bottom" > - overview.badges.measure.description + overview.badges.measure.description.TRK </p> <BadgeParams className="big-spacer-bottom" diff --git a/server/sonar-web/src/main/js/apps/overview/meta/Meta.tsx b/server/sonar-web/src/main/js/apps/overview/meta/Meta.tsx index ef5991a2a12..631c258e268 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/Meta.tsx +++ b/server/sonar-web/src/main/js/apps/overview/meta/Meta.tsx @@ -104,15 +104,15 @@ export default class Meta extends React.PureComponent<Props> { {organizationsEnabled && <MetaOrganizationKey organization={component.organization} />} </div> - {isProject && - !isPrivate && ( - <BadgesModal - branchLike={branchLike} - metrics={metrics} - onSonarCloud={onSonarCloud} - project={component.key} - /> - )} + {!isPrivate && ( + <BadgesModal + branchLike={branchLike} + metrics={metrics} + onSonarCloud={onSonarCloud} + project={component.key} + qualifier={component.qualifier} + /> + )} </div> ); } diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/App.tsx b/server/sonar-web/src/main/js/apps/portfolio/components/App.tsx index aa0fd5f0a16..ab35a37e8ae 100644 --- a/server/sonar-web/src/main/js/apps/portfolio/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/portfolio/components/App.tsx @@ -34,11 +34,11 @@ import { getChildren } from '../../../api/components'; import { translate } from '../../../helpers/l10n'; import { fetchMetrics } from '../../../store/rootActions'; import { getMetrics } from '../../../store/rootReducer'; -import { Metric } from '../../../app/types'; +import { Metric, Component } from '../../../app/types'; import '../styles.css'; interface OwnProps { - component: { key: string; name: string }; + component: Component; } interface StateToProps { @@ -184,10 +184,21 @@ export class App extends React.PureComponent<Props, State> { <div className="page-main">{this.renderMain()}</div> <aside className="page-sidebar-fixed"> - {!this.isEmpty() && - !this.isNotComputed() && <Summary component={component} measures={measures!} />} - <Activity component={component.key} metrics={this.props.metrics} /> - <Report component={component} /> + <div className="portfolio-meta-card"> + <h4 className="portfolio-meta-header"> + {translate('overview.about_this_portfolio')} + </h4> + {!this.isEmpty() && + !this.isNotComputed() && <Summary component={component} measures={measures!} />} + </div> + + <div className="portfolio-meta-card"> + <Activity component={component.key} metrics={this.props.metrics} /> + </div> + + <div className="portfolio-meta-card"> + <Report component={component} /> + </div> </aside> </div> </div> diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/Summary.tsx b/server/sonar-web/src/main/js/apps/portfolio/components/Summary.tsx index 75ef3f32723..b32e4cda434 100644 --- a/server/sonar-web/src/main/js/apps/portfolio/components/Summary.tsx +++ b/server/sonar-web/src/main/js/apps/portfolio/components/Summary.tsx @@ -34,7 +34,7 @@ export default function Summary({ component, measures }: Props) { const nclocDistribution = measures['ncloc_language_distribution']; return ( - <section id="portfolio-summary" className="big-spacer-bottom"> + <section className="big-spacer-bottom" id="portfolio-summary"> {component.description && <div className="big-spacer-bottom">{component.description}</div>} <ul className="portfolio-grid"> diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/App-test.tsx index 4abdc4e056b..58ec3447ae8 100644 --- a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/App-test.tsx +++ b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/App-test.tsx @@ -44,11 +44,12 @@ jest.mock('../Report', () => ({ import * as React from 'react'; import { shallow, mount } from 'enzyme'; import { App } from '../App'; +import { Component } from '../../../../app/types'; const getMeasures = require('../../../../api/measures').getMeasures as jest.Mock<any>; const getChildren = require('../../../../api/components').getChildren as jest.Mock<any>; -const component = { key: 'foo', name: 'Foo' }; +const component = { key: 'foo', name: 'Foo', qualifier: 'TRK' } as Component; it('renders', () => { const wrapper = shallow(<App component={component} fetchMetrics={jest.fn()} metrics={{}} />); diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/App-test.tsx.snap index 76ccc5b4cb8..4a89b29c509 100644 --- a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/App-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/App-test.tsx.snap @@ -61,32 +61,51 @@ exports[`renders 1`] = ` <aside className="page-sidebar-fixed" > - <Summary - component={ - Object { - "key": "foo", - "name": "Foo", + <div + className="portfolio-meta-card" + > + <h4 + className="portfolio-meta-header" + > + overview.about_this_portfolio + </h4> + <Summary + component={ + Object { + "key": "foo", + "name": "Foo", + "qualifier": "TRK", + } } - } - measures={ - Object { - "ncloc": "173", - "reliability_rating": "1", + measures={ + Object { + "ncloc": "173", + "reliability_rating": "1", + } } - } - /> - <Activity - component="foo" - metrics={Object {}} - /> - <Report - component={ - Object { - "key": "foo", - "name": "Foo", + /> + </div> + <div + className="portfolio-meta-card" + > + <Activity + component="foo" + metrics={Object {}} + /> + </div> + <div + className="portfolio-meta-card" + > + <Report + component={ + Object { + "key": "foo", + "name": "Foo", + "qualifier": "TRK", + } } - } - /> + /> + </div> </aside> </div> </div> @@ -116,18 +135,36 @@ exports[`renders when portfolio is empty 1`] = ` <aside className="page-sidebar-fixed" > - <Activity - component="foo" - metrics={Object {}} - /> - <Report - component={ - Object { - "key": "foo", - "name": "Foo", + <div + className="portfolio-meta-card" + > + <h4 + className="portfolio-meta-header" + > + overview.about_this_portfolio + </h4> + </div> + <div + className="portfolio-meta-card" + > + <Activity + component="foo" + metrics={Object {}} + /> + </div> + <div + className="portfolio-meta-card" + > + <Report + component={ + Object { + "key": "foo", + "name": "Foo", + "qualifier": "TRK", + } } - } - /> + /> + </div> </aside> </div> </div> @@ -154,18 +191,36 @@ exports[`renders when portfolio is not computed 1`] = ` <aside className="page-sidebar-fixed" > - <Activity - component="foo" - metrics={Object {}} - /> - <Report - component={ - Object { - "key": "foo", - "name": "Foo", + <div + className="portfolio-meta-card" + > + <h4 + className="portfolio-meta-header" + > + overview.about_this_portfolio + </h4> + </div> + <div + className="portfolio-meta-card" + > + <Activity + component="foo" + metrics={Object {}} + /> + </div> + <div + className="portfolio-meta-card" + > + <Report + component={ + Object { + "key": "foo", + "name": "Foo", + "qualifier": "TRK", + } } - } - /> + /> + </div> </aside> </div> </div> diff --git a/server/sonar-web/src/main/js/apps/portfolio/styles.css b/server/sonar-web/src/main/js/apps/portfolio/styles.css index 1d51166d27a..7267fc0b4b6 100644 --- a/server/sonar-web/src/main/js/apps/portfolio/styles.css +++ b/server/sonar-web/src/main/js/apps/portfolio/styles.css @@ -110,3 +110,19 @@ .portfolio-sub-components-cell { width: 90px; } + +.portfolio-meta-header { + margin-bottom: calc(0.5 * var(--gridSize)); + color: var(--baseFontColor); +} + +.portfolio-meta-card { + min-width: 200px; + box-sizing: border-box; +} + +.portfolio-meta-card + .portfolio-meta-card { + margin-top: calc(2 * var(--gridSize)); + padding-top: calc(2 * var(--gridSize) - 1px); + border-top: 1px solid var(--barBorderColor); +} diff --git a/server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/App-test.tsx index cdb269fd1f8..ff0be985150 100644 --- a/server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/App-test.tsx +++ b/server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/App-test.tsx @@ -36,6 +36,7 @@ jest.mock('../../../app/utils/handleRequiredAuthorization', () => ({ import * as React from 'react'; import { mount } from 'enzyme'; import App from '../App'; +import { Component } from '../../../app/types'; const associateGateWithProject = require('../../../api/quality-gates') .associateGateWithProject as jest.Mock<any>; @@ -62,7 +63,7 @@ const component = { organization: 'org', qualifier: 'TRK', version: '0.0.1' -}; +} as Component; beforeEach(() => { associateGateWithProject.mockClear(); @@ -73,7 +74,10 @@ beforeEach(() => { it('checks permissions', () => { handleRequiredAuthorization.mockClear(); mount( - <App component={{ ...component, configuration: undefined }} onComponentChange={jest.fn()} /> + <App + component={{ ...component, configuration: undefined } as Component} + onComponentChange={jest.fn()} + /> ); expect(handleRequiredAuthorization).toBeCalled(); }); 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 b7bc5c0ac53..67f4acdf5a4 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -2297,6 +2297,7 @@ overview.last_analysis_x=last analysis {0} overview.started_on_x=Started on {0} overview.last_analysis_on_x=Last analysis on {0} overview.on_new_code=On New Code +overview.about_this_portfolio=About This Portfolio overview.about_this_project.APP=About This Application overview.about_this_project.TRK=About This Project overview.about_this_project.BRC=About This Sub-Project @@ -2356,15 +2357,22 @@ overview.complexity_tooltip.file={0} files have complexity around {1} overview.deprecated_profile=This quality profile uses {0} deprecated rules and should be updated. -overview.badges.get_badge=Get project badges + +overview.badges.get_badge.TRK=Get project badges +overview.badges.get_badge.VW=Get portfolio badges +overview.badges.get_badge.APP=Get application badges overview.badges.title=Badges -overview.badges.description=Show the status of your project metrics on your README or website. Pick your style: +overview.badges.description.TRK=Show the status of your project metrics on your README or website. Pick your style: +overview.badges.description.VW=Show the status of your portfolio metrics on your README or website. Pick your style: +overview.badges.description.APP=Show the status of your application metrics on your README or website. Pick your style: overview.badges.metric=Metric overview.badges.options.colors.white=White overview.badges.options.colors.black=Black overview.badges.options.colors.orange=Orange overview.badges.measure.alt=Standard badge -overview.badges.measure.description=This badge dynamically displays the current status of one metric of your project. +overview.badges.measure.description.TRK=This badge dynamically displays the current status of one metric of your project. +overview.badges.measure.description.VW=This badge dynamically displays the current status of one metric of your portfolio. +overview.badges.measure.description.APP=This badge dynamically displays the current status of one metric of your application. overview.badges.marketing.alt=Scanned on SonarCloud badge overview.badges.marketing.description=This badge lets you advertise that you're using SonarCloud for code quality. overview.badges.quality_gate.alt=SonarCloud Quality Gate badge |