@@ -188,9 +188,9 @@ export interface Extension { | |||
name: string; | |||
} | |||
export interface FacetValue { | |||
export interface FacetValue<T = string> { | |||
count: number; | |||
val: string; | |||
val: T; | |||
} | |||
export interface FlowLocation { | |||
@@ -310,7 +310,7 @@ export interface Issue { | |||
tags?: string[]; | |||
textRange?: TextRange; | |||
transitions?: string[]; | |||
type: string; | |||
type: IssueType; | |||
} | |||
export interface IssueComment { | |||
@@ -326,6 +326,13 @@ export interface IssueComment { | |||
updatable: boolean; | |||
} | |||
export enum IssueType { | |||
Bug = 'BUG', | |||
Vulnerability = 'VULNERABILITY', | |||
CodeSmell = 'CODE_SMELL', | |||
Hotspot = 'SECURITY_HOTSPOT' | |||
} | |||
export interface LightComponent { | |||
key: string; | |||
organization: string; | |||
@@ -530,7 +537,7 @@ export interface Rule { | |||
status: string; | |||
sysTags?: string[]; | |||
tags?: string[]; | |||
type: string; | |||
type: RuleType; | |||
} | |||
export interface RuleActivation { | |||
@@ -587,6 +594,14 @@ export enum RuleScope { | |||
All = 'ALL' | |||
} | |||
export enum RuleType { | |||
Bug = 'BUG', | |||
Vulnerability = 'VULNERABILITY', | |||
CodeSmell = 'CODE_SMELL', | |||
Hotspot = 'SECURITY_HOTSPOT', | |||
Unknown = 'UNKNOWN' | |||
} | |||
export interface ShortLivingBranch extends Branch { | |||
isMain: false; | |||
isOrphan?: true; |
@@ -38,6 +38,7 @@ import { getAppState, getCurrentUser, getGlobalSettingValue } from '../../../sto | |||
import { translate } from '../../../helpers/l10n'; | |||
import { fetchAboutPageSettings } from '../actions'; | |||
import { isSonarCloud } from '../../../helpers/system'; | |||
import { IssueType } from '../../../app/types'; | |||
import '../styles.css'; | |||
/*:: | |||
@@ -138,9 +139,10 @@ class AboutApp extends React.PureComponent { | |||
let vulnerabilities; | |||
let codeSmells; | |||
if (!loading && issueTypes) { | |||
bugs = issueTypes['BUG'] && issueTypes['BUG'].count; | |||
vulnerabilities = issueTypes['VULNERABILITY'] && issueTypes['VULNERABILITY'].count; | |||
codeSmells = issueTypes['CODE_SMELL'] && issueTypes['CODE_SMELL'].count; | |||
bugs = issueTypes[IssueType.Bug] && issueTypes[IssueType.Bug].count; | |||
vulnerabilities = | |||
issueTypes[IssueType.Vulnerability] && issueTypes[IssueType.Vulnerability].count; | |||
codeSmells = issueTypes[IssueType.CodeSmell] && issueTypes[IssueType.CodeSmell].count; | |||
} | |||
return ( |
@@ -26,6 +26,7 @@ import { getIssuesUrl } from '../../../helpers/urls'; | |||
import BugIcon from '../../../components/icons-components/BugIcon'; | |||
import VulnerabilityIcon from '../../../components/icons-components/VulnerabilityIcon'; | |||
import CodeSmellIcon from '../../../components/icons-components/CodeSmellIcon'; | |||
import { IssueType } from '../../../app/types'; | |||
/*:: | |||
type Props = { | |||
@@ -49,7 +50,11 @@ export default function EntryIssueTypes( | |||
<td className="about-page-issue-type-number"> | |||
<Link | |||
className="about-page-issue-type-link" | |||
to={getIssuesUrl({ resolved: 'false', types: 'BUG', s: 'CREATION_DATE' })}> | |||
to={getIssuesUrl({ | |||
resolved: 'false', | |||
types: IssueType.Bug, | |||
s: 'CREATION_DATE' | |||
})}> | |||
{formatMeasure(bugs, 'SHORT_INT')} | |||
</Link> | |||
</td> | |||
@@ -66,7 +71,7 @@ export default function EntryIssueTypes( | |||
className="about-page-issue-type-link" | |||
to={getIssuesUrl({ | |||
resolved: 'false', | |||
types: 'VULNERABILITY', | |||
types: IssueType.Vulnerability, | |||
s: 'CREATION_DATE' | |||
})}> | |||
{formatMeasure(vulnerabilities, 'SHORT_INT')} | |||
@@ -83,7 +88,11 @@ export default function EntryIssueTypes( | |||
<td className="about-page-issue-type-number"> | |||
<Link | |||
className="about-page-issue-type-link" | |||
to={getIssuesUrl({ resolved: 'false', types: 'CODE_SMELL', s: 'CREATION_DATE' })}> | |||
to={getIssuesUrl({ | |||
resolved: 'false', | |||
types: IssueType.CodeSmell, | |||
s: 'CREATION_DATE' | |||
})}> | |||
{formatMeasure(codeSmells, 'SHORT_INT')} | |||
</Link> | |||
</td> |
@@ -18,11 +18,11 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { RuleDetails, RuleParameter } from '../../../app/types'; | |||
import { RuleDetails, RuleParameter, RuleType } from '../../../app/types'; | |||
import Modal from '../../../components/controls/Modal'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import MarkdownTips from '../../../components/common/MarkdownTips'; | |||
import { SEVERITIES, TYPES, RULE_STATUSES } from '../../../helpers/constants'; | |||
import { SEVERITIES, RULE_TYPES, RULE_STATUSES } from '../../../helpers/constants'; | |||
import latinize from '../../../helpers/latinize'; | |||
import Select from '../../../components/controls/Select'; | |||
import TypeHelper from '../../../components/shared/TypeHelper'; | |||
@@ -227,7 +227,9 @@ export default class CustomRuleFormModal extends React.PureComponent<Props, Stat | |||
</tr> | |||
); | |||
renderTypeOption = ({ value }: { value: string }) => <TypeHelper type={value} />; | |||
renderTypeOption = ({ value }: { value: RuleType }) => { | |||
return <TypeHelper type={value} />; | |||
}; | |||
renderTypeField = () => ( | |||
<tr className="property"> | |||
@@ -241,7 +243,7 @@ export default class CustomRuleFormModal extends React.PureComponent<Props, Stat | |||
disabled={this.state.submitting} | |||
onChange={this.handleTypeChange} | |||
optionRenderer={this.renderTypeOption} | |||
options={TYPES.map(type => ({ | |||
options={RULE_TYPES.map(type => ({ | |||
label: translate('issue.type', type), | |||
value: type | |||
}))} |
@@ -23,7 +23,7 @@ import { Link } from 'react-router'; | |||
import DeferredSpinner from '../../../components/common/DeferredSpinner'; | |||
import Tooltip from '../../../components/controls/Tooltip'; | |||
import { getFacet } from '../../../api/issues'; | |||
import { RuleDetails } from '../../../app/types'; | |||
import { RuleDetails, RuleType } from '../../../app/types'; | |||
import { getIssuesUrl } from '../../../helpers/urls'; | |||
import { formatMeasure } from '../../../helpers/measures'; | |||
import { translate } from '../../../helpers/l10n'; | |||
@@ -73,8 +73,8 @@ export default class RuleDetailsIssues extends React.PureComponent<Props, State> | |||
resolved: 'false', | |||
rules: this.props.ruleDetails.key, | |||
types: | |||
this.props.ruleDetails.type === 'SECURITY_HOTSPOT' | |||
? 'VULNERABILITY,SECURITY_HOTSPOT' | |||
this.props.ruleDetails.type === RuleType.Hotspot | |||
? [RuleType.Vulnerability, RuleType.Hotspot].join() | |||
: undefined | |||
}); | |||
@@ -21,6 +21,7 @@ import * as React from 'react'; | |||
import Facet, { BasicProps } from './Facet'; | |||
import IssueTypeIcon from '../../../components/ui/IssueTypeIcon'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { RuleType } from '../../../app/types'; | |||
export default class TypeFacet extends React.PureComponent<BasicProps> { | |||
renderName = (type: string) => ( | |||
@@ -33,7 +34,7 @@ export default class TypeFacet extends React.PureComponent<BasicProps> { | |||
renderTextName = (type: string) => translate('issue.type', type); | |||
render() { | |||
const options = ['BUG', 'VULNERABILITY', 'CODE_SMELL', 'SECURITY_HOTSPOT']; | |||
const options = [RuleType.Bug, RuleType.Vulnerability, RuleType.CodeSmell, RuleType.Hotspot]; | |||
return ( | |||
<Facet |
@@ -21,6 +21,7 @@ import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import RuleDetailsDescription from '../RuleDetailsDescription'; | |||
import { click, change, waitAndUpdate } from '../../../../helpers/testUtils'; | |||
import { RuleType } from '../../../../app/types'; | |||
jest.mock('../../../../api/rules', () => ({ | |||
updateRule: jest.fn().mockResolvedValue('updatedrule') | |||
@@ -37,7 +38,7 @@ const RULE = { | |||
status: 'READY', | |||
lang: 'java', | |||
langName: 'Java', | |||
type: 'CODE_SMELL' | |||
type: RuleType.CodeSmell | |||
}; | |||
const EXTERNAL_RULE = { | |||
@@ -46,7 +47,7 @@ const EXTERNAL_RULE = { | |||
name: 'xoo:OneExternalIssuePerLine', | |||
status: 'READY', | |||
isExternal: true, | |||
type: 'UNKNOWN' | |||
type: RuleType.Unknown | |||
}; | |||
const EXTERNAL_RULE_WITH_DATA = { | |||
@@ -57,7 +58,7 @@ const EXTERNAL_RULE_WITH_DATA = { | |||
htmlDesc: '<p>Html Description</p>', | |||
status: 'READY', | |||
isExternal: true, | |||
type: 'BUG' | |||
type: RuleType.Bug | |||
}; | |||
it('should display correctly', () => { |
@@ -22,6 +22,7 @@ import { shallow } from 'enzyme'; | |||
import RuleDetailsIssues from '../RuleDetailsIssues'; | |||
import { waitAndUpdate } from '../../../../helpers/testUtils'; | |||
import { getFacet } from '../../../../api/issues'; | |||
import { RuleType } from '../../../../app/types'; | |||
jest.mock('../../../../api/issues', () => ({ | |||
getFacet: jest.fn().mockResolvedValue({ | |||
@@ -38,14 +39,14 @@ beforeEach(() => { | |||
}); | |||
it('should fetch issues and render', async () => { | |||
await check('BUG', undefined); | |||
await check(RuleType.Bug, undefined); | |||
}); | |||
it('should handle hotspot rules', async () => { | |||
await check('SECURITY_HOTSPOT', ['VULNERABILITY', 'SECURITY_HOTSPOT']); | |||
await check(RuleType.Hotspot, [RuleType.Vulnerability, RuleType.Hotspot]); | |||
}); | |||
async function check(ruleType: string, requestedTypes: string[] | undefined) { | |||
async function check(ruleType: RuleType, requestedTypes: RuleType[] | undefined) { | |||
const wrapper = shallow( | |||
<RuleDetailsIssues organization="org" ruleDetails={{ key: 'foo', type: ruleType }} /> | |||
); |
@@ -20,7 +20,7 @@ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import RuleDetailsMeta from '../RuleDetailsMeta'; | |||
import { RuleScope } from '../../../../app/types'; | |||
import { RuleScope, RuleType } from '../../../../app/types'; | |||
import RuleDetailsTagsPopup from '../RuleDetailsTagsPopup'; | |||
const RULE = { | |||
@@ -33,7 +33,7 @@ const RULE = { | |||
lang: 'java', | |||
langName: 'Java', | |||
scope: RuleScope.Main, | |||
type: 'CODE_SMELL' | |||
type: RuleType.CodeSmell | |||
}; | |||
const EXTERNAL_RULE = { | |||
@@ -44,7 +44,7 @@ const EXTERNAL_RULE = { | |||
status: 'READY', | |||
scope: RuleScope.All, | |||
isExternal: true, | |||
type: 'UNKNOWN' | |||
type: RuleType.Unknown | |||
}; | |||
const EXTERNAL_RULE_WITH_DATA = { | |||
@@ -59,7 +59,7 @@ const EXTERNAL_RULE_WITH_DATA = { | |||
langName: 'Xoo', | |||
scope: RuleScope.All, | |||
isExternal: true, | |||
type: 'BUG' | |||
type: RuleType.Bug | |||
}; | |||
it('should display right meta info', () => { |
@@ -20,7 +20,7 @@ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import RuleListItem from '../RuleListItem'; | |||
import { Rule } from '../../../../app/types'; | |||
import { Rule, RuleType } from '../../../../app/types'; | |||
import { mockEvent } from '../../../../helpers/testUtils'; | |||
const rule: Rule = { | |||
@@ -32,7 +32,7 @@ const rule: Rule = { | |||
status: 'READY', | |||
sysTags: ['a', 'b'], | |||
tags: ['x'], | |||
type: 'CODE_SMELL' | |||
type: RuleType.CodeSmell | |||
}; | |||
it('should render', () => { |
@@ -21,7 +21,7 @@ import * as React from 'react'; | |||
import { pickBy, sortBy } from 'lodash'; | |||
import { searchAssignees } from '../utils'; | |||
import { searchIssueTags, bulkChangeIssues } from '../../../api/issues'; | |||
import { Component, CurrentUser, Issue, Paging, isLoggedIn } from '../../../app/types'; | |||
import { Component, CurrentUser, Issue, Paging, isLoggedIn, IssueType } from '../../../app/types'; | |||
import throwGlobalError from '../../../app/utils/throwGlobalError'; | |||
import MarkdownTips from '../../../components/common/MarkdownTips'; | |||
import SearchSelect from '../../../components/controls/SearchSelect'; | |||
@@ -332,7 +332,7 @@ export default class BulkChangeModal extends React.PureComponent<Props, State> { | |||
return null; | |||
} | |||
const types = ['BUG', 'VULNERABILITY', 'CODE_SMELL']; | |||
const types = [IssueType.Bug, IssueType.Vulnerability, IssueType.CodeSmell]; | |||
const options = types.map(type => ({ label: translate('issue.type', type), value: type })); | |||
const optionRenderer = (option: { label: string; value: string }) => ( |
@@ -21,7 +21,7 @@ import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import BulkChangeModal from '../BulkChangeModal'; | |||
import { waitAndUpdate } from '../../../../helpers/testUtils'; | |||
import { Issue } from '../../../../app/types'; | |||
import { Issue, IssueType } from '../../../../app/types'; | |||
jest.mock('../../../../api/issues', () => ({ | |||
searchIssueTags: () => Promise.resolve([undefined, []]) | |||
@@ -55,7 +55,7 @@ it('should display form when issues are present', async () => { | |||
secondaryLocations: [], | |||
severity: 'foo', | |||
status: 'foo', | |||
type: 'foo' | |||
type: IssueType.Bug | |||
} | |||
]); | |||
await waitAndUpdate(wrapper); |
@@ -20,6 +20,7 @@ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import ConciseIssue from '../ConciseIssue'; | |||
import { IssueType } from '../../../../app/types'; | |||
const issue = { | |||
component: '', | |||
@@ -38,7 +39,7 @@ const issue = { | |||
ruleName: '', | |||
severity: '', | |||
status: '', | |||
type: '', | |||
type: IssueType.Bug, | |||
secondaryLocations: [], | |||
flows: [], | |||
fromHotspot: false |
@@ -27,7 +27,7 @@ exports[`should render 1`] = ` | |||
"secondaryLocations": Array [], | |||
"severity": "", | |||
"status": "", | |||
"type": "", | |||
"type": "BUG", | |||
} | |||
} | |||
onClick={[MockFunction]} |
@@ -28,6 +28,7 @@ import IssueTypeIcon from '../../../components/ui/IssueTypeIcon'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import DeferredSpinner from '../../../components/common/DeferredSpinner'; | |||
import MultipleSelectionHint from '../../../components/facet/MultipleSelectionHint'; | |||
import { IssueType } from '../../../app/types'; | |||
interface Props { | |||
fetching: boolean; | |||
@@ -38,7 +39,7 @@ interface Props { | |||
types: string[]; | |||
} | |||
const TYPES = ['BUG', 'VULNERABILITY', 'CODE_SMELL', 'SECURITY_HOTSPOT']; | |||
const TYPES = [IssueType.Bug, IssueType.Vulnerability, IssueType.CodeSmell, IssueType.Hotspot]; | |||
export default class TypeFacet extends React.PureComponent<Props> { | |||
property = 'types'; | |||
@@ -80,7 +81,8 @@ export default class TypeFacet extends React.PureComponent<Props> { | |||
// type is selected explicitly | |||
types.includes(type) || | |||
// bugs, vulnerabilities and code smells are selected implicitly by default | |||
(types.length === 0 && ['BUG', 'VULNERABILITY', 'CODE_SMELL'].includes(type)) | |||
(types.length === 0 && | |||
[IssueType.Bug, IssueType.Vulnerability, IssueType.CodeSmell].includes(type as IssueType)) | |||
); | |||
} | |||
@@ -29,6 +29,7 @@ import { getMetricName } from '../helpers/metrics'; | |||
import { getComponentDrilldownUrl } from '../../../helpers/urls'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { isLongLivingBranch } from '../../../helpers/branches'; | |||
import { IssueType } from '../../../app/types'; | |||
export class BugsAndVulnerabilities extends React.PureComponent<ComposedProps> { | |||
renderHeader() { | |||
@@ -81,7 +82,9 @@ export class BugsAndVulnerabilities extends React.PureComponent<ComposedProps> { | |||
<div className="overview-domain-measures"> | |||
<div className="overview-domain-measure"> | |||
<div className="overview-domain-measure-value"> | |||
<span style={{ marginLeft: 30 }}>{this.props.renderIssues('new_bugs', 'BUG')}</span> | |||
<span style={{ marginLeft: 30 }}> | |||
{this.props.renderIssues('new_bugs', IssueType.Bug)} | |||
</span> | |||
{this.props.renderRating('new_reliability_rating')} | |||
</div> | |||
<div className="overview-domain-measure-label"> | |||
@@ -92,7 +95,7 @@ export class BugsAndVulnerabilities extends React.PureComponent<ComposedProps> { | |||
<div className="overview-domain-measure"> | |||
<div className="overview-domain-measure-value"> | |||
<span style={{ marginLeft: 30 }}> | |||
{this.props.renderIssues('new_vulnerabilities', 'VULNERABILITY')} | |||
{this.props.renderIssues('new_vulnerabilities', IssueType.Vulnerability)} | |||
</span> | |||
{this.props.renderRating('new_security_rating')} | |||
</div> | |||
@@ -112,7 +115,7 @@ export class BugsAndVulnerabilities extends React.PureComponent<ComposedProps> { | |||
<div className="overview-domain-measures"> | |||
<div className="overview-domain-measure"> | |||
<div className="overview-domain-measure-value"> | |||
{this.props.renderIssues('bugs', 'BUG')} | |||
{this.props.renderIssues('bugs', IssueType.Bug)} | |||
{this.props.renderRating('reliability_rating')} | |||
</div> | |||
<div className="overview-domain-measure-label"> | |||
@@ -123,7 +126,7 @@ export class BugsAndVulnerabilities extends React.PureComponent<ComposedProps> { | |||
</div> | |||
<div className="overview-domain-measure"> | |||
<div className="overview-domain-measure-value"> | |||
{this.props.renderIssues('vulnerabilities', 'VULNERABILITY')} | |||
{this.props.renderIssues('vulnerabilities', IssueType.Vulnerability)} | |||
{this.props.renderRating('security_rating')} | |||
</div> | |||
<div className="overview-domain-measure-label"> |
@@ -25,6 +25,7 @@ import { translate, translateWithParameters } from '../../../helpers/l10n'; | |||
import { formatMeasure } from '../../../helpers/measures'; | |||
import CodeSmellIcon from '../../../components/icons-components/CodeSmellIcon'; | |||
import DrilldownLink from '../../../components/shared/DrilldownLink'; | |||
import { IssueType } from '../../../app/types'; | |||
export class CodeSmells extends React.PureComponent<ComposedProps> { | |||
renderHeader() { | |||
@@ -84,7 +85,7 @@ export class CodeSmells extends React.PureComponent<ComposedProps> { | |||
</div> | |||
<div className="overview-domain-measure"> | |||
<div className="overview-domain-measure-value"> | |||
{this.props.renderIssues('new_code_smells', 'CODE_SMELL')} | |||
{this.props.renderIssues('new_code_smells', IssueType.CodeSmell)} | |||
</div> | |||
<div className="overview-domain-measure-label"> | |||
<CodeSmellIcon className="little-spacer-right" /> | |||
@@ -114,7 +115,7 @@ export class CodeSmells extends React.PureComponent<ComposedProps> { | |||
</div> | |||
<div className="overview-domain-measure"> | |||
<div className="overview-domain-measure-value"> | |||
{this.props.renderIssues('code_smells', 'CODE_SMELL')} | |||
{this.props.renderIssues('code_smells', IssueType.CodeSmell)} | |||
</div> | |||
<div className="overview-domain-measure-label offset-left"> | |||
<CodeSmellIcon className="little-spacer-right " /> |
@@ -28,6 +28,7 @@ import { getPeriodValue, isDiffMetric, formatMeasure } from '../../../helpers/me | |||
import { translate } from '../../../helpers/l10n'; | |||
import { getComponentIssuesUrl } from '../../../helpers/urls'; | |||
import { getBranchLikeQuery } from '../../../helpers/branches'; | |||
import { IssueType } from '../../../app/types'; | |||
/*:: import type { Component } from '../types'; */ | |||
/*:: import type { MeasureEnhanced } from '../../../components/measure/types'; */ | |||
@@ -67,7 +68,7 @@ export default class QualityGateCondition extends React.PureComponent { | |||
}; | |||
getUrlForCodeSmells(sinceLeakPeriod /*: boolean */) { | |||
return this.getIssuesUrl(sinceLeakPeriod, { types: 'CODE_SMELL' }); | |||
return this.getIssuesUrl(sinceLeakPeriod, { types: IssueType.CodeSmell }); | |||
} | |||
getUrlForBugsOrVulnerabilities(type /*: string */, sinceLeakPeriod /*: boolean */) { | |||
@@ -88,7 +89,7 @@ export default class QualityGateCondition extends React.PureComponent { | |||
} | |||
getUrlForType(type /*: string */, sinceLeakPeriod /*: boolean */) { | |||
return type === 'CODE_SMELL' | |||
return type === IssueType.CodeSmell | |||
? this.getUrlForCodeSmells(sinceLeakPeriod) | |||
: this.getUrlForBugsOrVulnerabilities(type, sinceLeakPeriod); | |||
} | |||
@@ -104,14 +105,16 @@ export default class QualityGateCondition extends React.PureComponent { | |||
const metricKey = condition.measure.metric.key; | |||
/* eslint-disable camelcase */ | |||
const RATING_METRICS_MAPPING = { | |||
reliability_rating: ['BUG', false], | |||
new_reliability_rating: ['BUG', true], | |||
security_rating: ['VULNERABILITY', false], | |||
new_security_rating: ['VULNERABILITY', true], | |||
sqale_rating: ['CODE_SMELL', false], | |||
new_maintainability_rating: ['CODE_SMELL', true] | |||
reliability_rating: [IssueType.Bug, false], | |||
new_reliability_rating: [IssueType.Bug, true], | |||
security_rating: [IssueType.Vulnerability, false], | |||
new_security_rating: [IssueType.Vulnerability, true], | |||
sqale_rating: [IssueType.CodeSmell, false], | |||
new_maintainability_rating: [IssueType.CodeSmell, true] | |||
}; | |||
/* eslint-enable camelcase */ | |||
return RATING_METRICS_MAPPING[metricKey] ? ( | |||
<Link className={className} to={this.getUrlForType(...RATING_METRICS_MAPPING[metricKey])}> |
@@ -29,8 +29,9 @@ import { getQualityProfile } from '../../../api/quality-profiles'; | |||
import { getRulesUrl } from '../../../helpers/urls'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { Profile } from '../types'; | |||
import { RuleType } from '../../../app/types'; | |||
const TYPES = ['BUG', 'VULNERABILITY', 'CODE_SMELL', 'SECURITY_HOTSPOT']; | |||
const TYPES = [RuleType.Bug, RuleType.Vulnerability, RuleType.CodeSmell, RuleType.Hotspot] | |||
interface Props { | |||
organization: string | null; |
@@ -23,6 +23,7 @@ import ProfileRules from '../ProfileRules'; | |||
import * as apiRules from '../../../../api/rules'; | |||
import * as apiQP from '../../../../api/quality-profiles'; | |||
import { waitAndUpdate } from '../../../../helpers/testUtils'; | |||
import { RuleType } from '../../../../app/types'; | |||
const PROFILE = { | |||
activeRuleCount: 68, | |||
@@ -48,10 +49,10 @@ const apiResponseAll = { | |||
{ | |||
property: 'types', | |||
values: [ | |||
{ val: 'CODE_SMELL', count: 168 }, | |||
{ val: 'BUG', count: 68 }, | |||
{ val: 'VULNERABILITY', count: 7 }, | |||
{ val: 'SECURITY_HOTSPOT', count: 10 } | |||
{ val: RuleType.CodeSmell, count: 168 }, | |||
{ val: RuleType.Bug, count: 68 }, | |||
{ val: RuleType.Vulnerability, count: 7 }, | |||
{ val: RuleType.Hotspot, count: 10 } | |||
] | |||
} | |||
] | |||
@@ -63,10 +64,10 @@ const apiResponseActive = { | |||
{ | |||
property: 'types', | |||
values: [ | |||
{ val: 'BUG', count: 68 }, | |||
{ val: 'CODE_SMELL', count: 0 }, | |||
{ val: 'VULNERABILITY', count: 0 }, | |||
{ val: 'SECURITY_HOTSPOT', count: 0 } | |||
{ val: RuleType.Bug, count: 68 }, | |||
{ val: RuleType.CodeSmell, count: 0 }, | |||
{ val: RuleType.Vulnerability, count: 0 }, | |||
{ val: RuleType.Hotspot, count: 0 } | |||
] | |||
} | |||
] |
@@ -25,7 +25,7 @@ import { FormattedMessage } from 'react-intl'; | |||
import VulnerabilityList from './VulnerabilityList'; | |||
import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { Component, BranchLike, SecurityHotspot } from '../../../app/types'; | |||
import { Component, BranchLike, SecurityHotspot, RuleType } from '../../../app/types'; | |||
import DeferredSpinner from '../../../components/common/DeferredSpinner'; | |||
import Checkbox from '../../../components/controls/Checkbox'; | |||
import { RawQuery } from '../../../helpers/query'; | |||
@@ -154,7 +154,7 @@ export default class App extends React.PureComponent<Props, State> { | |||
link: ( | |||
<Link | |||
to={getRulesUrl( | |||
{ types: 'SECURITY_HOTSPOT,VULNERABILITY' }, | |||
{ types: [RuleType.Vulnerability, RuleType.Hotspot].join() }, | |||
isSonarCloud() ? component.organization : undefined | |||
)}> | |||
{translate('security_reports.info.link')} |
@@ -21,7 +21,7 @@ import * as React from 'react'; | |||
import * as classNames from 'classnames'; | |||
import { Link } from 'react-router'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { SecurityHotspot, Component, BranchLike } from '../../../app/types'; | |||
import { SecurityHotspot, Component, BranchLike, IssueType } from '../../../app/types'; | |||
import Rating from '../../../components/ui/Rating'; | |||
import { getComponentIssuesUrl } from '../../../helpers/urls'; | |||
import { getBranchLikeQuery } from '../../../helpers/branches'; | |||
@@ -125,7 +125,7 @@ export default class VulnerabilityList extends React.PureComponent<Props, State> | |||
const { branchLike, component, type } = this.props; | |||
const params: { [name: string]: string | undefined } = { | |||
...getBranchLikeQuery(branchLike), | |||
types: 'SECURITY_HOTSPOT' | |||
types: IssueType.Hotspot | |||
}; | |||
if (isCWE && parent) { | |||
params['cwe'] = finding.cwe; | |||
@@ -151,7 +151,7 @@ export default class VulnerabilityList extends React.PureComponent<Props, State> | |||
<Link | |||
to={getComponentIssuesUrl(component.key, { | |||
...params, | |||
types: 'VULNERABILITY', | |||
types: IssueType.Vulnerability, | |||
resolved: 'false' | |||
})}> | |||
{finding.vulnerabilities} | |||
@@ -161,7 +161,7 @@ export default class VulnerabilityList extends React.PureComponent<Props, State> | |||
className="link-no-underline spacer-left" | |||
to={getComponentIssuesUrl(component.key, { | |||
...params, | |||
types: 'VULNERABILITY', | |||
types: IssueType.Vulnerability, | |||
resolved: 'false' | |||
})}> | |||
<Rating value={finding.vulnerabilityRating || 1} /> | |||
@@ -173,7 +173,7 @@ export default class VulnerabilityList extends React.PureComponent<Props, State> | |||
<Link | |||
to={getComponentIssuesUrl(component.key, { | |||
...params, | |||
types: 'SECURITY_HOTSPOT', | |||
types: IssueType.Hotspot, | |||
resolved: 'false', | |||
statuses: 'OPEN,REOPENED' | |||
})}> | |||
@@ -184,7 +184,7 @@ export default class VulnerabilityList extends React.PureComponent<Props, State> | |||
<Link | |||
to={getComponentIssuesUrl(component.key, { | |||
...params, | |||
types: 'SECURITY_HOTSPOT', | |||
types: IssueType.Hotspot, | |||
resolutions: 'FIXED', | |||
statuses: 'RESOLVED' | |||
})}> | |||
@@ -195,7 +195,7 @@ export default class VulnerabilityList extends React.PureComponent<Props, State> | |||
<Link | |||
to={getComponentIssuesUrl(component.key, { | |||
...params, | |||
types: 'SECURITY_HOTSPOT', | |||
types: IssueType.Hotspot, | |||
resolutions: 'WONTFIX', | |||
statuses: 'RESOLVED' | |||
})}> |
@@ -54,7 +54,7 @@ exports[`handle checkbox for cwe display 1`] = ` | |||
Object { | |||
"pathname": "/coding_rules", | |||
"query": Object { | |||
"types": "SECURITY_HOTSPOT,VULNERABILITY", | |||
"types": "VULNERABILITY,SECURITY_HOTSPOT", | |||
}, | |||
} | |||
} | |||
@@ -164,7 +164,7 @@ exports[`handle checkbox for cwe display 2`] = ` | |||
Object { | |||
"pathname": "/coding_rules", | |||
"query": Object { | |||
"types": "SECURITY_HOTSPOT,VULNERABILITY", | |||
"types": "VULNERABILITY,SECURITY_HOTSPOT", | |||
}, | |||
} | |||
} | |||
@@ -317,7 +317,7 @@ exports[`renders owaspTop10 1`] = ` | |||
Object { | |||
"pathname": "/coding_rules", | |||
"query": Object { | |||
"types": "SECURITY_HOTSPOT,VULNERABILITY", | |||
"types": "VULNERABILITY,SECURITY_HOTSPOT", | |||
}, | |||
} | |||
} | |||
@@ -427,7 +427,7 @@ exports[`renders sansTop25 1`] = ` | |||
Object { | |||
"pathname": "/coding_rules", | |||
"query": Object { | |||
"types": "SECURITY_HOTSPOT,VULNERABILITY", | |||
"types": "VULNERABILITY,SECURITY_HOTSPOT", | |||
}, | |||
} | |||
} | |||
@@ -537,7 +537,7 @@ exports[`renders with cwe 1`] = ` | |||
Object { | |||
"pathname": "/coding_rules", | |||
"query": Object { | |||
"types": "SECURITY_HOTSPOT,VULNERABILITY", | |||
"types": "VULNERABILITY,SECURITY_HOTSPOT", | |||
}, | |||
} | |||
} |
@@ -26,7 +26,13 @@ import { Button } from '../../ui/buttons'; | |||
import { getFacets } from '../../../api/issues'; | |||
import { getMeasures } from '../../../api/measures'; | |||
import { getAllMetrics } from '../../../api/metrics'; | |||
import { FacetValue, SourceViewerFile, BranchLike, MeasureEnhanced } from '../../../app/types'; | |||
import { | |||
FacetValue, | |||
SourceViewerFile, | |||
BranchLike, | |||
MeasureEnhanced, | |||
IssueType | |||
} from '../../../app/types'; | |||
import Modal from '../../controls/Modal'; | |||
import Measure from '../../measure/Measure'; | |||
import QualifierIcon from '../../icons-components/QualifierIcon'; | |||
@@ -34,7 +40,7 @@ import SeverityHelper from '../../shared/SeverityHelper'; | |||
import CoverageRating from '../../ui/CoverageRating'; | |||
import DuplicationsRating from '../../ui/DuplicationsRating'; | |||
import IssueTypeIcon from '../../ui/IssueTypeIcon'; | |||
import { SEVERITIES, TYPES } from '../../../helpers/constants'; | |||
import { SEVERITIES, ISSUE_TYPES } from '../../../helpers/constants'; | |||
import { translate, getLocalizedMetricName } from '../../../helpers/l10n'; | |||
import { | |||
formatMeasure, | |||
@@ -61,7 +67,7 @@ interface State { | |||
severitiesFacet?: FacetValue[]; | |||
showAllMeasures: boolean; | |||
tagsFacet?: FacetValue[]; | |||
typesFacet?: FacetValue[]; | |||
typesFacet?: FacetValue<IssueType>[]; | |||
} | |||
export default class MeasuresOverlay extends React.PureComponent<Props, State> { | |||
@@ -125,7 +131,7 @@ export default class MeasuresOverlay extends React.PureComponent<Props, State> { | |||
return { | |||
severitiesFacet: severitiesFacet && severitiesFacet.values, | |||
tagsFacet: tagsFacet && tagsFacet.values, | |||
typesFacet: typesFacet && typesFacet.values | |||
typesFacet: typesFacet && (typesFacet.values as FacetValue<IssueType>[]) | |||
}; | |||
}); | |||
}; | |||
@@ -197,7 +203,7 @@ export default class MeasuresOverlay extends React.PureComponent<Props, State> { | |||
{typesFacet && ( | |||
<div className="measures"> | |||
<div className="measures-list"> | |||
{sortBy(typesFacet, f => TYPES.indexOf(f.val)).map(f => ( | |||
{sortBy(typesFacet, f => ISSUE_TYPES.indexOf(f.val)).map(f => ( | |||
<div className="measure measure-one-line" key={f.val}> | |||
<span className="measure-name"> | |||
<IssueTypeIcon className="little-spacer-right" query={f.val} /> |
@@ -20,7 +20,7 @@ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import LineCode from '../LineCode'; | |||
import { BranchType, Issue, ShortLivingBranch } from '../../../../app/types'; | |||
import { BranchType, Issue, ShortLivingBranch, IssueType } from '../../../../app/types'; | |||
const issueBase: Issue = { | |||
component: '', | |||
@@ -42,7 +42,7 @@ const issueBase: Issue = { | |||
secondaryLocations: [], | |||
severity: '', | |||
status: '', | |||
type: '' | |||
type: IssueType.Bug | |||
}; | |||
it('render code', () => { |
@@ -21,7 +21,7 @@ import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import { click } from '../../../../helpers/testUtils'; | |||
import LineIssuesIndicator from '../LineIssuesIndicator'; | |||
import { Issue } from '../../../../app/types'; | |||
import { Issue, IssueType } from '../../../../app/types'; | |||
const issueBase: Issue = { | |||
component: '', | |||
@@ -43,7 +43,7 @@ const issueBase: Issue = { | |||
secondaryLocations: [], | |||
severity: '', | |||
status: '', | |||
type: '' | |||
type: IssueType.Bug | |||
}; | |||
it('render highest severity', () => { |
@@ -20,7 +20,7 @@ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import LineIssuesList from '../LineIssuesList'; | |||
import { Issue } from '../../../../app/types'; | |||
import { Issue, IssueType } from '../../../../app/types'; | |||
const issueBase: Issue = { | |||
component: '', | |||
@@ -42,7 +42,7 @@ const issueBase: Issue = { | |||
secondaryLocations: [], | |||
severity: '', | |||
status: '', | |||
type: '' | |||
type: IssueType.Bug | |||
}; | |||
it('render issues list', () => { |
@@ -66,7 +66,7 @@ exports[`render code 1`] = ` | |||
"secondaryLocations": Array [], | |||
"severity": "", | |||
"status": "", | |||
"type": "", | |||
"type": "BUG", | |||
}, | |||
Object { | |||
"component": "", | |||
@@ -88,7 +88,7 @@ exports[`render code 1`] = ` | |||
"secondaryLocations": Array [], | |||
"severity": "", | |||
"status": "", | |||
"type": "", | |||
"type": "BUG", | |||
}, | |||
] | |||
} |
@@ -28,7 +28,7 @@ exports[`render issues list 1`] = ` | |||
"secondaryLocations": Array [], | |||
"severity": "", | |||
"status": "", | |||
"type": "", | |||
"type": "BUG", | |||
} | |||
} | |||
key="foo" | |||
@@ -61,7 +61,7 @@ exports[`render issues list 1`] = ` | |||
"secondaryLocations": Array [], | |||
"severity": "", | |||
"status": "", | |||
"type": "", | |||
"type": "BUG", | |||
} | |||
} | |||
key="bar" |
@@ -26,6 +26,7 @@ import IssueTags from './IssueTags'; | |||
import IssueTransition from './IssueTransition'; | |||
import IssueType from './IssueType'; | |||
import { updateIssue } from '../actions'; | |||
import { IssueType as IssueTypes } from '../../../app/types'; | |||
import { translate, translateWithParameters } from '../../../helpers/l10n'; | |||
/*:: import type { Issue } from '../types'; */ | |||
@@ -81,7 +82,7 @@ export default class IssueActionsBar extends React.PureComponent { | |||
this.props.onChange(issue); | |||
if ( | |||
issue.resolution === 'FALSE-POSITIVE' || | |||
(issue.resolution === 'WONTFIX' && issue.type !== 'SECURITY_HOTSPOT') | |||
(issue.resolution === 'WONTFIX' && issue.type !== IssueTypes.Hotspot) | |||
) { | |||
this.toggleComment(true, translate('issue.comment.tell_why')); | |||
} | |||
@@ -95,7 +96,7 @@ export default class IssueActionsBar extends React.PureComponent { | |||
const canSetType = issue.actions.includes('set_type'); | |||
const canSetTags = issue.actions.includes('set_tags'); | |||
const hasTransitions = issue.transitions && issue.transitions.length > 0; | |||
const isSecurityHotspot = issue.type === 'SECURITY_HOTSPOT'; | |||
const isSecurityHotspot = issue.type === IssueTypes.Hotspot; | |||
return ( | |||
<div className="issue-actions"> |
@@ -30,6 +30,7 @@ import { getBranchLikeQuery } from '../../../helpers/branches'; | |||
import { getComponentIssuesUrl } from '../../../helpers/urls'; | |||
import { formatMeasure } from '../../../helpers/measures'; | |||
import { translate, translateWithParameters } from '../../../helpers/l10n'; | |||
import { IssueType } from '../../../app/types'; | |||
/*:: import type { Issue } from '../types'; */ | |||
/*:: | |||
@@ -75,7 +76,7 @@ export default function IssueTitleBar(props /*: Props */) { | |||
<div className="issue-row"> | |||
<IssueMessage | |||
engine={issue.externalRuleEngine} | |||
manualVulnerability={issue.fromHotspot && issue.type === 'VULNERABILITY'} | |||
manualVulnerability={issue.fromHotspot && issue.type === IssueType.Vulnerability} | |||
message={issue.message} | |||
organization={issue.organization} | |||
rule={issue.rule} |
@@ -24,6 +24,7 @@ import IssueTypeIcon from '../../ui/IssueTypeIcon'; | |||
import SelectList from '../../common/SelectList'; | |||
import SelectListItem from '../../common/SelectListItem'; | |||
import { DropdownOverlay } from '../../controls/Dropdown'; | |||
import { IssueType } from '../../../app/types'; | |||
/*:: import type { Issue } from '../types'; */ | |||
/*:: | |||
@@ -33,7 +34,7 @@ type Props = { | |||
}; | |||
*/ | |||
const TYPES = ['BUG', 'VULNERABILITY', 'CODE_SMELL']; | |||
const TYPES = [IssueType.Bug, IssueType.Vulnerability, IssueType.CodeSmell]; | |||
export default class SetTypePopup extends React.PureComponent { | |||
/*:: props: Props; */ |
@@ -20,8 +20,9 @@ | |||
import { shallow } from 'enzyme'; | |||
import React from 'react'; | |||
import SetTypePopup from '../SetTypePopup'; | |||
import { IssueType } from '../../../../app/types'; | |||
it('should render tags popup correctly', () => { | |||
const element = shallow(<SetTypePopup issue={{ type: 'BUG' }} onSelect={jest.fn()} />); | |||
const element = shallow(<SetTypePopup issue={{ type: IssueType.Bug }} onSelect={jest.fn()} />); | |||
expect(element).toMatchSnapshot(); | |||
}); |
@@ -20,7 +20,7 @@ | |||
import * as React from 'react'; | |||
import { Link } from 'react-router'; | |||
import { getComponentDrilldownUrl, getComponentIssuesUrl } from '../../helpers/urls'; | |||
import { BranchLike } from '../../app/types'; | |||
import { BranchLike, IssueType } from '../../app/types'; | |||
import { getBranchLikeQuery } from '../../helpers/branches'; | |||
const ISSUE_MEASURES = [ | |||
@@ -104,15 +104,15 @@ export default class DrilldownLink extends React.PureComponent<Props> { | |||
break; | |||
case 'code_smells': | |||
case 'new_code_smells': | |||
Object.assign(params, { resolved: 'false', types: 'CODE_SMELL' }); | |||
Object.assign(params, { resolved: 'false', types: IssueType.CodeSmell }); | |||
break; | |||
case 'bugs': | |||
case 'new_bugs': | |||
Object.assign(params, { resolved: 'false', types: 'BUG' }); | |||
Object.assign(params, { resolved: 'false', types: IssueType.Bug }); | |||
break; | |||
case 'vulnerabilities': | |||
case 'new_vulnerabilities': | |||
Object.assign(params, { resolved: 'false', types: 'VULNERABILITY' }); | |||
Object.assign(params, { resolved: 'false', types: IssueType.Vulnerability }); | |||
break; | |||
default: | |||
Object.assign(params, { resolved: 'false' }); |
@@ -20,10 +20,11 @@ | |||
import * as React from 'react'; | |||
import IssueTypeIcon from '../ui/IssueTypeIcon'; | |||
import { translate } from '../../helpers/l10n'; | |||
import { RuleType, IssueType } from '../../app/types'; | |||
interface Props { | |||
className?: string; | |||
type: string; | |||
type: IssueType | RuleType; | |||
} | |||
export default function TypeHelper(props: Props) { |
@@ -18,10 +18,22 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as theme from '../app/theme'; | |||
import { RuleType, IssueType } from '../app/types'; | |||
export const SEVERITIES = ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO']; | |||
export const STATUSES = ['OPEN', 'REOPENED', 'CONFIRMED', 'RESOLVED', 'CLOSED']; | |||
export const TYPES = ['BUG', 'VULNERABILITY', 'CODE_SMELL', 'SECURITY_HOTSPOT']; | |||
export const ISSUE_TYPES = [ | |||
IssueType.Bug, | |||
IssueType.Vulnerability, | |||
IssueType.CodeSmell, | |||
IssueType.Hotspot | |||
]; | |||
export const RULE_TYPES = [ | |||
RuleType.Bug, | |||
RuleType.Vulnerability, | |||
RuleType.CodeSmell, | |||
RuleType.Hotspot | |||
]; | |||
export const RULE_STATUSES = ['READY', 'BETA', 'DEPRECATED']; | |||
export const CHART_COLORS_RANGE_PERCENT = [ |