Tidy up proxy logs, add copy action for headers

This commit is contained in:
David Stotijn
2020-09-27 18:59:38 +02:00
parent 854839daf8
commit ab90bfe4e9
11 changed files with 140 additions and 78 deletions

View File

@ -25,6 +25,13 @@ import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
import clsx from "clsx";
export enum Page {
Home,
ProxySetup,
ProxyLogs,
Sender,
}
const drawerWidth = 240;
const useStyles = makeStyles((theme: Theme) =>
@ -49,7 +56,7 @@ const useStyles = makeStyles((theme: Theme) =>
}),
},
menuButton: {
marginRight: 36,
marginRight: 28,
},
hide: {
display: "none",
@ -100,10 +107,20 @@ const useStyles = makeStyles((theme: Theme) =>
listItemIcon: {
minWidth: 42,
},
titleHighlight: {
color: theme.palette.secondary.main,
marginRight: 4,
},
})
);
export function Layout(props: { children: React.ReactNode }): JSX.Element {
interface Props {
children: React.ReactNode;
title: string;
page: Page;
}
export function Layout({ title, page, children }: Props): JSX.Element {
const classes = useStyles();
const theme = useTheme();
const [open, setOpen] = React.useState(false);
@ -137,7 +154,10 @@ export function Layout(props: { children: React.ReactNode }): JSX.Element {
<MenuIcon />
</IconButton>
<Typography variant="h5" noWrap>
Hetty://
<span className={title !== "" && classes.titleHighlight}>
Hetty://
</span>
{title}
</Typography>
</Toolbar>
</AppBar>
@ -170,6 +190,7 @@ export function Layout(props: { children: React.ReactNode }): JSX.Element {
button
component="a"
key="home"
selected={page === Page.Home}
className={classes.listItem}
>
<Tooltip title="Home">
@ -184,7 +205,8 @@ export function Layout(props: { children: React.ReactNode }): JSX.Element {
<ListItem
button
component="a"
key="proxy"
key="proxyLogs"
selected={page === Page.ProxyLogs}
className={classes.listItem}
>
<Tooltip title="Proxy">
@ -200,6 +222,7 @@ export function Layout(props: { children: React.ReactNode }): JSX.Element {
button
component="a"
key="sender"
selected={page === Page.Sender}
className={classes.listItem}
>
<Tooltip title="Sender">
@ -214,7 +237,7 @@ export function Layout(props: { children: React.ReactNode }): JSX.Element {
</Drawer>
<main className={classes.content}>
<div className={classes.toolbar} />
{props.children}
{children}
</main>
</div>
);

View File

@ -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>
);
}

View File

@ -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);

View File

@ -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>
)}

View File

@ -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>

View File

@ -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" }}>

View File

@ -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>

View File

@ -11,7 +11,7 @@ import SettingsEthernetIcon from "@material-ui/icons/SettingsEthernet";
import SendIcon from "@material-ui/icons/Send";
import Link from "next/link";
import Layout from "../components/Layout";
import Layout, { Page } from "../components/Layout";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@ -33,7 +33,7 @@ const useStyles = makeStyles((theme: Theme) =>
function Index(): JSX.Element {
const classes = useStyles();
return (
<Layout>
<Layout page={Page.Home} title="">
<Box p={4}>
<Box mb={4} width="60%">
<Typography variant="h2">

View File

@ -1,16 +1,13 @@
import React from "react";
import { Box, Button, Typography } from "@material-ui/core";
import { Button, Typography } from "@material-ui/core";
import ListIcon from "@material-ui/icons/List";
import Link from "next/link";
import Layout from "../../components/Layout";
import Layout, { Page } from "../../components/Layout";
function Index(): JSX.Element {
return (
<Layout>
<Box mb={2}>
<Typography variant="h5">Proxy setup</Typography>
</Box>
<Layout page={Page.ProxySetup} title="Proxy setup">
<Typography paragraph>Coming soon</Typography>
<Link href="/proxy/logs" passHref>
<Button

View File

@ -1,14 +1,9 @@
import { Typography, Box } from "@material-ui/core";
import LogsOverview from "../../../components/reqlog/LogsOverview";
import Layout from "../../../components/Layout";
import Layout, { Page } from "../../../components/Layout";
function ProxyLogs(): JSX.Element {
return (
<Layout>
<Box mb={2}>
<Typography variant="h5">Proxy logs</Typography>
</Box>
<Layout page={Page.ProxyLogs} title="Proxy logs">
<LogsOverview />
</Layout>
);

View File

@ -1,13 +1,10 @@
import { Box, Typography } from "@material-ui/core";
import Layout from "../../components/Layout";
import Layout, { Page } from "../../components/Layout";
function Index(): JSX.Element {
return (
<Layout>
<Box mb={2}>
<Typography variant="h5">Sender</Typography>
</Box>
<Layout page={Page.Sender} title="Sender">
<Typography paragraph>Coming soon</Typography>
</Layout>
);