mirror of
https://github.com/hibiken/asynqmon.git
synced 2025-10-26 16:26:12 +08:00
(ui): Add top level shift buttons
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect, ConnectedProps } from "react-redux";
|
import { connect, ConnectedProps } from "react-redux";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Button from "@material-ui/core/Button";
|
import Button, { ButtonProps } from "@material-ui/core/Button";
|
||||||
|
import ButtonGroup from "@material-ui/core/ButtonGroup";
|
||||||
import Popover from "@material-ui/core/Popover";
|
import Popover from "@material-ui/core/Popover";
|
||||||
import Radio from "@material-ui/core/Radio";
|
import Radio from "@material-ui/core/Radio";
|
||||||
import RadioGroup from "@material-ui/core/RadioGroup";
|
import RadioGroup from "@material-ui/core/RadioGroup";
|
||||||
@@ -53,6 +54,12 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
endTimeCaption: {
|
endTimeCaption: {
|
||||||
marginRight: theme.spacing(1),
|
marginRight: theme.spacing(1),
|
||||||
},
|
},
|
||||||
|
shiftButtons: {
|
||||||
|
marginLeft: theme.spacing(1),
|
||||||
|
},
|
||||||
|
buttonGroupRoot: {
|
||||||
|
height: 30,
|
||||||
|
},
|
||||||
endTimeShiftControls: {
|
endTimeShiftControls: {
|
||||||
padding: theme.spacing(1),
|
padding: theme.spacing(1),
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@@ -331,269 +338,311 @@ function MetricsFetchControls(props: Props) {
|
|||||||
<Typography variant="caption" className={classes.endTimeCaption}>
|
<Typography variant="caption" className={classes.endTimeCaption}>
|
||||||
{formatTime(props.endTimeSec)}
|
{formatTime(props.endTimeSec)}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Button
|
<div>
|
||||||
aria-describedby={id}
|
<Button
|
||||||
variant="outlined"
|
aria-describedby={id}
|
||||||
color="primary"
|
variant="outlined"
|
||||||
onClick={handleButtonClick}
|
color="primary"
|
||||||
size="small"
|
onClick={handleButtonClick}
|
||||||
classes={{
|
size="small"
|
||||||
label: classes.buttonLabel,
|
classes={{
|
||||||
}}
|
label: classes.buttonLabel,
|
||||||
>
|
}}
|
||||||
{state.endTimeOption === "real_time" ? "Realtime" : "Historical"}:{" "}
|
>
|
||||||
{state.durationOption === "custom"
|
{state.endTimeOption === "real_time" ? "Realtime" : "Historical"}:{" "}
|
||||||
? state.customDuration
|
{state.durationOption === "custom"
|
||||||
: state.durationOption}
|
? state.customDuration
|
||||||
</Button>
|
: state.durationOption}
|
||||||
<Popover
|
</Button>
|
||||||
id={id}
|
<Popover
|
||||||
open={open}
|
id={id}
|
||||||
anchorEl={anchorEl}
|
open={open}
|
||||||
onClose={handleClose}
|
anchorEl={anchorEl}
|
||||||
anchorOrigin={{
|
onClose={handleClose}
|
||||||
vertical: "bottom",
|
anchorOrigin={{
|
||||||
horizontal: "center",
|
vertical: "bottom",
|
||||||
}}
|
horizontal: "center",
|
||||||
transformOrigin={{
|
}}
|
||||||
vertical: "top",
|
transformOrigin={{
|
||||||
horizontal: "center",
|
vertical: "top",
|
||||||
}}
|
horizontal: "center",
|
||||||
>
|
}}
|
||||||
<div className={classes.endTimeShiftControls}>
|
>
|
||||||
<div className={classes.leftShiftButtons}>
|
<div className={classes.endTimeShiftControls}>
|
||||||
<ShiftButton
|
<div className={classes.leftShiftButtons}>
|
||||||
direction="left"
|
<ShiftButton
|
||||||
text="2h"
|
direction="left"
|
||||||
onClick={shiftBy(-2 * hour)}
|
text="2h"
|
||||||
/>
|
onClick={shiftBy(-2 * hour)}
|
||||||
<ShiftButton
|
dense={true}
|
||||||
direction="left"
|
/>
|
||||||
text="1h"
|
<ShiftButton
|
||||||
onClick={shiftBy(-1 * hour)}
|
direction="left"
|
||||||
/>
|
text="1h"
|
||||||
<ShiftButton
|
onClick={shiftBy(-1 * hour)}
|
||||||
direction="left"
|
dense={true}
|
||||||
text="30m"
|
/>
|
||||||
onClick={shiftBy(-30 * minute)}
|
<ShiftButton
|
||||||
/>
|
direction="left"
|
||||||
<ShiftButton
|
text="30m"
|
||||||
direction="left"
|
onClick={shiftBy(-30 * minute)}
|
||||||
text="15m"
|
dense={true}
|
||||||
onClick={shiftBy(-15 * minute)}
|
/>
|
||||||
/>
|
<ShiftButton
|
||||||
<ShiftButton
|
direction="left"
|
||||||
direction="left"
|
text="15m"
|
||||||
text="5m"
|
onClick={shiftBy(-15 * minute)}
|
||||||
onClick={shiftBy(-5 * minute)}
|
dense={true}
|
||||||
/>
|
/>
|
||||||
|
<ShiftButton
|
||||||
|
direction="left"
|
||||||
|
text="5m"
|
||||||
|
onClick={shiftBy(-5 * minute)}
|
||||||
|
dense={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={classes.rightShiftButtons}>
|
||||||
|
<ShiftButton
|
||||||
|
direction="right"
|
||||||
|
text="5m"
|
||||||
|
onClick={shiftBy(5 * minute)}
|
||||||
|
dense={true}
|
||||||
|
/>
|
||||||
|
<ShiftButton
|
||||||
|
direction="right"
|
||||||
|
text="15m"
|
||||||
|
onClick={shiftBy(15 * minute)}
|
||||||
|
dense={true}
|
||||||
|
/>
|
||||||
|
<ShiftButton
|
||||||
|
direction="right"
|
||||||
|
text="30m"
|
||||||
|
onClick={shiftBy(30 * minute)}
|
||||||
|
dense={true}
|
||||||
|
/>
|
||||||
|
<ShiftButton
|
||||||
|
direction="right"
|
||||||
|
text="1h"
|
||||||
|
onClick={shiftBy(1 * hour)}
|
||||||
|
dense={true}
|
||||||
|
/>
|
||||||
|
<ShiftButton
|
||||||
|
direction="right"
|
||||||
|
text="2h"
|
||||||
|
onClick={shiftBy(2 * hour)}
|
||||||
|
dense={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.rightShiftButtons}>
|
<div className={classes.controlSelectorBox}>
|
||||||
<ShiftButton
|
<div className={classes.controlEndTimeSelector}>
|
||||||
direction="right"
|
<FormControl
|
||||||
text="5m"
|
component="fieldset"
|
||||||
onClick={shiftBy(5 * minute)}
|
margin="dense"
|
||||||
/>
|
classes={{ root: classes.formControlRoot }}
|
||||||
<ShiftButton
|
|
||||||
direction="right"
|
|
||||||
text="15m"
|
|
||||||
onClick={shiftBy(15 * minute)}
|
|
||||||
/>
|
|
||||||
<ShiftButton
|
|
||||||
direction="right"
|
|
||||||
text="30m"
|
|
||||||
onClick={shiftBy(30 * minute)}
|
|
||||||
/>
|
|
||||||
<ShiftButton
|
|
||||||
direction="right"
|
|
||||||
text="1h"
|
|
||||||
onClick={shiftBy(1 * hour)}
|
|
||||||
/>
|
|
||||||
<ShiftButton
|
|
||||||
direction="right"
|
|
||||||
text="2h"
|
|
||||||
onClick={shiftBy(2 * hour)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes.controlSelectorBox}>
|
|
||||||
<div className={classes.controlEndTimeSelector}>
|
|
||||||
<FormControl
|
|
||||||
component="fieldset"
|
|
||||||
margin="dense"
|
|
||||||
classes={{ root: classes.formControlRoot }}
|
|
||||||
>
|
|
||||||
<FormLabel component="legend">End Time</FormLabel>
|
|
||||||
<RadioGroup
|
|
||||||
aria-label="end_time"
|
|
||||||
name="end_time"
|
|
||||||
value={state.endTimeOption}
|
|
||||||
onChange={handleEndTimeOptionChange}
|
|
||||||
>
|
>
|
||||||
<FormControlLabel
|
<FormLabel component="legend">End Time</FormLabel>
|
||||||
classes={{
|
<RadioGroup
|
||||||
label: classes.radioButtonLabel,
|
aria-label="end_time"
|
||||||
}}
|
name="end_time"
|
||||||
value="real_time"
|
value={state.endTimeOption}
|
||||||
control={
|
onChange={handleEndTimeOptionChange}
|
||||||
<Radio
|
>
|
||||||
size="small"
|
<FormControlLabel
|
||||||
classes={{ root: classes.radioButtonRoot }}
|
classes={{
|
||||||
/>
|
label: classes.radioButtonLabel,
|
||||||
}
|
}}
|
||||||
label="Real Time"
|
value="real_time"
|
||||||
/>
|
control={
|
||||||
<FormControlLabel
|
<Radio
|
||||||
classes={{
|
size="small"
|
||||||
label: classes.radioButtonLabel,
|
classes={{ root: classes.radioButtonRoot }}
|
||||||
}}
|
/>
|
||||||
value="freeze_at_now"
|
}
|
||||||
control={
|
label="Real Time"
|
||||||
<Radio
|
/>
|
||||||
size="small"
|
<FormControlLabel
|
||||||
classes={{ root: classes.radioButtonRoot }}
|
classes={{
|
||||||
/>
|
label: classes.radioButtonLabel,
|
||||||
}
|
}}
|
||||||
label="Freeze at now"
|
value="freeze_at_now"
|
||||||
/>
|
control={
|
||||||
<FormControlLabel
|
<Radio
|
||||||
classes={{
|
size="small"
|
||||||
label: classes.radioButtonLabel,
|
classes={{ root: classes.radioButtonRoot }}
|
||||||
}}
|
/>
|
||||||
value="custom"
|
}
|
||||||
control={
|
label="Freeze at now"
|
||||||
<Radio
|
/>
|
||||||
size="small"
|
<FormControlLabel
|
||||||
classes={{ root: classes.radioButtonRoot }}
|
classes={{
|
||||||
/>
|
label: classes.radioButtonLabel,
|
||||||
}
|
}}
|
||||||
label="Custom End Time"
|
value="custom"
|
||||||
/>
|
control={
|
||||||
</RadioGroup>
|
<Radio
|
||||||
<div>
|
size="small"
|
||||||
<TextField
|
classes={{ root: classes.radioButtonRoot }}
|
||||||
id="custom-endtime"
|
/>
|
||||||
label="yyyy-mm-dd hh:mm:ssz"
|
}
|
||||||
variant="outlined"
|
label="Custom End Time"
|
||||||
size="small"
|
/>
|
||||||
onChange={handleCustomEndTimeChange}
|
</RadioGroup>
|
||||||
value={state.customEndTime}
|
<div>
|
||||||
onKeyDown={handleCustomEndTimeKeyDown}
|
<TextField
|
||||||
error={state.customEndTimeError !== ""}
|
id="custom-endtime"
|
||||||
helperText={state.customEndTimeError}
|
label="yyyy-mm-dd hh:mm:ssz"
|
||||||
/>
|
variant="outlined"
|
||||||
</div>
|
size="small"
|
||||||
</FormControl>
|
onChange={handleCustomEndTimeChange}
|
||||||
</div>
|
value={state.customEndTime}
|
||||||
<div className={classes.controlDurationSelector}>
|
onKeyDown={handleCustomEndTimeKeyDown}
|
||||||
<FormControl
|
error={state.customEndTimeError !== ""}
|
||||||
component="fieldset"
|
helperText={state.customEndTimeError}
|
||||||
margin="dense"
|
/>
|
||||||
classes={{ root: classes.formControlRoot }}
|
</div>
|
||||||
>
|
</FormControl>
|
||||||
<FormLabel component="legend">Duration</FormLabel>
|
</div>
|
||||||
<RadioGroup
|
<div className={classes.controlDurationSelector}>
|
||||||
aria-label="duration"
|
<FormControl
|
||||||
name="duration"
|
component="fieldset"
|
||||||
value={state.durationOption}
|
margin="dense"
|
||||||
onChange={handleDurationOptionChange}
|
classes={{ root: classes.formControlRoot }}
|
||||||
>
|
>
|
||||||
<FormControlLabel
|
<FormLabel component="legend">Duration</FormLabel>
|
||||||
classes={{
|
<RadioGroup
|
||||||
label: classes.radioButtonLabel,
|
aria-label="duration"
|
||||||
}}
|
name="duration"
|
||||||
value="1h"
|
value={state.durationOption}
|
||||||
control={
|
onChange={handleDurationOptionChange}
|
||||||
<Radio
|
>
|
||||||
size="small"
|
<FormControlLabel
|
||||||
classes={{ root: classes.radioButtonRoot }}
|
classes={{
|
||||||
/>
|
label: classes.radioButtonLabel,
|
||||||
}
|
}}
|
||||||
label="1h"
|
value="1h"
|
||||||
/>
|
control={
|
||||||
<FormControlLabel
|
<Radio
|
||||||
classes={{
|
size="small"
|
||||||
label: classes.radioButtonLabel,
|
classes={{ root: classes.radioButtonRoot }}
|
||||||
}}
|
/>
|
||||||
value="6h"
|
}
|
||||||
control={
|
label="1h"
|
||||||
<Radio
|
/>
|
||||||
size="small"
|
<FormControlLabel
|
||||||
classes={{ root: classes.radioButtonRoot }}
|
classes={{
|
||||||
/>
|
label: classes.radioButtonLabel,
|
||||||
}
|
}}
|
||||||
label="6h"
|
value="6h"
|
||||||
/>
|
control={
|
||||||
<FormControlLabel
|
<Radio
|
||||||
classes={{
|
size="small"
|
||||||
label: classes.radioButtonLabel,
|
classes={{ root: classes.radioButtonRoot }}
|
||||||
}}
|
/>
|
||||||
value="1d"
|
}
|
||||||
control={
|
label="6h"
|
||||||
<Radio
|
/>
|
||||||
size="small"
|
<FormControlLabel
|
||||||
classes={{ root: classes.radioButtonRoot }}
|
classes={{
|
||||||
/>
|
label: classes.radioButtonLabel,
|
||||||
}
|
}}
|
||||||
label="1 day"
|
value="1d"
|
||||||
/>
|
control={
|
||||||
<FormControlLabel
|
<Radio
|
||||||
classes={{
|
size="small"
|
||||||
label: classes.radioButtonLabel,
|
classes={{ root: classes.radioButtonRoot }}
|
||||||
}}
|
/>
|
||||||
value="8d"
|
}
|
||||||
control={
|
label="1 day"
|
||||||
<Radio
|
/>
|
||||||
size="small"
|
<FormControlLabel
|
||||||
classes={{ root: classes.radioButtonRoot }}
|
classes={{
|
||||||
/>
|
label: classes.radioButtonLabel,
|
||||||
}
|
}}
|
||||||
label="8 days"
|
value="8d"
|
||||||
/>
|
control={
|
||||||
<FormControlLabel
|
<Radio
|
||||||
classes={{
|
size="small"
|
||||||
label: classes.radioButtonLabel,
|
classes={{ root: classes.radioButtonRoot }}
|
||||||
}}
|
/>
|
||||||
value="30d"
|
}
|
||||||
control={
|
label="8 days"
|
||||||
<Radio
|
/>
|
||||||
size="small"
|
<FormControlLabel
|
||||||
classes={{ root: classes.radioButtonRoot }}
|
classes={{
|
||||||
/>
|
label: classes.radioButtonLabel,
|
||||||
}
|
}}
|
||||||
label="30 days"
|
value="30d"
|
||||||
/>
|
control={
|
||||||
<FormControlLabel
|
<Radio
|
||||||
classes={{
|
size="small"
|
||||||
label: classes.radioButtonLabel,
|
classes={{ root: classes.radioButtonRoot }}
|
||||||
}}
|
/>
|
||||||
value="custom"
|
}
|
||||||
control={
|
label="30 days"
|
||||||
<Radio
|
/>
|
||||||
size="small"
|
<FormControlLabel
|
||||||
classes={{ root: classes.radioButtonRoot }}
|
classes={{
|
||||||
/>
|
label: classes.radioButtonLabel,
|
||||||
}
|
}}
|
||||||
label="Custom Duration"
|
value="custom"
|
||||||
/>
|
control={
|
||||||
</RadioGroup>
|
<Radio
|
||||||
<div>
|
size="small"
|
||||||
<TextField
|
classes={{ root: classes.radioButtonRoot }}
|
||||||
id="custom-duration"
|
/>
|
||||||
label="duration"
|
}
|
||||||
variant="outlined"
|
label="Custom Duration"
|
||||||
size="small"
|
/>
|
||||||
onChange={handleCustomDurationChange}
|
</RadioGroup>
|
||||||
value={state.customDuration}
|
<div>
|
||||||
onKeyDown={handleCustomDurationKeyDown}
|
<TextField
|
||||||
error={state.customDurationError !== ""}
|
id="custom-duration"
|
||||||
helperText={state.customDurationError}
|
label="duration"
|
||||||
/>
|
variant="outlined"
|
||||||
</div>
|
size="small"
|
||||||
</FormControl>
|
onChange={handleCustomDurationChange}
|
||||||
|
value={state.customDuration}
|
||||||
|
onKeyDown={handleCustomDurationKeyDown}
|
||||||
|
error={state.customDurationError !== ""}
|
||||||
|
helperText={state.customDurationError}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Popover>
|
||||||
</Popover>
|
</div>
|
||||||
|
<div className={classes.shiftButtons}>
|
||||||
|
<ButtonGroup
|
||||||
|
classes={{ root: classes.buttonGroupRoot }}
|
||||||
|
size="small"
|
||||||
|
aria-label="shift buttons"
|
||||||
|
>
|
||||||
|
<ShiftButton
|
||||||
|
direction="left"
|
||||||
|
text={
|
||||||
|
state.durationOption === "custom" ? "1h" : state.durationOption
|
||||||
|
}
|
||||||
|
onClick={
|
||||||
|
state.durationOption === "custom"
|
||||||
|
? shiftBy(-1 * hour)
|
||||||
|
: shiftBy(-props.durationSec)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ShiftButton
|
||||||
|
direction="right"
|
||||||
|
text={
|
||||||
|
state.durationOption === "custom" ? "1h" : state.durationOption
|
||||||
|
}
|
||||||
|
onClick={
|
||||||
|
state.durationOption === "custom"
|
||||||
|
? shiftBy(1 * hour)
|
||||||
|
: shiftBy(props.durationSec)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</ButtonGroup>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -605,10 +654,11 @@ function formatTime(unixtime: number): string {
|
|||||||
return dayjs.unix(unixtime).format("ddd, DD MMM YYYY HH:mm:ss ") + tz;
|
return dayjs.unix(unixtime).format("ddd, DD MMM YYYY HH:mm:ss ") + tz;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ShiftButtonProps {
|
interface ShiftButtonProps extends ButtonProps {
|
||||||
text: string;
|
text: string;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
direction: "left" | "right";
|
direction: "left" | "right";
|
||||||
|
dense?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useShiftButtonStyles = makeStyles((theme) => ({
|
const useShiftButtonStyles = makeStyles((theme) => ({
|
||||||
@@ -616,9 +666,9 @@ const useShiftButtonStyles = makeStyles((theme) => ({
|
|||||||
label: { fontSize: 12, textTransform: "none" },
|
label: { fontSize: 12, textTransform: "none" },
|
||||||
iconRoot: {
|
iconRoot: {
|
||||||
marginRight: (props: ShiftButtonProps) =>
|
marginRight: (props: ShiftButtonProps) =>
|
||||||
props.direction === "left" ? -8 : 0,
|
props.direction === "left" && props.dense ? -8 : 0,
|
||||||
marginLeft: (props: ShiftButtonProps) =>
|
marginLeft: (props: ShiftButtonProps) =>
|
||||||
props.direction === "right" ? -8 : 0,
|
props.direction === "right" && props.dense ? -8 : 0,
|
||||||
color: theme.palette.grey[700],
|
color: theme.palette.grey[700],
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
@@ -627,12 +677,12 @@ function ShiftButton(props: ShiftButtonProps) {
|
|||||||
const classes = useShiftButtonStyles(props);
|
const classes = useShiftButtonStyles(props);
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
|
{...props}
|
||||||
classes={{
|
classes={{
|
||||||
root: classes.root,
|
root: classes.root,
|
||||||
label: classes.label,
|
label: classes.label,
|
||||||
}}
|
}}
|
||||||
size="small"
|
size="small"
|
||||||
onClick={props.onClick}
|
|
||||||
>
|
>
|
||||||
{props.direction === "left" && (
|
{props.direction === "left" && (
|
||||||
<ArrowLeftIcon classes={{ root: classes.iconRoot }} />
|
<ArrowLeftIcon classes={{ root: classes.iconRoot }} />
|
||||||
@@ -645,4 +695,8 @@ function ShiftButton(props: ShiftButtonProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShiftButton.defaultProps = {
|
||||||
|
dense: false,
|
||||||
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps)(MetricsFetchControls);
|
export default connect(mapStateToProps)(MetricsFetchControls);
|
||||||
|
|||||||
Reference in New Issue
Block a user