import React , { FC , useEffect } from 'react' ; import { Typography , Grid , Breadcrumbs , IconButton , makeStyles , Box , } from '@material-ui/core' ; import { InfoCard , Page , Content , Link as MaterialLink , } from '@backstage/core-components' ; import { useParams } from 'react-router-dom' ; import Alert from '@material-ui/lab/Alert' ; import { Entity } from '@backstage/catalog-model' ; import LaunchIcon from '@material-ui/icons/Launch' ; import { ActionOutput } from './components/ActionOutput' ; import { useSingleBuild } from '../useSingleBuild' ; import { useProjectEntity } from '../useProjectEntity' ; import { BuildkiteBuildInfo , BuildkiteJob } from '../types' ; const useStyles = makeStyles ( theme => ( { neutral : { } , failed : { position : 'relative' , '&:after' : { pointerEvents : 'none' , content : '""' , position : 'absolute' , top : 0 , right : 0 , left : 0 , bottom : 0 , boxShadow : `inset 4px 0px 0px ${ theme . palette . error . main }` , } , } , running : { position : 'relative' , '&:after' : { pointerEvents : 'none' , content : '""' , position : 'absolute' , top : 0 , right : 0 , left : 0 , bottom : 0 , boxShadow : `inset 4px 0px 0px ${ theme . palette . info . main }` , } , } , cardContent : { backgroundColor : theme . palette . background . default , padding : '0!important' , } , success : { position : 'relative' , '&:after' : { pointerEvents : 'none' , content : '""' , position : 'absolute' , top : 0 , right : 0 , left : 0 , bottom : 0 , boxShadow : `inset 4px 0px 0px ${ theme . palette . success . main }` , } , } , } ) ) ; const BuildName = ( { build } ) => ( < Box display = "flex" alignItems = "center" > # { build ?. number } - { build ?. message } < IconButton href = { build ?. web_url as string } target = "_blank" rel = "noopener noreferrer" > < LaunchIcon /> < /IconButton> < /Box>); const pickClassName = ( classes , build ) => { if ( build . state === 'failed' ) return classes . failed ; if ( [ 'running' , 'queued' , 'scheduled' , 'assigned' ] . includes ( build . state ) ) return classes . running ; if ( build . state === 'passed' ) return classes . success ; return classes . neutral ; } ; const ActionsList = ( { jobs , } ) => { const classes = useStyles ( ) ; return ( < > { jobs . map ( ( job ) => ( < ActionOutput className = { pickClassName ( classes , job ) } job = { job } url = { job . log_url || '' } key = { job . id } / > ) ) } < />); } ; const BuildsList = ( { build } ) => ( < Box > { build . jobs ? < ActionsList jobs = { build . jobs } /> : < Alert severity = "error" > Jobs list is empty < /Alert>} < /Box>); const BuildkiteBuildView = ( { entity } ) => { const classes = useStyles ( ) ; const { buildNumber } = useParams ( ) as any ; const { owner , repo } = useProjectEntity ( entity ) ; const { value , error , fetchBuildData } = useSingleBuild ( { owner , repo , buildNumber } ) ; useEffect ( ( ) => { fetchBuildData ( ) ; } , [ fetchBuildData ] ) ; useEffect ( ( ) => { let timer ; if ( value ?. state === 'running' || value ?. state === 'schedudled' ) { timer = setTimeout ( ( ) => { fetchBuildData ( ) ; } , 1500 ) ; } return ( ) => clearTimeout ( timer ) ; } , [ value , fetchBuildData ] ) ; if ( error ) { return < Alert severity = "error" > { error . message } < /Alert>; } return value ? ( < Page themeId = "tool" > < Content > < Breadcrumbs aria - label = "breadcrumb" > < MaterialLink to = ".." > All builds < /MaterialLink> < Typography > Build details < /Typography> < /Breadcrumbs> < Grid container spacing = { 3 } direction = "column" > < Grid item > < Box mt = { 3 } > < InfoCard title = { < BuildName build = { value } />} cardClassName={classes.cardContent}> < BuildsList build = { value } / > < /InfoCard> < /Box> < /Grid> < /Grid> < /Content> < /Page>) : null; } ; export default BuildkiteBuildView ;