@@ -258,7 +258,7 @@ export default class RuleDetails extends React.PureComponent<Props, State> { | |||
/> | |||
)} | |||
{!ruleDetails.isTemplate && ( | |||
{!ruleDetails.isTemplate && ruleDetails.type !== 'SECURITY_HOTSPOT' && ( | |||
<RuleDetailsIssues organization={organization} ruleDetails={ruleDetails} /> | |||
)} | |||
</DeferredSpinner> |
@@ -47,7 +47,7 @@ interface State { | |||
export class RuleDetailsIssues extends React.PureComponent<Props, State> { | |||
mounted = false; | |||
state: State = { loading: true }; | |||
state: State = { loading: false }; | |||
componentDidMount() { | |||
this.mounted = true; | |||
@@ -64,19 +64,19 @@ export class RuleDetailsIssues extends React.PureComponent<Props, State> { | |||
this.mounted = false; | |||
} | |||
getBaseIssuesQuery = () => ({ | |||
resolved: 'false', | |||
rules: this.props.ruleDetails.key, | |||
types: | |||
this.props.ruleDetails.type === 'SECURITY_HOTSPOT' | |||
? ['VULNERABILITY', 'SECURITY_HOTSPOT'].join() | |||
: undefined | |||
}); | |||
fetchIssues = () => { | |||
const { | |||
ruleDetails: { key }, | |||
organization | |||
} = this.props; | |||
this.setState({ loading: true }); | |||
getFacet( | |||
{ ...this.getBaseIssuesQuery(), organization: this.props.organization }, | |||
{ | |||
resolved: 'false', | |||
rules: key, | |||
organization | |||
}, | |||
'projects' | |||
).then( | |||
({ facet, response }) => { | |||
@@ -101,11 +101,16 @@ export class RuleDetailsIssues extends React.PureComponent<Props, State> { | |||
}; | |||
renderTotal = () => { | |||
const { | |||
ruleDetails: { key }, | |||
organization | |||
} = this.props; | |||
const { total } = this.state; | |||
if (total === undefined) { | |||
return null; | |||
} | |||
const path = getIssuesUrl(this.getBaseIssuesQuery(), this.props.organization); | |||
const path = getIssuesUrl({ resolved: 'false', rules: key }, organization); | |||
const totalItem = ( | |||
<span className="little-spacer-left"> | |||
@@ -125,9 +130,14 @@ export class RuleDetailsIssues extends React.PureComponent<Props, State> { | |||
}; | |||
renderProject = (project: Project) => { | |||
const { | |||
ruleDetails: { key }, | |||
organization | |||
} = this.props; | |||
const path = getIssuesUrl( | |||
{ ...this.getBaseIssuesQuery(), projects: project.key }, | |||
this.props.organization | |||
{ resolved: 'false', rules: key, projects: project.key }, | |||
organization | |||
); | |||
return ( | |||
<tr key={project.key}> |
@@ -44,30 +44,26 @@ beforeEach(() => { | |||
}); | |||
it('should fetch issues and render', async () => { | |||
await check('BUG', undefined); | |||
}); | |||
it('should handle hotspot rules', async () => { | |||
await check('SECURITY_HOTSPOT', ['VULNERABILITY', 'SECURITY_HOTSPOT']); | |||
}); | |||
async function check(ruleType: T.RuleType, requestedTypes: T.RuleType[] | undefined) { | |||
const wrapper = shallow( | |||
<RuleDetailsIssues | |||
appState={{ branchesEnabled: false }} | |||
organization="org" | |||
ruleDetails={{ key: 'foo', type: ruleType }} | |||
/> | |||
); | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper).toMatchSnapshot(); | |||
expect(getFacet).toBeCalledWith( | |||
{ | |||
organization: 'org', | |||
resolved: 'false', | |||
rules: 'foo', | |||
types: requestedTypes && requestedTypes.join() | |||
rules: 'foo' | |||
}, | |||
'projects' | |||
); | |||
}); | |||
function shallowRender(props: Partial<RuleDetailsIssues['props']> = {}) { | |||
return shallow( | |||
<RuleDetailsIssues | |||
appState={{ branchesEnabled: false }} | |||
organization="org" | |||
ruleDetails={{ key: 'foo', type: 'BUG' }} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -28,7 +28,6 @@ exports[`should fetch issues and render 1`] = ` | |||
"query": Object { | |||
"resolved": "false", | |||
"rules": "foo", | |||
"types": undefined, | |||
}, | |||
} | |||
} | |||
@@ -71,7 +70,6 @@ exports[`should fetch issues and render 1`] = ` | |||
"projects": "sample-key", | |||
"resolved": "false", | |||
"rules": "foo", | |||
"types": undefined, | |||
}, | |||
} | |||
} | |||
@@ -101,123 +99,6 @@ exports[`should fetch issues and render 1`] = ` | |||
"projects": "example-key", | |||
"resolved": "false", | |||
"rules": "foo", | |||
"types": undefined, | |||
}, | |||
} | |||
} | |||
> | |||
5 | |||
</Link> | |||
</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</DeferredSpinner> | |||
</div> | |||
`; | |||
exports[`should handle hotspot rules 1`] = ` | |||
<div | |||
className="js-rule-issues coding-rule-section" | |||
> | |||
<div | |||
className="coding-rule-section-separator" | |||
/> | |||
<DeferredSpinner | |||
loading={false} | |||
timeout={100} | |||
> | |||
<h3 | |||
className="coding-rules-detail-title" | |||
> | |||
coding_rules.issues | |||
<span | |||
className="little-spacer-left" | |||
> | |||
( | |||
<Link | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to={ | |||
Object { | |||
"pathname": "/organizations/org/issues", | |||
"query": Object { | |||
"resolved": "false", | |||
"rules": "foo", | |||
"types": "VULNERABILITY,SECURITY_HOTSPOT", | |||
}, | |||
} | |||
} | |||
> | |||
18 | |||
</Link> | |||
) | |||
</span> | |||
</h3> | |||
<table | |||
className="coding-rules-detail-list coding-rules-most-violated-projects" | |||
> | |||
<tbody> | |||
<tr> | |||
<td | |||
className="coding-rules-detail-list-name" | |||
colSpan={2} | |||
> | |||
coding_rules.most_violating_projects | |||
</td> | |||
</tr> | |||
<tr | |||
key="sample-key" | |||
> | |||
<td | |||
className="coding-rules-detail-list-name" | |||
> | |||
Sample | |||
</td> | |||
<td | |||
className="coding-rules-detail-list-parameters" | |||
> | |||
<Link | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to={ | |||
Object { | |||
"pathname": "/organizations/org/issues", | |||
"query": Object { | |||
"projects": "sample-key", | |||
"resolved": "false", | |||
"rules": "foo", | |||
"types": "VULNERABILITY,SECURITY_HOTSPOT", | |||
}, | |||
} | |||
} | |||
> | |||
13 | |||
</Link> | |||
</td> | |||
</tr> | |||
<tr | |||
key="example-key" | |||
> | |||
<td | |||
className="coding-rules-detail-list-name" | |||
> | |||
Example | |||
</td> | |||
<td | |||
className="coding-rules-detail-list-parameters" | |||
> | |||
<Link | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to={ | |||
Object { | |||
"pathname": "/organizations/org/issues", | |||
"query": Object { | |||
"projects": "example-key", | |||
"resolved": "false", | |||
"rules": "foo", | |||
"types": "VULNERABILITY,SECURITY_HOTSPOT", | |||
}, | |||
} | |||
} |