mirror of
https://github.com/hibiken/asynqmon.git
synced 2025-01-19 03:05:53 +08:00
Add breadcrumb to task view
This commit is contained in:
parent
b2c8de61bb
commit
2b2d5f88a5
87
ui/src/components/QueueBreadcrumb.tsx
Normal file
87
ui/src/components/QueueBreadcrumb.tsx
Normal file
@ -0,0 +1,87 @@
|
||||
import React, { useState } from "react";
|
||||
import { Link, useHistory } from "react-router-dom";
|
||||
import { emphasize, withStyles, Theme } from "@material-ui/core/styles";
|
||||
import Breadcrumbs from "@material-ui/core/Breadcrumbs";
|
||||
import Chip from "@material-ui/core/Chip";
|
||||
import Menu from "@material-ui/core/Menu";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import { paths, queueDetailsPath } from "../paths";
|
||||
|
||||
const StyledBreadcrumb = withStyles((theme: Theme) => ({
|
||||
root: {
|
||||
backgroundColor:
|
||||
theme.palette.type === "dark"
|
||||
? "#303030"
|
||||
: theme.palette.background.default,
|
||||
height: theme.spacing(3),
|
||||
color: theme.palette.text.secondary,
|
||||
fontWeight: theme.typography.fontWeightRegular,
|
||||
"&:hover, &:focus": {
|
||||
backgroundColor: theme.palette.action.hover,
|
||||
},
|
||||
"&:active": {
|
||||
boxShadow: theme.shadows[1],
|
||||
backgroundColor: emphasize(theme.palette.action.hover, 0.12),
|
||||
},
|
||||
},
|
||||
}))(Chip) as typeof Chip; // Note: need a type cast here because https://github.com/Microsoft/TypeScript/issues/26591
|
||||
|
||||
interface Props {
|
||||
// All queue names.
|
||||
queues: string[];
|
||||
// Name of the queue currently selected.
|
||||
selectedQueue: string;
|
||||
}
|
||||
|
||||
export default function QueueBreadcrumbs(props: Props) {
|
||||
const history = useHistory();
|
||||
const [anchorEl, setAnchorEl] = useState<null | Element>(null);
|
||||
|
||||
const handleClick = (event: React.MouseEvent<Element, MouseEvent>) => {
|
||||
event.preventDefault();
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const closeMenu = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Breadcrumbs aria-label="breadcrumb">
|
||||
<StyledBreadcrumb
|
||||
component={Link}
|
||||
to={paths.HOME}
|
||||
label="Queues"
|
||||
onClick={() => history.push(paths.HOME)}
|
||||
/>
|
||||
<StyledBreadcrumb
|
||||
label={props.selectedQueue}
|
||||
deleteIcon={<ExpandMoreIcon />}
|
||||
onClick={handleClick}
|
||||
onDelete={handleClick}
|
||||
/>
|
||||
</Breadcrumbs>
|
||||
<Menu
|
||||
id="queue-breadcrumb-menu"
|
||||
anchorEl={anchorEl}
|
||||
keepMounted
|
||||
open={Boolean(anchorEl)}
|
||||
onClose={closeMenu}
|
||||
>
|
||||
{props.queues.sort().map((qname) => (
|
||||
<MenuItem
|
||||
key={qname}
|
||||
onClick={() => {
|
||||
history.push(queueDetailsPath(qname));
|
||||
closeMenu();
|
||||
}}
|
||||
>
|
||||
{qname}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
</>
|
||||
);
|
||||
}
|
@ -3,6 +3,7 @@ import { connect, ConnectedProps } from "react-redux";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import { AppState } from "../store";
|
||||
import { percentage } from "../utils";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
banner: {
|
||||
@ -92,7 +93,9 @@ function QueueInfoBanner(props: Props & ReduxProps) {
|
||||
<Typography variant="subtitle2" color="textPrimary" gutterBottom>
|
||||
Error rate
|
||||
</Typography>
|
||||
<Typography color="textSecondary">0.3 %</Typography>
|
||||
<Typography color="textSecondary">
|
||||
{queue ? percentage(queue.failed, queue.processed) : "-"}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -79,3 +79,8 @@ export function uuidPrefix(uuid: string): string {
|
||||
}
|
||||
return uuid.substr(0, idx);
|
||||
}
|
||||
|
||||
export function percentage(numerator: number, denominator: number): string {
|
||||
const perc = ((numerator / denominator) * 100).toFixed(2);
|
||||
return `${perc} %`;
|
||||
}
|
||||
|
@ -1,19 +1,34 @@
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { connect, ConnectedProps } from "react-redux";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Container from "@material-ui/core/Container";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import TasksTable from "../components/TasksTable";
|
||||
import QueueInfoBanner from "../components/QueueInfoBanner";
|
||||
import QueueBreadCrumb from "../components/QueueBreadcrumb";
|
||||
import { useParams, useLocation } from "react-router-dom";
|
||||
import { listQueuesAsync } from "../actions/queuesActions";
|
||||
import { AppState } from "../store";
|
||||
|
||||
function mapStateToProps(state: AppState) {
|
||||
return {
|
||||
queues: state.queues.data.map((q) => q.name),
|
||||
};
|
||||
}
|
||||
|
||||
const connector = connect(mapStateToProps, { listQueuesAsync });
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
container: {
|
||||
paddingTop: theme.spacing(2),
|
||||
},
|
||||
bannerContainer: {
|
||||
breadcrumbs: {
|
||||
marginBottom: theme.spacing(2),
|
||||
},
|
||||
taskTableContainer: {
|
||||
banner: {
|
||||
marginBottom: theme.spacing(2),
|
||||
},
|
||||
tasksTable: {
|
||||
marginBottom: theme.spacing(4),
|
||||
},
|
||||
}));
|
||||
@ -29,7 +44,7 @@ interface RouteParams {
|
||||
const validStatus = ["active", "pending", "scheduled", "retry", "archived"];
|
||||
const defaultStatus = "active";
|
||||
|
||||
function TasksView() {
|
||||
function TasksView(props: ConnectedProps<typeof connector>) {
|
||||
const classes = useStyles();
|
||||
const { qname } = useParams<RouteParams>();
|
||||
const query = useQuery();
|
||||
@ -37,14 +52,22 @@ function TasksView() {
|
||||
if (!selected || !validStatus.includes(selected)) {
|
||||
selected = defaultStatus;
|
||||
}
|
||||
const { listQueuesAsync } = props;
|
||||
|
||||
useEffect(() => {
|
||||
listQueuesAsync();
|
||||
}, [listQueuesAsync]);
|
||||
|
||||
return (
|
||||
<Container maxWidth="lg">
|
||||
<Grid container spacing={0} className={classes.container}>
|
||||
<Grid item xs={12} className={classes.bannerContainer}>
|
||||
<Grid xs={12} className={classes.breadcrumbs}>
|
||||
<QueueBreadCrumb queues={props.queues} selectedQueue={qname} />
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.banner}>
|
||||
<QueueInfoBanner qname={qname} />
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.taskTableContainer}>
|
||||
<Grid item xs={12} className={classes.tasksTable}>
|
||||
<TasksTable queue={qname} selected={selected} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
@ -52,4 +75,4 @@ function TasksView() {
|
||||
);
|
||||
}
|
||||
|
||||
export default TasksView;
|
||||
export default connector(TasksView);
|
||||
|
Loading…
Reference in New Issue
Block a user