mirror of
https://github.com/dstotijn/hetty.git
synced 2025-07-01 18:47:29 -04:00
Tidy up proxy logs, add copy action for headers
This commit is contained in:
@ -7,7 +7,10 @@ import {
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableRow,
|
||||
Snackbar,
|
||||
} from "@material-ui/core";
|
||||
import { Alert } from "@material-ui/lab";
|
||||
import React, { useState } from "react";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
const paddingX = 0;
|
||||
@ -19,23 +22,35 @@ const useStyles = makeStyles((theme: Theme) => {
|
||||
paddingBottom: paddingY,
|
||||
verticalAlign: "top",
|
||||
border: "none",
|
||||
whiteSpace: "nowrap" as any,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
"&:hover": {
|
||||
color: theme.palette.secondary.main,
|
||||
whiteSpace: "inherit" as any,
|
||||
overflow: "inherit",
|
||||
textOverflow: "inherit",
|
||||
cursor: "copy",
|
||||
},
|
||||
};
|
||||
return createStyles({
|
||||
root: {},
|
||||
table: {
|
||||
tableLayout: "fixed",
|
||||
width: "100%",
|
||||
},
|
||||
keyCell: {
|
||||
...tableCell,
|
||||
paddingRight: theme.spacing(1),
|
||||
width: "40%",
|
||||
fontWeight: "bold",
|
||||
fontSize: ".75rem",
|
||||
},
|
||||
valueCell: {
|
||||
...tableCell,
|
||||
width: "60%",
|
||||
border: "none",
|
||||
wordBreak: "break-all",
|
||||
whiteSpace: "pre-wrap",
|
||||
fontSize: ".75rem",
|
||||
},
|
||||
});
|
||||
});
|
||||
@ -46,23 +61,59 @@ interface Props {
|
||||
|
||||
function HttpHeadersTable({ headers }: Props): JSX.Element {
|
||||
const classes = useStyles();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const handleClick = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
const r = document.createRange();
|
||||
r.selectNode(e.currentTarget);
|
||||
window.getSelection().removeAllRanges();
|
||||
window.getSelection().addRange(r);
|
||||
document.execCommand("copy");
|
||||
window.getSelection().removeAllRanges();
|
||||
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const handleClose = (event?: React.SyntheticEvent, reason?: string) => {
|
||||
if (reason === "clickaway") {
|
||||
return;
|
||||
}
|
||||
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<TableContainer>
|
||||
<Table className={classes.table} size="small">
|
||||
<TableBody>
|
||||
{headers.map(({ key, value }, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell component="th" scope="row" className={classes.keyCell}>
|
||||
<code>{key}:</code>
|
||||
</TableCell>
|
||||
<TableCell className={classes.valueCell}>
|
||||
<code>{value}</code>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<div>
|
||||
<Snackbar open={open} autoHideDuration={3000} onClose={handleClose}>
|
||||
<Alert onClose={handleClose} severity="info">
|
||||
Copied to clipboard.
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
<TableContainer className={classes.root}>
|
||||
<Table className={classes.table} size="small">
|
||||
<TableBody>
|
||||
{headers.map(({ key, value }, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell
|
||||
component="th"
|
||||
scope="row"
|
||||
className={classes.keyCell}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<code>{key}:</code>
|
||||
</TableCell>
|
||||
<TableCell className={classes.valueCell} onClick={handleClick}>
|
||||
<code>{value}</code>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,19 +1,31 @@
|
||||
import { green, orange, red } from "@material-ui/core/colors";
|
||||
import { Theme, withTheme } from "@material-ui/core";
|
||||
import { orange, red } from "@material-ui/core/colors";
|
||||
import FiberManualRecordIcon from "@material-ui/icons/FiberManualRecord";
|
||||
|
||||
function HttpStatusIcon({ status }: { status: number }): JSX.Element {
|
||||
interface Props {
|
||||
status: number;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
function HttpStatusIcon({ status, theme }: Props): JSX.Element {
|
||||
const style = { marginTop: "-.25rem", verticalAlign: "middle" };
|
||||
switch (Math.floor(status / 100)) {
|
||||
case 2:
|
||||
case 3:
|
||||
return <FiberManualRecordIcon style={{ ...style, color: green[400] }} />;
|
||||
return (
|
||||
<FiberManualRecordIcon
|
||||
style={{ ...style, color: theme.palette.secondary.main }}
|
||||
/>
|
||||
);
|
||||
case 4:
|
||||
return <FiberManualRecordIcon style={{ ...style, color: orange[400] }} />;
|
||||
return (
|
||||
<FiberManualRecordIcon style={{ ...style, color: orange["A400"] }} />
|
||||
);
|
||||
case 5:
|
||||
return <FiberManualRecordIcon style={{ ...style, color: red[400] }} />;
|
||||
return <FiberManualRecordIcon style={{ ...style, color: red["A400"] }} />;
|
||||
default:
|
||||
return <FiberManualRecordIcon style={style} />;
|
||||
}
|
||||
}
|
||||
|
||||
export default HttpStatusIcon;
|
||||
export default withTheme(HttpStatusIcon);
|
||||
|
@ -65,13 +65,13 @@ function LogDetail({ requestId: id }: Props): JSX.Element {
|
||||
<div>
|
||||
<Grid container item spacing={2}>
|
||||
<Grid item xs={6}>
|
||||
<Box component={Paper} maxHeight="62vh" overflow="scroll">
|
||||
<Box component={Paper}>
|
||||
<RequestDetail request={{ method, url, proto, headers, body }} />
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
{response && (
|
||||
<Box component={Paper} maxHeight="62vh" overflow="scroll">
|
||||
<Box component={Paper}>
|
||||
<ResponseDetail response={response} />
|
||||
</Box>
|
||||
)}
|
||||
|
@ -57,7 +57,7 @@ function RequestDetail({ request }: Props): JSX.Element {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Box mx={2} my={2}>
|
||||
<Box p={2}>
|
||||
<Typography
|
||||
variant="overline"
|
||||
color="textSecondary"
|
||||
@ -79,7 +79,7 @@ function RequestDetail({ request }: Props): JSX.Element {
|
||||
|
||||
<Divider />
|
||||
|
||||
<Box m={2}>
|
||||
<Box p={2}>
|
||||
<HttpHeadersTable headers={headers} />
|
||||
</Box>
|
||||
|
||||
|
@ -19,27 +19,13 @@ import CenteredPaper from "../CenteredPaper";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
requestTitle: {
|
||||
width: "calc(100% - 80px)",
|
||||
fontSize: "1rem",
|
||||
wordBreak: "break-all",
|
||||
whiteSpace: "pre-wrap",
|
||||
},
|
||||
headersTable: {
|
||||
tableLayout: "fixed",
|
||||
width: "100%",
|
||||
},
|
||||
headerKeyCell: {
|
||||
verticalAlign: "top",
|
||||
width: "30%",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
headerValueCell: {
|
||||
width: "70%",
|
||||
verticalAlign: "top",
|
||||
wordBreak: "break-all",
|
||||
whiteSpace: "pre-wrap",
|
||||
row: {
|
||||
"&:hover": {
|
||||
cursor: "pointer",
|
||||
},
|
||||
},
|
||||
/* Pseudo-class applied to the root element if `hover={true}`. */
|
||||
hover: {},
|
||||
})
|
||||
);
|
||||
|
||||
@ -88,6 +74,7 @@ function RequestListTable({
|
||||
onLogClick,
|
||||
theme,
|
||||
}: RequestListTableProps): JSX.Element {
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<TableContainer
|
||||
component={Paper}
|
||||
@ -117,15 +104,15 @@ function RequestListTable({
|
||||
|
||||
const rowStyle = {
|
||||
backgroundColor:
|
||||
id === selectedReqLogId
|
||||
? theme.palette.action.selected
|
||||
: "inherit",
|
||||
id === selectedReqLogId && theme.palette.action.selected,
|
||||
};
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
key={id}
|
||||
className={classes.row}
|
||||
style={rowStyle}
|
||||
hover
|
||||
onClick={() => onLogClick(id)}
|
||||
>
|
||||
<TableCell style={{ ...cellStyle, width: "100px" }}>
|
||||
|
@ -20,7 +20,7 @@ function ResponseDetail({ response }: Props): JSX.Element {
|
||||
)?.value;
|
||||
return (
|
||||
<div>
|
||||
<Box mx={2} my={2}>
|
||||
<Box p={2}>
|
||||
<Typography
|
||||
variant="overline"
|
||||
color="textSecondary"
|
||||
@ -48,7 +48,7 @@ function ResponseDetail({ response }: Props): JSX.Element {
|
||||
|
||||
<Divider />
|
||||
|
||||
<Box m={2}>
|
||||
<Box p={2}>
|
||||
<HttpHeadersTable headers={response.headers} />
|
||||
</Box>
|
||||
|
||||
|
Reference in New Issue
Block a user