import React , { FC } from 'react' ; import { Box , makeStyles } from '@material-ui/core' ; import Alert from '@material-ui/lab/Alert' ; import { InfoCard , Progress , StructuredMetadataTable , } from '@backstage/core-components' ; import { useApi , githubAuthApiRef , } from '@backstage/core-plugin-api' ; import { useAsync } from 'react-use' ; import { Octokit } from '@octokit/rest' ; import { useProjectEntity } from '../useProjectEntity' ; import { useUrl } from '../useUrl' ; import { getSeverityBadge } from '../utils' ; import { SecurityInsight , IssuesCounterProps , SeverityLevels , SecurityInsightFilterState , } from '../../types' ; import { Entity } from '@backstage/catalog-model' ; import { useEntity } from "@backstage/plugin-catalog-react" ; const useStyles = makeStyles ( ( theme ) => ( { infoCard : { marginBottom : theme . spacing ( 3 ) , } , } ) ) ; const IssuesCounter = ( { issues , issueStatus = null , } ) => { const countIssues = ( type , severityLevel ) => issues . reduce ( ( acc , cur ) => ( cur . state === type || issueStatus === null ) && cur . rule . severity === severityLevel ? ++ acc : acc , 0 ) ; const countWarningIssues = countIssues ( issueStatus , 'warning' ) ; const countErrorIssues = countIssues ( issueStatus , 'error' ) ; const countNoteIssues = countIssues ( issueStatus , 'note' ) ; return ( < Box display = "flex" flexDirection = "column" > { getSeverityBadge ( 'warning' , countWarningIssues ) } { getSeverityBadge ( 'error' , countErrorIssues ) } { getSeverityBadge ( 'note' , countNoteIssues ) } < /Box>); } ; type Props = { deprecated entity ? : Entity ; } ; export const SecurityInsightsWidget = ( _props ) => { const { entity } = useEntity ( ) ; const { owner , repo } = useProjectEntity ( entity ) ; const classes = useStyles ( ) ; const auth = useApi ( githubAuthApiRef ) ; const { baseUrl , hostname } = useUrl ( entity ) ; const { value , loading , error } = useAsync ( async ( ) : Promise < SecurityInsight [ ] > => { const token = await auth . getAccessToken ( [ 'repo' ] ) ; const octokit = new Octokit ( { auth : token } ) ; const response = await octokit . request ( 'GET /repos/{owner}/{repo}/code-scanning/alerts' , { baseUrl , owner , repo , } ) ; const data = response . data as SecurityInsight [ ] ; return data ; } , [ ] ) ; return ( < InfoCard title = "Security Insights" className = { classes . infoCard } deepLink = { { link : `//${ hostname }/${ owner }/${ repo }/security/code-scanning` , title : 'Security Insights' , onClick : ( e ) => { e . preventDefault ( ) ; window . open ( `//${ hostname }/${ owner }/${ repo }/security/code-scanning` ) ; } , } } > < Box position = "relative" > { error ? ( < Alert severity = "error" className = { classes . infoCard } > { error . message } < /Alert>) : null} { loading ? ( < Box my = { 3 } > < Progress /> < /Box>) : (<> { value ? ( < StructuredMetadataTable metadata = { { 'Open Issues' : ( < IssuesCounter issues = { value } issueStatus = "open" / > ) , } } />) : null} < />)} < /Box> < /InfoCard>); } ;