metrics: { [key: string]: Metric }; | metrics: { [key: string]: Metric }; | ||||
onSonarCloud: boolean; | onSonarCloud: boolean; | ||||
project: string; | project: string; | ||||
qualifier: string; | |||||
} | } | ||||
interface State { | interface State { | ||||
}; | }; | ||||
render() { | render() { | ||||
const { branchLike, project } = this.props; | |||||
const { branchLike, project, qualifier } = this.props; | |||||
const { selectedType, badgeOptions } = this.state; | const { selectedType, badgeOptions } = this.state; | ||||
const header = translate('overview.badges.title'); | const header = translate('overview.badges.title'); | ||||
const fullBadgeOptions = { project, ...badgeOptions, ...getBranchLikeQuery(branchLike) }; | const fullBadgeOptions = { project, ...badgeOptions, ...getBranchLikeQuery(branchLike) }; | ||||
return ( | return ( | ||||
<div className="overview-meta-card"> | <div className="overview-meta-card"> | ||||
<Button className="js-project-badges" onClick={this.handleOpen}> | <Button className="js-project-badges" onClick={this.handleOpen}> | ||||
{translate('overview.badges.get_badge')} | |||||
{translate('overview.badges.get_badge', qualifier)} | |||||
</Button> | </Button> | ||||
{this.state.open && ( | {this.state.open && ( | ||||
<Modal contentLabel={header} onRequestClose={this.handleClose}> | <Modal contentLabel={header} onRequestClose={this.handleClose}> | ||||
<h2>{header}</h2> | <h2>{header}</h2> | ||||
</header> | </header> | ||||
<div className="modal-body"> | <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"> | <div className="badges-list spacer-bottom"> | ||||
{badges.map(type => ( | {badges.map(type => ( | ||||
<BadgeButton | <BadgeButton | ||||
))} | ))} | ||||
</div> | </div> | ||||
<p className="text-center note huge-spacer-bottom"> | <p className="text-center note huge-spacer-bottom"> | ||||
{translate('overview.badges', selectedType, 'description')} | |||||
{translate('overview.badges', selectedType, 'description', qualifier)} | |||||
</p> | </p> | ||||
<BadgeParams | <BadgeParams | ||||
className="big-spacer-bottom" | className="big-spacer-bottom" |
it('should display the modal after click on sonar cloud', () => { | it('should display the modal after click on sonar cloud', () => { | ||||
const wrapper = shallow( | const wrapper = shallow( | ||||
<BadgesModal branchLike={shortBranch} metrics={{}} onSonarCloud={true} project="foo" /> | |||||
<BadgesModal | |||||
branchLike={shortBranch} | |||||
metrics={{}} | |||||
onSonarCloud={true} | |||||
project="foo" | |||||
qualifier="TRK" | |||||
/> | |||||
); | ); | ||||
expect(wrapper).toMatchSnapshot(); | expect(wrapper).toMatchSnapshot(); | ||||
click(wrapper.find('Button')); | click(wrapper.find('Button')); | ||||
it('should display the modal after click on sonar qube', () => { | it('should display the modal after click on sonar qube', () => { | ||||
const wrapper = shallow( | const wrapper = shallow( | ||||
<BadgesModal branchLike={shortBranch} metrics={{}} onSonarCloud={false} project="foo" /> | |||||
<BadgesModal | |||||
branchLike={shortBranch} | |||||
metrics={{}} | |||||
onSonarCloud={false} | |||||
project="foo" | |||||
qualifier="TRK" | |||||
/> | |||||
); | ); | ||||
expect(wrapper).toMatchSnapshot(); | expect(wrapper).toMatchSnapshot(); | ||||
click(wrapper.find('Button')); | click(wrapper.find('Button')); |
className="js-project-badges" | className="js-project-badges" | ||||
onClick={[Function]} | onClick={[Function]} | ||||
> | > | ||||
overview.badges.get_badge | |||||
overview.badges.get_badge.TRK | |||||
</Button> | </Button> | ||||
</div> | </div> | ||||
`; | `; | ||||
<p | <p | ||||
className="huge-spacer-bottom" | className="huge-spacer-bottom" | ||||
> | > | ||||
overview.badges.description | |||||
overview.badges.description.TRK | |||||
</p> | </p> | ||||
<div | <div | ||||
className="badges-list spacer-bottom" | className="badges-list spacer-bottom" | ||||
<p | <p | ||||
className="text-center note huge-spacer-bottom" | className="text-center note huge-spacer-bottom" | ||||
> | > | ||||
overview.badges.measure.description | |||||
overview.badges.measure.description.TRK | |||||
</p> | </p> | ||||
<BadgeParams | <BadgeParams | ||||
className="big-spacer-bottom" | className="big-spacer-bottom" | ||||
className="js-project-badges" | className="js-project-badges" | ||||
onClick={[Function]} | onClick={[Function]} | ||||
> | > | ||||
overview.badges.get_badge | |||||
overview.badges.get_badge.TRK | |||||
</Button> | </Button> | ||||
</div> | </div> | ||||
`; | `; | ||||
<p | <p | ||||
className="huge-spacer-bottom" | className="huge-spacer-bottom" | ||||
> | > | ||||
overview.badges.description | |||||
overview.badges.description.TRK | |||||
</p> | </p> | ||||
<div | <div | ||||
className="badges-list spacer-bottom" | className="badges-list spacer-bottom" | ||||
<p | <p | ||||
className="text-center note huge-spacer-bottom" | className="text-center note huge-spacer-bottom" | ||||
> | > | ||||
overview.badges.measure.description | |||||
overview.badges.measure.description.TRK | |||||
</p> | </p> | ||||
<BadgeParams | <BadgeParams | ||||
className="big-spacer-bottom" | className="big-spacer-bottom" |
{organizationsEnabled && <MetaOrganizationKey organization={component.organization} />} | {organizationsEnabled && <MetaOrganizationKey organization={component.organization} />} | ||||
</div> | </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> | </div> | ||||
); | ); | ||||
} | } |
import { translate } from '../../../helpers/l10n'; | import { translate } from '../../../helpers/l10n'; | ||||
import { fetchMetrics } from '../../../store/rootActions'; | import { fetchMetrics } from '../../../store/rootActions'; | ||||
import { getMetrics } from '../../../store/rootReducer'; | import { getMetrics } from '../../../store/rootReducer'; | ||||
import { Metric } from '../../../app/types'; | |||||
import { Metric, Component } from '../../../app/types'; | |||||
import '../styles.css'; | import '../styles.css'; | ||||
interface OwnProps { | interface OwnProps { | ||||
component: { key: string; name: string }; | |||||
component: Component; | |||||
} | } | ||||
interface StateToProps { | interface StateToProps { | ||||
<div className="page-main">{this.renderMain()}</div> | <div className="page-main">{this.renderMain()}</div> | ||||
<aside className="page-sidebar-fixed"> | <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> | </aside> | ||||
</div> | </div> | ||||
</div> | </div> |
const nclocDistribution = measures['ncloc_language_distribution']; | const nclocDistribution = measures['ncloc_language_distribution']; | ||||
return ( | 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>} | {component.description && <div className="big-spacer-bottom">{component.description}</div>} | ||||
<ul className="portfolio-grid"> | <ul className="portfolio-grid"> |
import * as React from 'react'; | import * as React from 'react'; | ||||
import { shallow, mount } from 'enzyme'; | import { shallow, mount } from 'enzyme'; | ||||
import { App } from '../App'; | import { App } from '../App'; | ||||
import { Component } from '../../../../app/types'; | |||||
const getMeasures = require('../../../../api/measures').getMeasures as jest.Mock<any>; | const getMeasures = require('../../../../api/measures').getMeasures as jest.Mock<any>; | ||||
const getChildren = require('../../../../api/components').getChildren 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', () => { | it('renders', () => { | ||||
const wrapper = shallow(<App component={component} fetchMetrics={jest.fn()} metrics={{}} />); | const wrapper = shallow(<App component={component} fetchMetrics={jest.fn()} metrics={{}} />); |
<aside | <aside | ||||
className="page-sidebar-fixed" | 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> | </aside> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<aside | <aside | ||||
className="page-sidebar-fixed" | 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> | </aside> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<aside | <aside | ||||
className="page-sidebar-fixed" | 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> | </aside> | ||||
</div> | </div> | ||||
</div> | </div> |
.portfolio-sub-components-cell { | .portfolio-sub-components-cell { | ||||
width: 90px; | 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); | |||||
} |
import * as React from 'react'; | import * as React from 'react'; | ||||
import { mount } from 'enzyme'; | import { mount } from 'enzyme'; | ||||
import App from '../App'; | import App from '../App'; | ||||
import { Component } from '../../../app/types'; | |||||
const associateGateWithProject = require('../../../api/quality-gates') | const associateGateWithProject = require('../../../api/quality-gates') | ||||
.associateGateWithProject as jest.Mock<any>; | .associateGateWithProject as jest.Mock<any>; | ||||
organization: 'org', | organization: 'org', | ||||
qualifier: 'TRK', | qualifier: 'TRK', | ||||
version: '0.0.1' | version: '0.0.1' | ||||
}; | |||||
} as Component; | |||||
beforeEach(() => { | beforeEach(() => { | ||||
associateGateWithProject.mockClear(); | associateGateWithProject.mockClear(); | ||||
it('checks permissions', () => { | it('checks permissions', () => { | ||||
handleRequiredAuthorization.mockClear(); | handleRequiredAuthorization.mockClear(); | ||||
mount( | mount( | ||||
<App component={{ ...component, configuration: undefined }} onComponentChange={jest.fn()} /> | |||||
<App | |||||
component={{ ...component, configuration: undefined } as Component} | |||||
onComponentChange={jest.fn()} | |||||
/> | |||||
); | ); | ||||
expect(handleRequiredAuthorization).toBeCalled(); | expect(handleRequiredAuthorization).toBeCalled(); | ||||
}); | }); |
overview.started_on_x=Started on {0} | overview.started_on_x=Started on {0} | ||||
overview.last_analysis_on_x=Last analysis on {0} | overview.last_analysis_on_x=Last analysis on {0} | ||||
overview.on_new_code=On New Code | 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.APP=About This Application | ||||
overview.about_this_project.TRK=About This Project | overview.about_this_project.TRK=About This Project | ||||
overview.about_this_project.BRC=About This Sub-Project | overview.about_this_project.BRC=About This Sub-Project | ||||
overview.deprecated_profile=This quality profile uses {0} deprecated rules and should be updated. | 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.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.metric=Metric | ||||
overview.badges.options.colors.white=White | overview.badges.options.colors.white=White | ||||
overview.badges.options.colors.black=Black | overview.badges.options.colors.black=Black | ||||
overview.badges.options.colors.orange=Orange | overview.badges.options.colors.orange=Orange | ||||
overview.badges.measure.alt=Standard badge | 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.alt=Scanned on SonarCloud badge | ||||
overview.badges.marketing.description=This badge lets you advertise that you're using SonarCloud for code quality. | 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 | overview.badges.quality_gate.alt=SonarCloud Quality Gate badge |