mirror of
https://github.com/hibiken/asynqmon.git
synced 2025-01-19 03:05:53 +08:00
Change layout of TasksTable
This commit is contained in:
parent
e69d343d89
commit
b2c8de61bb
101
ui/src/components/QueueInfoBanner.tsx
Normal file
101
ui/src/components/QueueInfoBanner.tsx
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { connect, ConnectedProps } from "react-redux";
|
||||||
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
import { AppState } from "../store";
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
banner: {
|
||||||
|
paddingTop: theme.spacing(2),
|
||||||
|
paddingBottom: theme.spacing(2),
|
||||||
|
display: "flex",
|
||||||
|
},
|
||||||
|
bannerItem: {
|
||||||
|
flexGrow: 1,
|
||||||
|
borderLeft: `1px solid ${theme.palette.divider}`,
|
||||||
|
paddingLeft: theme.spacing(2),
|
||||||
|
paddingRight: theme.spacing(2),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
qname: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps(state: AppState, ownProps: Props) {
|
||||||
|
const queueInfo = state.queues.data.find((q) => q.name === ownProps.qname);
|
||||||
|
return {
|
||||||
|
queue: queueInfo?.currentStats,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const connector = connect(mapStateToProps);
|
||||||
|
|
||||||
|
type ReduxProps = ConnectedProps<typeof connector>;
|
||||||
|
|
||||||
|
function QueueInfoBanner(props: Props & ReduxProps) {
|
||||||
|
const classes = useStyles();
|
||||||
|
const { queue, qname } = props;
|
||||||
|
return (
|
||||||
|
<div className={classes.banner}>
|
||||||
|
<div className={classes.bannerItem}>
|
||||||
|
<Typography variant="subtitle2" color="textPrimary" gutterBottom>
|
||||||
|
Queue name
|
||||||
|
</Typography>
|
||||||
|
<Typography color="textSecondary">{qname}</Typography>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classes.bannerItem}>
|
||||||
|
<Typography variant="subtitle2" color="textPrimary" gutterBottom>
|
||||||
|
Queue state
|
||||||
|
</Typography>
|
||||||
|
<Typography color="textSecondary">
|
||||||
|
{queue ? (queue.paused ? "paused" : "run") : "-"}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classes.bannerItem}>
|
||||||
|
<Typography variant="subtitle2" color="textPrimary" gutterBottom>
|
||||||
|
Queue size
|
||||||
|
</Typography>
|
||||||
|
<Typography color="textSecondary">
|
||||||
|
{queue ? queue.size : "-"}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classes.bannerItem}>
|
||||||
|
<Typography variant="subtitle2" color="textPrimary" gutterBottom>
|
||||||
|
Memory usage
|
||||||
|
</Typography>
|
||||||
|
<Typography color="textSecondary">1.2MB</Typography>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classes.bannerItem}>
|
||||||
|
<Typography variant="subtitle2" color="textPrimary" gutterBottom>
|
||||||
|
Processed
|
||||||
|
</Typography>
|
||||||
|
<Typography color="textSecondary">
|
||||||
|
{queue ? queue.processed : "-"}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classes.bannerItem}>
|
||||||
|
<Typography variant="subtitle2" color="textPrimary" gutterBottom>
|
||||||
|
Failed
|
||||||
|
</Typography>
|
||||||
|
<Typography color="textSecondary">
|
||||||
|
{queue ? queue.failed : "-"}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classes.bannerItem}>
|
||||||
|
<Typography variant="subtitle2" color="textPrimary" gutterBottom>
|
||||||
|
Error rate
|
||||||
|
</Typography>
|
||||||
|
<Typography color="textSecondary">0.3 %</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connector(QueueInfoBanner);
|
@ -45,53 +45,6 @@ function a11yProps(value: string) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const usePanelHeadingStyles = makeStyles((theme) => ({
|
|
||||||
paper: {
|
|
||||||
padding: theme.spacing(2),
|
|
||||||
marginBottom: theme.spacing(2),
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
function PanelHeading(props: {
|
|
||||||
queue: string;
|
|
||||||
processed: number;
|
|
||||||
failed: number;
|
|
||||||
paused: boolean;
|
|
||||||
}) {
|
|
||||||
const classes = usePanelHeadingStyles();
|
|
||||||
return (
|
|
||||||
<Paper variant="outlined" className={classes.paper}>
|
|
||||||
<div>
|
|
||||||
<Typography variant="overline" display="block">
|
|
||||||
Queue Name
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="h5">{props.queue}</Typography>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Typography variant="overline" display="block">
|
|
||||||
Processed Today (UTC)
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="h5">{props.processed}</Typography>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Typography variant="overline" display="block">
|
|
||||||
Failed Today (UTC)
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="h5">{props.failed}</Typography>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Typography variant="overline" display="block">
|
|
||||||
Paused
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="h5">{props.paused ? "YES" : "No"}</Typography>
|
|
||||||
</div>
|
|
||||||
</Paper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapStatetoProps(state: AppState, ownProps: Props) {
|
function mapStatetoProps(state: AppState, ownProps: Props) {
|
||||||
// TODO: Add loading state for each queue.
|
// TODO: Add loading state for each queue.
|
||||||
const queueInfo = state.queues.data.find(
|
const queueInfo = state.queues.data.find(
|
||||||
@ -126,52 +79,46 @@ interface Props {
|
|||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
container: {
|
container: {
|
||||||
display: "flex",
|
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
background: theme.palette.background.paper,
|
background: theme.palette.background.paper,
|
||||||
},
|
},
|
||||||
heading: {
|
heading: {
|
||||||
fontSize: "1.7rem",
|
paddingTop: theme.spacing(1),
|
||||||
fontWeight: 500,
|
paddingBottom: theme.spacing(1),
|
||||||
paddingLeft: "28px", // TODO: maybe use theme.spacing(3),
|
paddingLeft: theme.spacing(2),
|
||||||
paddingTop: "28px",
|
paddingRight: theme.spacing(2),
|
||||||
paddingBottom: "28px",
|
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||||
color: theme.palette.text.primary,
|
|
||||||
},
|
},
|
||||||
tabsContainer: {
|
tabsContainer: {
|
||||||
background:
|
// background:
|
||||||
theme.palette.type === "dark"
|
// theme.palette.type === "dark"
|
||||||
? "#303030"
|
// ? "#303030"
|
||||||
: theme.palette.background.default,
|
// : theme.palette.background.default,
|
||||||
},
|
},
|
||||||
tabsRoot: {
|
tabsRoot: {
|
||||||
paddingLeft: theme.spacing(2),
|
// background:
|
||||||
background:
|
// theme.palette.type === "dark"
|
||||||
theme.palette.type === "dark"
|
// ? "#303030"
|
||||||
? "#303030"
|
// : theme.palette.background.default,
|
||||||
: theme.palette.background.default,
|
|
||||||
},
|
},
|
||||||
tabsIndicator: {
|
tabsIndicator: {
|
||||||
right: "auto",
|
right: "auto",
|
||||||
left: "0",
|
left: "0",
|
||||||
},
|
},
|
||||||
tabroot: {
|
tabroot: {
|
||||||
width: "204px",
|
flexGrow: 1,
|
||||||
textAlign: "left",
|
textAlign: "center",
|
||||||
padding: theme.spacing(2),
|
padding: theme.spacing(2),
|
||||||
},
|
},
|
||||||
tabwrapper: {
|
tabwrapper: {
|
||||||
alignItems: "flex-start",
|
alignItems: "center",
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
},
|
},
|
||||||
tabSelected: {
|
tabSelected: {
|
||||||
background: theme.palette.background.paper,
|
background: theme.palette.background.paper,
|
||||||
boxShadow: theme.shadows[1],
|
|
||||||
},
|
|
||||||
panelContainer: {
|
|
||||||
padding: "24px",
|
|
||||||
},
|
},
|
||||||
|
panelContainer: {},
|
||||||
taskCount: {
|
taskCount: {
|
||||||
fontSize: "2rem",
|
fontSize: "2rem",
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
@ -185,24 +132,22 @@ function TasksTable(props: Props & ReduxProps) {
|
|||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.container}>
|
<Paper variant="outlined" className={classes.container}>
|
||||||
|
<Typography color="textPrimary" className={classes.heading}>
|
||||||
|
Tasks list
|
||||||
|
</Typography>
|
||||||
<div className={classes.tabsContainer}>
|
<div className={classes.tabsContainer}>
|
||||||
<div className={classes.heading}>Tasks</div>
|
|
||||||
<Tabs
|
<Tabs
|
||||||
value={props.selected}
|
value={props.selected}
|
||||||
onChange={(_, value: string) =>
|
onChange={(_, value: string) =>
|
||||||
history.push(queueDetailsPath(props.queue, value))
|
history.push(queueDetailsPath(props.queue, value))
|
||||||
}
|
}
|
||||||
aria-label="tasks table"
|
aria-label="tasks table"
|
||||||
orientation="vertical"
|
|
||||||
classes={{ root: classes.tabsRoot, indicator: classes.tabsIndicator }}
|
classes={{ root: classes.tabsRoot, indicator: classes.tabsIndicator }}
|
||||||
>
|
>
|
||||||
<Tab
|
<Tab
|
||||||
value="active"
|
value="active"
|
||||||
label="Active"
|
label={`Active (${currentStats.active})`}
|
||||||
icon={
|
|
||||||
<div className={classes.taskCount}>{currentStats.active}</div>
|
|
||||||
}
|
|
||||||
classes={{
|
classes={{
|
||||||
root: classes.tabroot,
|
root: classes.tabroot,
|
||||||
wrapper: classes.tabwrapper,
|
wrapper: classes.tabwrapper,
|
||||||
@ -212,10 +157,7 @@ function TasksTable(props: Props & ReduxProps) {
|
|||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
value="pending"
|
value="pending"
|
||||||
label="Pending"
|
label={`Pending (${currentStats.pending})`}
|
||||||
icon={
|
|
||||||
<div className={classes.taskCount}>{currentStats.pending}</div>
|
|
||||||
}
|
|
||||||
classes={{
|
classes={{
|
||||||
root: classes.tabroot,
|
root: classes.tabroot,
|
||||||
wrapper: classes.tabwrapper,
|
wrapper: classes.tabwrapper,
|
||||||
@ -225,10 +167,7 @@ function TasksTable(props: Props & ReduxProps) {
|
|||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
value="scheduled"
|
value="scheduled"
|
||||||
label="Scheduled"
|
label={`Scheduled (${currentStats.scheduled})`}
|
||||||
icon={
|
|
||||||
<div className={classes.taskCount}>{currentStats.scheduled}</div>
|
|
||||||
}
|
|
||||||
classes={{
|
classes={{
|
||||||
root: classes.tabroot,
|
root: classes.tabroot,
|
||||||
wrapper: classes.tabwrapper,
|
wrapper: classes.tabwrapper,
|
||||||
@ -238,8 +177,7 @@ function TasksTable(props: Props & ReduxProps) {
|
|||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
value="retry"
|
value="retry"
|
||||||
label="Retry"
|
label={`Retry (${currentStats.retry})`}
|
||||||
icon={<div className={classes.taskCount}>{currentStats.retry}</div>}
|
|
||||||
classes={{
|
classes={{
|
||||||
root: classes.tabroot,
|
root: classes.tabroot,
|
||||||
wrapper: classes.tabwrapper,
|
wrapper: classes.tabwrapper,
|
||||||
@ -249,10 +187,7 @@ function TasksTable(props: Props & ReduxProps) {
|
|||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
value="archived"
|
value="archived"
|
||||||
label="Archived"
|
label={`Archived (${currentStats.archived})`}
|
||||||
icon={
|
|
||||||
<div className={classes.taskCount}>{currentStats.archived}</div>
|
|
||||||
}
|
|
||||||
classes={{
|
classes={{
|
||||||
root: classes.tabroot,
|
root: classes.tabroot,
|
||||||
wrapper: classes.tabwrapper,
|
wrapper: classes.tabwrapper,
|
||||||
@ -264,23 +199,11 @@ function TasksTable(props: Props & ReduxProps) {
|
|||||||
</div>
|
</div>
|
||||||
<TabPanel value="active" selected={props.selected}>
|
<TabPanel value="active" selected={props.selected}>
|
||||||
<div className={classes.panelContainer}>
|
<div className={classes.panelContainer}>
|
||||||
<PanelHeading
|
|
||||||
queue={props.queue}
|
|
||||||
processed={currentStats.processed}
|
|
||||||
failed={currentStats.failed}
|
|
||||||
paused={currentStats.paused}
|
|
||||||
/>
|
|
||||||
<ActiveTasksTable queue={props.queue} />
|
<ActiveTasksTable queue={props.queue} />
|
||||||
</div>
|
</div>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel value="pending" selected={props.selected}>
|
<TabPanel value="pending" selected={props.selected}>
|
||||||
<div className={classes.panelContainer}>
|
<div className={classes.panelContainer}>
|
||||||
<PanelHeading
|
|
||||||
queue={props.queue}
|
|
||||||
processed={currentStats.processed}
|
|
||||||
failed={currentStats.failed}
|
|
||||||
paused={currentStats.paused}
|
|
||||||
/>
|
|
||||||
<PendingTasksTable
|
<PendingTasksTable
|
||||||
queue={props.queue}
|
queue={props.queue}
|
||||||
totalTaskCount={currentStats.pending}
|
totalTaskCount={currentStats.pending}
|
||||||
@ -289,12 +212,6 @@ function TasksTable(props: Props & ReduxProps) {
|
|||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel value="scheduled" selected={props.selected}>
|
<TabPanel value="scheduled" selected={props.selected}>
|
||||||
<div className={classes.panelContainer}>
|
<div className={classes.panelContainer}>
|
||||||
<PanelHeading
|
|
||||||
queue={props.queue}
|
|
||||||
processed={currentStats.processed}
|
|
||||||
failed={currentStats.failed}
|
|
||||||
paused={currentStats.paused}
|
|
||||||
/>
|
|
||||||
<ScheduledTasksTable
|
<ScheduledTasksTable
|
||||||
queue={props.queue}
|
queue={props.queue}
|
||||||
totalTaskCount={currentStats.scheduled}
|
totalTaskCount={currentStats.scheduled}
|
||||||
@ -303,12 +220,6 @@ function TasksTable(props: Props & ReduxProps) {
|
|||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel value="retry" selected={props.selected}>
|
<TabPanel value="retry" selected={props.selected}>
|
||||||
<div className={classes.panelContainer}>
|
<div className={classes.panelContainer}>
|
||||||
<PanelHeading
|
|
||||||
queue={props.queue}
|
|
||||||
processed={currentStats.processed}
|
|
||||||
failed={currentStats.failed}
|
|
||||||
paused={currentStats.paused}
|
|
||||||
/>
|
|
||||||
<RetryTasksTable
|
<RetryTasksTable
|
||||||
queue={props.queue}
|
queue={props.queue}
|
||||||
totalTaskCount={currentStats.retry}
|
totalTaskCount={currentStats.retry}
|
||||||
@ -317,19 +228,13 @@ function TasksTable(props: Props & ReduxProps) {
|
|||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel value="archived" selected={props.selected}>
|
<TabPanel value="archived" selected={props.selected}>
|
||||||
<div className={classes.panelContainer}>
|
<div className={classes.panelContainer}>
|
||||||
<PanelHeading
|
|
||||||
queue={props.queue}
|
|
||||||
processed={currentStats.processed}
|
|
||||||
failed={currentStats.failed}
|
|
||||||
paused={currentStats.paused}
|
|
||||||
/>
|
|
||||||
<ArchivedTasksTable
|
<ArchivedTasksTable
|
||||||
queue={props.queue}
|
queue={props.queue}
|
||||||
totalTaskCount={currentStats.archived}
|
totalTaskCount={currentStats.archived}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</div>
|
</Paper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,21 +3,18 @@ import { makeStyles } from "@material-ui/core/styles";
|
|||||||
import Container from "@material-ui/core/Container";
|
import Container from "@material-ui/core/Container";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@material-ui/core/Grid";
|
||||||
import TasksTable from "../components/TasksTable";
|
import TasksTable from "../components/TasksTable";
|
||||||
|
import QueueInfoBanner from "../components/QueueInfoBanner";
|
||||||
import { useParams, useLocation } from "react-router-dom";
|
import { useParams, useLocation } from "react-router-dom";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
container: {
|
container: {
|
||||||
paddingLeft: 0,
|
paddingTop: theme.spacing(2),
|
||||||
marginLeft: 0,
|
|
||||||
height: "100%",
|
|
||||||
},
|
},
|
||||||
gridContainer: {
|
bannerContainer: {
|
||||||
height: "100%",
|
marginBottom: theme.spacing(2),
|
||||||
paddingBottom: 0,
|
|
||||||
},
|
},
|
||||||
gridItem: {
|
taskTableContainer: {
|
||||||
height: "100%",
|
marginBottom: theme.spacing(4),
|
||||||
paddingBottom: 0,
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -42,9 +39,12 @@ function TasksView() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="lg" className={classes.container}>
|
<Container maxWidth="lg">
|
||||||
<Grid container spacing={0} className={classes.gridContainer}>
|
<Grid container spacing={0} className={classes.container}>
|
||||||
<Grid item xs={12} className={classes.gridItem}>
|
<Grid item xs={12} className={classes.bannerContainer}>
|
||||||
|
<QueueInfoBanner qname={qname} />
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} className={classes.taskTableContainer}>
|
||||||
<TasksTable queue={qname} selected={selected} />
|
<TasksTable queue={qname} selected={selected} />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
Loading…
Reference in New Issue
Block a user