109 lines
3.4 KiB
TypeScript
109 lines
3.4 KiB
TypeScript
|
import { useQuery } from '@apollo/client';
|
||
|
import { faPlayCircle, faVial } from '@fortawesome/free-solid-svg-icons';
|
||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||
|
import { CircularProgress, Collapse, IconButton, LinearProgress, List, ListItem, ListItemIcon, ListItemSecondaryAction, ListItemText, makeStyles, useTheme } from '@material-ui/core';
|
||
|
import { Cancel, CheckCircle, CloudDownload, ShoppingCart, Timer } from '@material-ui/icons';
|
||
|
import { format } from 'date-fns';
|
||
|
import React, { FC, Fragment, ReactNode, useState } from 'react';
|
||
|
import { Commit, Pipeline, PipelineTask, TaskStatuses } from '../generated/graphql';
|
||
|
import { COMMITS } from './queries';
|
||
|
|
||
|
interface Props {
|
||
|
pipeline: Pipeline;
|
||
|
}
|
||
|
|
||
|
const useStyles = makeStyles((theme) => ({
|
||
|
root: {
|
||
|
flex: "1 1 100%",
|
||
|
},
|
||
|
nested: {
|
||
|
paddingLeft: theme.spacing(4),
|
||
|
},
|
||
|
}));
|
||
|
|
||
|
export const CommitList: FC<Props> = ({pipeline}) => {
|
||
|
const { data, loading } = useQuery<{ commits: Commit[] }>(COMMITS, {
|
||
|
variables: {
|
||
|
pipelineId: pipeline.id,
|
||
|
},
|
||
|
});
|
||
|
|
||
|
const classes = useStyles();
|
||
|
|
||
|
return (
|
||
|
<section className={classes.root}>
|
||
|
{(() => {
|
||
|
if (loading) {
|
||
|
return <LinearProgress color="secondary" />;
|
||
|
}
|
||
|
|
||
|
return <List>
|
||
|
{data?.commits.map(commit => (
|
||
|
<Item key={commit.hash} commit={commit} />
|
||
|
))}
|
||
|
</List>;
|
||
|
})()}
|
||
|
</section>
|
||
|
)
|
||
|
}
|
||
|
|
||
|
const Item: FC<{commit: Commit}> = ({commit}) => {
|
||
|
const [isOpen, setOpen] = useState(() => false);
|
||
|
const classes = useStyles();
|
||
|
return (
|
||
|
<Fragment>
|
||
|
<ListItem button onClick={() => setOpen(!isOpen)}>
|
||
|
<ListItemText
|
||
|
primary={commit.message}
|
||
|
secondary={format(commit.date, "yyyy-MM-dd HH:mm:ss")}
|
||
|
/>
|
||
|
<ListItemSecondaryAction>
|
||
|
<IconButton edge="end" aria-label="delete">
|
||
|
<ShoppingCart />
|
||
|
</IconButton>
|
||
|
<IconButton edge="end" aria-label="delete">
|
||
|
<CloudDownload />
|
||
|
</IconButton>
|
||
|
<IconButton edge="end" aria-label="delete">
|
||
|
<FontAwesomeIcon icon={faVial} />
|
||
|
</IconButton>
|
||
|
<IconButton edge="end" aria-label="delete">
|
||
|
<FontAwesomeIcon icon={faPlayCircle} />
|
||
|
</IconButton>
|
||
|
</ListItemSecondaryAction>
|
||
|
</ListItem>
|
||
|
<Collapse in={isOpen} timeout="auto" unmountOnExit>
|
||
|
<List component="div" disablePadding>
|
||
|
{
|
||
|
commit.tasks.map(task => (<TaskItem key={task.id} task={task} />))
|
||
|
}
|
||
|
</List>
|
||
|
</Collapse>
|
||
|
</Fragment>
|
||
|
);
|
||
|
}
|
||
|
|
||
|
const TaskItem: FC<{task: PipelineTask}> = ({task}) => {
|
||
|
const classes = useStyles();
|
||
|
const theme = useTheme();
|
||
|
const statusIcon: ReactNode = (() => {
|
||
|
switch (task.status) {
|
||
|
case TaskStatuses.Pending:
|
||
|
return <Timer style={{ color: theme.palette.info.main }} />;
|
||
|
case TaskStatuses.Success:
|
||
|
return <CheckCircle style={{ color: theme.palette.success.main }} />;
|
||
|
case TaskStatuses.Failed:
|
||
|
return <Cancel style={{ color: theme.palette.error.main }} />;
|
||
|
case TaskStatuses.Working:
|
||
|
return <CircularProgress style={{ color: theme.palette.secondary.main }} />;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
)()
|
||
|
return (
|
||
|
<ListItem button className={classes.nested}>
|
||
|
<ListItemIcon>{statusIcon}</ListItemIcon>
|
||
|
<ListItemText primary={format(task.startedAt, "yyyy-MM-dd HH:mm:ss")} />
|
||
|
</ListItem>
|
||
|
);
|
||
|
};
|