@@ -57,6 +57,11 @@ export interface AnalysisEvent { | |||
description?: string; | |||
key: string; | |||
name: string; | |||
qualityGate?: { | |||
failing: Array<{ branch: string; key: string; name: string }>; | |||
status: string; | |||
stillFailing: boolean; | |||
}; | |||
} | |||
export interface AppState { |
@@ -18,8 +18,11 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { AnalysisEvent } from '../../../app/types'; | |||
import { isRichQualityGateEvent } from '../../projectActivity/components/RichQualityGateEventInner'; | |||
import Level from '../../../components/ui/Level'; | |||
import { translate } from '../../../helpers/l10n'; | |||
interface Props { | |||
event: AnalysisEvent; | |||
@@ -36,6 +39,23 @@ export default function Event({ event }: Props) { | |||
); | |||
} | |||
if (isRichQualityGateEvent(event)) { | |||
return ( | |||
<div className="overview-analysis-event"> | |||
<span className="note">{translate('event.category', event.category)}:</span>{' '} | |||
{event.qualityGate.stillFailing ? ( | |||
<FormattedMessage | |||
defaultMessage={translate('event.quality_gate.still_x')} | |||
id="event.quality_gate.still_x" | |||
values={{ status: <Level level={event.qualityGate.status} small={true} /> }} | |||
/> | |||
) : ( | |||
<Level level={event.qualityGate.status} small={true} /> | |||
)} | |||
</div> | |||
); | |||
} | |||
return ( | |||
<div className="overview-analysis-event"> | |||
<span className="note">{translate('event.category', event.category)}:</span>{' '} |
@@ -20,6 +20,7 @@ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import Event from '../Event'; | |||
import { RichQualityGateEvent } from '../../../projectActivity/components/RichQualityGateEventInner'; | |||
const EVENT = { key: '1', category: 'OTHER', name: 'test' }; | |||
const VERSION = { key: '2', category: 'VERSION', name: '6.5-SNAPSHOT' }; | |||
@@ -31,3 +32,17 @@ it('should render an event correctly', () => { | |||
it('should render a version correctly', () => { | |||
expect(shallow(<Event event={VERSION} />)).toMatchSnapshot(); | |||
}); | |||
it('should render rich quality gate event', () => { | |||
const event: RichQualityGateEvent = { | |||
category: 'QUALITY_GATE', | |||
key: 'foo1234', | |||
name: '', | |||
qualityGate: { | |||
failing: [{ branch: 'master', key: 'foo', name: 'Foo' }], | |||
status: 'ERROR', | |||
stillFailing: true | |||
} | |||
}; | |||
expect(shallow(<Event event={event} />)).toMatchSnapshot(); | |||
}); |
@@ -25,3 +25,29 @@ exports[`should render an event correctly 1`] = ` | |||
</strong> | |||
</div> | |||
`; | |||
exports[`should render rich quality gate event 1`] = ` | |||
<div | |||
className="overview-analysis-event" | |||
> | |||
<span | |||
className="note" | |||
> | |||
event.category.QUALITY_GATE | |||
: | |||
</span> | |||
<FormattedMessage | |||
defaultMessage="event.quality_gate.still_x" | |||
id="event.quality_gate.still_x" | |||
values={ | |||
Object { | |||
"status": <Level | |||
level="ERROR" | |||
small={true} | |||
/>, | |||
} | |||
} | |||
/> | |||
</div> | |||
`; |
@@ -86,7 +86,7 @@ export class Meta extends React.PureComponent<Props> { | |||
} | |||
return ( | |||
<div className="overview-meta-card"> | |||
<div className="overview-meta-card" id="overview-meta-quality-gate"> | |||
{qualityGate && ( | |||
<MetaQualityGate | |||
organization={organizationsEnabled ? component.organization : undefined} |
@@ -18,6 +18,8 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import * as classNames from 'classnames'; | |||
import { isRichQualityGateEvent, RichQualityGateEventInner } from './RichQualityGateEventInner'; | |||
import { AnalysisEvent } from '../../../app/types'; | |||
import ProjectEventIcon from '../../../components/icons-components/ProjectEventIcon'; | |||
import { translate } from '../../../helpers/l10n'; | |||
@@ -27,17 +29,28 @@ interface Props { | |||
} | |||
export default function EventInner({ event }: Props) { | |||
return ( | |||
<div className="project-activity-event-inner"> | |||
<div className="project-activity-event-inner-icon little-spacer-right"> | |||
<ProjectEventIcon | |||
className={'project-activity-event-icon margin-align ' + event.category} | |||
/> | |||
if (isRichQualityGateEvent(event)) { | |||
return <RichQualityGateEventInner event={event} />; | |||
} else { | |||
return ( | |||
<div className="project-activity-event-inner"> | |||
<div className="project-activity-event-inner-main"> | |||
<ProjectEventIcon | |||
className={classNames( | |||
'project-activity-event-icon', | |||
'little-spacer-right', | |||
event.category | |||
)} | |||
/> | |||
<span className="project-activity-event-inner-text"> | |||
<span className="note little-spacer-right"> | |||
{translate('event.category', event.category)}: | |||
</span> | |||
<strong title={event.description}>{event.name}</strong> | |||
</span> | |||
</div> | |||
</div> | |||
<span className="project-activity-event-inner-text"> | |||
<span className="note">{translate('event.category', event.category)}:</span>{' '} | |||
<strong title={event.description}>{event.name}</strong> | |||
</span> | |||
</div> | |||
); | |||
); | |||
} | |||
} |
@@ -108,7 +108,6 @@ export default class ProjectActivityAnalysis extends React.PureComponent<Props, | |||
render() { | |||
const { analysis, isFirst, canAdmin } = this.props; | |||
const { date, events } = analysis; | |||
const analysisTitle = translate('project_activity.analysis'); | |||
const hasVersion = events.find(event => event.category === 'VERSION') != null; | |||
const canAddVersion = canAdmin && !hasVersion && this.props.canCreateVersion; | |||
@@ -117,16 +116,13 @@ export default class ProjectActivityAnalysis extends React.PureComponent<Props, | |||
return ( | |||
<li | |||
className={classNames('project-activity-analysis clearfix', { | |||
selected: this.props.selected | |||
})} | |||
className={classNames('project-activity-analysis', { selected: this.props.selected })} | |||
data-date={date.valueOf()} | |||
onClick={this.handleClick} | |||
tabIndex={0}> | |||
<div className="project-activity-time spacer-right"> | |||
<TimeTooltipFormatter className="text-middle" date={date} /> | |||
</div> | |||
<div className="project-activity-analysis-icon spacer-right" title={analysisTitle} /> | |||
{(canAddVersion || canAddEvent || canDeleteAnalyses) && ( | |||
<div className="project-activity-analysis-actions big-spacer-right"> |
@@ -0,0 +1,117 @@ | |||
/* | |||
* 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 { FormattedMessage } from 'react-intl'; | |||
import { Link } from 'react-router'; | |||
import * as classNames from 'classnames'; | |||
import { AnalysisEvent } from '../../../app/types'; | |||
import DropdownIcon from '../../../components/icons-components/DropdownIcon'; | |||
import ProjectEventIcon from '../../../components/icons-components/ProjectEventIcon'; | |||
import { ResetButtonLink } from '../../../components/ui/buttons'; | |||
import Level from '../../../components/ui/Level'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { getProjectUrl } from '../../../helpers/urls'; | |||
export type RichQualityGateEvent = Exclude<AnalysisEvent, 'qualityGate'> & | |||
Required<Pick<AnalysisEvent, 'qualityGate'>>; | |||
export function isRichQualityGateEvent(event: AnalysisEvent): event is RichQualityGateEvent { | |||
return event.category === 'QUALITY_GATE' && event.qualityGate !== undefined; | |||
} | |||
interface Props { | |||
event: RichQualityGateEvent; | |||
} | |||
interface State { | |||
expanded: boolean; | |||
} | |||
export class RichQualityGateEventInner extends React.PureComponent<Props, State> { | |||
state: State = { expanded: false }; | |||
toggleProjectsList = () => { | |||
this.setState(state => ({ expanded: !state.expanded })); | |||
}; | |||
render() { | |||
const { event } = this.props; | |||
const { expanded } = this.state; | |||
return ( | |||
<div className="project-activity-event-inner"> | |||
<div className="project-activity-event-inner-main"> | |||
<ProjectEventIcon | |||
className={classNames( | |||
'project-activity-event-icon', | |||
'little-spacer-right', | |||
event.category | |||
)} | |||
/> | |||
<div className="project-activity-event-inner-text flex-1"> | |||
<span className="note little-spacer-right"> | |||
{translate('event.category', event.category)}: | |||
</span> | |||
{event.qualityGate.stillFailing ? ( | |||
<FormattedMessage | |||
defaultMessage={translate('event.quality_gate.still_x')} | |||
id="event.quality_gate.still_x" | |||
values={{ status: <Level level={event.qualityGate.status} small={true} /> }} | |||
/> | |||
) : ( | |||
<Level level={event.qualityGate.status} small={true} /> | |||
)} | |||
</div> | |||
{event.qualityGate.failing.length > 0 && ( | |||
<ResetButtonLink | |||
className="project-activity-event-inner-more-link" | |||
onClick={this.toggleProjectsList} | |||
stopPropagation={true}> | |||
{expanded ? translate('hide') : translate('more')} | |||
<DropdownIcon className="little-spacer-left" turned={expanded} /> | |||
</ResetButtonLink> | |||
)} | |||
</div> | |||
{expanded && ( | |||
<ul> | |||
{event.qualityGate.failing.map(project => ( | |||
<li className="display-flex-center little-spacer-top" key={project.key}> | |||
<Level | |||
className="little-spacer-right" | |||
level={event.qualityGate.status} | |||
small={true} | |||
/> | |||
<div className="flex-1 text-ellipsis"> | |||
<Link | |||
onClick={e => e.stopPropagation()} | |||
to={getProjectUrl(project.key, project.branch)}> | |||
{project.name} | |||
</Link> | |||
</div> | |||
</li> | |||
))} | |||
</ul> | |||
)} | |||
</div> | |||
); | |||
} | |||
} |
@@ -0,0 +1,55 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import { RichQualityGateEventInner, RichQualityGateEvent } from '../RichQualityGateEventInner'; | |||
import { click } from '../../../../helpers/testUtils'; | |||
const event: RichQualityGateEvent = { | |||
category: 'QUALITY_GATE', | |||
key: 'foo1234', | |||
name: '', | |||
qualityGate: { | |||
failing: [ | |||
{ branch: 'master', key: 'foo', name: 'Foo' }, | |||
{ branch: 'master', key: 'bar', name: 'Bar' } | |||
], | |||
status: 'ERROR', | |||
stillFailing: true | |||
} | |||
}; | |||
it('should render', () => { | |||
const wrapper = shallow(<RichQualityGateEventInner event={event} />); | |||
expect(wrapper).toMatchSnapshot(); | |||
click(wrapper.find('.project-activity-event-inner-more-link')); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
}); | |||
it('should not expand', () => { | |||
const wrapper = shallow( | |||
<RichQualityGateEventInner | |||
event={{ ...event, qualityGate: { ...event.qualityGate, failing: [] } }} | |||
/> | |||
); | |||
expect(wrapper.find('.project-activity-event-inner-more-link').exists()).toBe(false); | |||
}); |
@@ -0,0 +1,157 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render 1`] = ` | |||
<div | |||
className="project-activity-event-inner" | |||
> | |||
<div | |||
className="project-activity-event-inner-main" | |||
> | |||
<ProjectEventIcon | |||
className="project-activity-event-icon little-spacer-right QUALITY_GATE" | |||
/> | |||
<div | |||
className="project-activity-event-inner-text flex-1" | |||
> | |||
<span | |||
className="note little-spacer-right" | |||
> | |||
event.category.QUALITY_GATE | |||
: | |||
</span> | |||
<FormattedMessage | |||
defaultMessage="event.quality_gate.still_x" | |||
id="event.quality_gate.still_x" | |||
values={ | |||
Object { | |||
"status": <Level | |||
level="ERROR" | |||
small={true} | |||
/>, | |||
} | |||
} | |||
/> | |||
</div> | |||
<ResetButtonLink | |||
className="project-activity-event-inner-more-link" | |||
onClick={[Function]} | |||
stopPropagation={true} | |||
> | |||
more | |||
<DropdownIcon | |||
className="little-spacer-left" | |||
turned={false} | |||
/> | |||
</ResetButtonLink> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render 2`] = ` | |||
<div | |||
className="project-activity-event-inner" | |||
> | |||
<div | |||
className="project-activity-event-inner-main" | |||
> | |||
<ProjectEventIcon | |||
className="project-activity-event-icon little-spacer-right QUALITY_GATE" | |||
/> | |||
<div | |||
className="project-activity-event-inner-text flex-1" | |||
> | |||
<span | |||
className="note little-spacer-right" | |||
> | |||
event.category.QUALITY_GATE | |||
: | |||
</span> | |||
<FormattedMessage | |||
defaultMessage="event.quality_gate.still_x" | |||
id="event.quality_gate.still_x" | |||
values={ | |||
Object { | |||
"status": <Level | |||
level="ERROR" | |||
small={true} | |||
/>, | |||
} | |||
} | |||
/> | |||
</div> | |||
<ResetButtonLink | |||
className="project-activity-event-inner-more-link" | |||
onClick={[Function]} | |||
stopPropagation={true} | |||
> | |||
hide | |||
<DropdownIcon | |||
className="little-spacer-left" | |||
turned={true} | |||
/> | |||
</ResetButtonLink> | |||
</div> | |||
<ul> | |||
<li | |||
className="display-flex-center little-spacer-top" | |||
key="foo" | |||
> | |||
<Level | |||
className="little-spacer-right" | |||
level="ERROR" | |||
small={true} | |||
/> | |||
<div | |||
className="flex-1 text-ellipsis" | |||
> | |||
<Link | |||
onClick={[Function]} | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to={ | |||
Object { | |||
"pathname": "/dashboard", | |||
"query": Object { | |||
"branch": "master", | |||
"id": "foo", | |||
}, | |||
} | |||
} | |||
> | |||
Foo | |||
</Link> | |||
</div> | |||
</li> | |||
<li | |||
className="display-flex-center little-spacer-top" | |||
key="bar" | |||
> | |||
<Level | |||
className="little-spacer-right" | |||
level="ERROR" | |||
small={true} | |||
/> | |||
<div | |||
className="flex-1 text-ellipsis" | |||
> | |||
<Link | |||
onClick={[Function]} | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to={ | |||
Object { | |||
"pathname": "/dashboard", | |||
"query": Object { | |||
"branch": "master", | |||
"id": "bar", | |||
}, | |||
} | |||
} | |||
> | |||
Bar | |||
</Link> | |||
</div> | |||
</li> | |||
</ul> | |||
</div> | |||
`; |
@@ -61,78 +61,6 @@ | |||
flex-shrink: 0; | |||
} | |||
.project-activity-graphs { | |||
flex-grow: 1; | |||
display: flex; | |||
flex-direction: column; | |||
align-items: stretch; | |||
justify-content: center; | |||
} | |||
.project-activity-graph-container { | |||
padding: 10px 0; | |||
flex-grow: 1; | |||
display: flex; | |||
flex-direction: column; | |||
align-items: stretch; | |||
justify-content: center; | |||
} | |||
.project-activity-graph { | |||
flex: 1; | |||
overflow: hidden; | |||
} | |||
.project-activity-graph-legends { | |||
flex-grow: 0; | |||
padding-bottom: 16px; | |||
text-align: center; | |||
} | |||
.project-activity-graph-legend-actionable { | |||
display: inline-block; | |||
padding: 4px 8px 4px 12px; | |||
border-width: 1px; | |||
border-style: solid; | |||
border-radius: 12px; | |||
} | |||
.project-activity-graph-tooltip { | |||
padding: 8px; | |||
} | |||
.project-activity-graph-tooltip-line { | |||
height: 20px; | |||
} | |||
.project-activity-graph-tooltip-line + .project-activity-graph-tooltip-line { | |||
padding-top: 4px; | |||
} | |||
.project-activity-graph-tooltip-line .project-activity-event-icon { | |||
margin-top: 1px; | |||
} | |||
.project-activity-graph-tooltip-issues-line { | |||
height: 26px; | |||
padding-bottom: 4px; | |||
} | |||
.project-activity-graph-tooltip-separator { | |||
padding-left: 16px; | |||
padding-right: 16px; | |||
} | |||
.project-activity-graph-tooltip-separator hr { | |||
margin-top: 8px; | |||
margin-bottom: 8px; | |||
} | |||
.project-activity-graph-tooltip-title, | |||
.project-activity-graph-tooltip-value { | |||
font-weight: bold; | |||
} | |||
.project-activity-days-list { | |||
} | |||
@@ -156,8 +84,9 @@ | |||
.project-activity-analysis { | |||
position: relative; | |||
min-height: 20px; | |||
padding: 4px; | |||
display: flex; | |||
min-height: var(--smallControlHeight); | |||
padding: calc(0.5 * var(--gridSize)); | |||
border-top: 1px solid var(--barBorderColor); | |||
border-bottom: 1px solid var(--barBorderColor); | |||
cursor: pointer; | |||
@@ -180,36 +109,30 @@ | |||
} | |||
.project-activity-analysis-actions { | |||
float: left; | |||
flex-shrink: 0; | |||
flex-grow: 0; | |||
height: var(--smallControlHeight); | |||
} | |||
.project-activity-time { | |||
float: left; | |||
flex-shrink: 0; | |||
flex-grow: 0; | |||
width: 54px; | |||
line-height: 20px; | |||
height: var(--smallControlHeight); | |||
line-height: var(--smallControlHeight); | |||
box-sizing: border-box; | |||
font-size: var(--smallFontSize); | |||
font-weight: bold; | |||
text-align: right; | |||
} | |||
.project-activity-analysis-icon { | |||
float: left; | |||
width: 10px; | |||
height: 10px; | |||
margin-top: 5px; | |||
border: 2px solid var(--blue); | |||
border-radius: 10px; | |||
box-sizing: border-box; | |||
content: ''; | |||
} | |||
.project-activity-events { | |||
overflow: hidden; | |||
flex: 1; | |||
min-width: 0; | |||
} | |||
.project-activity-event { | |||
line-height: 18px; | |||
line-height: var(--smallControlHeight); | |||
display: flex; | |||
} | |||
@@ -219,28 +142,32 @@ | |||
.project-activity-event-inner { | |||
flex: 1; | |||
min-width: 0; | |||
} | |||
.project-activity-event-inner-main { | |||
display: flex; | |||
flex-direction: row; | |||
overflow: hidden; | |||
align-items: flex-start; | |||
} | |||
.project-activity-event-inner-icon { | |||
.project-activity-event-icon { | |||
flex-shrink: 0; | |||
flex-grow: 0; | |||
margin-top: calc(0.5 * var(--smallControlHeight) - 7px); | |||
} | |||
.project-activity-event-inner-text { | |||
flex: 1; | |||
display: inline-block; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
line-height: var(--smallControlHeight); | |||
} | |||
.project-activity-event-actions { | |||
display: inline-block; | |||
.project-activity-event-inner-more-link { | |||
line-height: 16px; | |||
margin-top: 2px; | |||
} | |||
.project-activity-event-inner-icon .project-activity-event-icon { | |||
margin-top: 3px; | |||
.project-activity-event-actions { | |||
flex-shrink: 0; | |||
flex-grow: 0; | |||
} | |||
.project-activity-event-icon.VERSION { | |||
@@ -289,3 +216,76 @@ | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
} | |||
.project-activity-graphs { | |||
flex-grow: 1; | |||
display: flex; | |||
flex-direction: column; | |||
align-items: stretch; | |||
justify-content: center; | |||
} | |||
.project-activity-graph-container { | |||
padding: 10px 0; | |||
flex-grow: 1; | |||
display: flex; | |||
flex-direction: column; | |||
align-items: stretch; | |||
justify-content: center; | |||
} | |||
.project-activity-graph { | |||
flex: 1; | |||
overflow: hidden; | |||
} | |||
.project-activity-graph-legends { | |||
flex-grow: 0; | |||
padding-bottom: 16px; | |||
text-align: center; | |||
} | |||
.project-activity-graph-legend-actionable { | |||
display: inline-block; | |||
padding: 4px 8px 4px 12px; | |||
border-width: 1px; | |||
border-style: solid; | |||
border-radius: 12px; | |||
} | |||
.project-activity-graph-tooltip { | |||
padding: 8px; | |||
} | |||
.project-activity-graph-tooltip-line { | |||
height: 20px; | |||
} | |||
.project-activity-graph-tooltip-line + .project-activity-graph-tooltip-line { | |||
padding-top: 4px; | |||
} | |||
.Select .project-activity-event-icon, | |||
.project-activity-graph-tooltip-line .project-activity-event-icon { | |||
margin-top: 1px; | |||
} | |||
.project-activity-graph-tooltip-issues-line { | |||
height: 26px; | |||
padding-bottom: 4px; | |||
} | |||
.project-activity-graph-tooltip-separator { | |||
padding-left: 16px; | |||
padding-right: 16px; | |||
} | |||
.project-activity-graph-tooltip-separator hr { | |||
margin-top: 8px; | |||
margin-bottom: 8px; | |||
} | |||
.project-activity-graph-tooltip-title, | |||
.project-activity-graph-tooltip-value { | |||
font-weight: bold; | |||
} |
@@ -42,8 +42,8 @@ | |||
padding-right: 9px; | |||
margin-top: -1px; | |||
margin-bottom: -1px; | |||
height: 18px; | |||
line-height: 18px; | |||
height: var(--smallControlHeight); | |||
line-height: var(--smallControlHeight); | |||
font-size: var(--smallFontSize); | |||
} | |||
@@ -30,7 +30,7 @@ interface Props { | |||
} | |||
export default function Level(props: Props) { | |||
const formatted = formatMeasure(props.level, 'LEVEL', null); | |||
const formatted = formatMeasure(props.level, 'LEVEL'); | |||
const className = classNames(props.className, 'level', 'level-' + props.level, { | |||
'level-small': props.small, | |||
'level-muted': props.muted |
@@ -119,6 +119,7 @@ | |||
.button-link { | |||
display: inline; | |||
height: auto; /* Keep this to not inherit the height from .button */ | |||
line-height: 1; | |||
margin: 0; | |||
padding: 0; | |||
border: none; | |||
@@ -128,7 +129,6 @@ | |||
border-bottom: 1px solid var(--lightBlue); | |||
font-weight: 400; | |||
font-size: inherit; | |||
line-height: inherit; | |||
transition: all 0.2s ease; | |||
} | |||
@@ -437,6 +437,7 @@ event.category.VERSION=Version | |||
event.category.QUALITY_GATE=Quality Gate | |||
event.category.QUALITY_PROFILE=Quality Profile | |||
event.category.OTHER=Other | |||
event.quality_gate.still_x=Still {status} | |||
#------------------------------------------------------------------------------ |