Skip to content

Commit 3059f8c

Browse files
committed
Much innovation
1 parent cd4c1fb commit 3059f8c

File tree

9 files changed

+318
-86
lines changed

9 files changed

+318
-86
lines changed

frontend/src/App.tsx

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,35 @@
11
import { RouterProvider, createBrowserRouter } from "react-router-dom";
22
import Sidebar from "./AppFrame";
33
import Home from "./routes/Home";
4+
import ViewBatch from "./routes/batch/ViewBatch";
5+
import Error404 from "./routes/404";
46

57
export default function App() {
6-
const router = createBrowserRouter([
8+
const router = createBrowserRouter(
9+
[
10+
{
11+
path: "*",
12+
Component: Sidebar,
13+
children: [
14+
{
15+
index: true,
16+
Component: Home,
17+
},
18+
{
19+
path: "batches",
20+
},
21+
{
22+
path: "batches/:batchId",
23+
Component: ViewBatch,
24+
},
25+
{ path: "*", Component: Error404 },
26+
],
27+
},
28+
],
729
{
8-
path: "*",
9-
Component: Sidebar,
10-
children: [
11-
{
12-
index: true,
13-
Component: Home,
14-
},
15-
]
30+
basename: "/app/",
1631
}
17-
], {
18-
basename: "/app/"
19-
});
32+
);
2033

2134
return <RouterProvider router={router} />;
2235
}

frontend/src/AppFrame.tsx

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
11
import {
22
Box,
3+
Divider,
34
Drawer,
45
List,
56
ListItemButton,
67
ListItemText,
78
Paper,
89
Typography,
910
} from "@mui/material";
10-
import React from "react";
11+
import React, { PropsWithChildren, useEffect } from "react";
1112
import {
1213
Outlet,
1314
Link as RouterLink,
1415
LinkProps as RouterLinkProps,
16+
To,
1517
useLocation,
1618
} from "react-router-dom";
1719

18-
interface ListItemLinkProps {
19-
children: string;
20-
to: string;
21-
}
2220

2321
const Link = React.forwardRef<HTMLAnchorElement, RouterLinkProps>(function Link(
2422
itemProps,
@@ -27,8 +25,7 @@ const Link = React.forwardRef<HTMLAnchorElement, RouterLinkProps>(function Link(
2725
return <RouterLink ref={ref} {...itemProps} role={undefined} />;
2826
});
2927

30-
export function ListItemLink(props: ListItemLinkProps) {
31-
const { children, to } = props;
28+
export function ListItemLink({children, to}: PropsWithChildren<{to: To}>) {
3229
const currentPath = useLocation().pathname;
3330

3431
const child = (
@@ -50,6 +47,15 @@ export function ListItemLink(props: ListItemLinkProps) {
5047
);
5148
}
5249

50+
function SidebarSection({ title, children }: PropsWithChildren<{ title: string}>) {
51+
return (
52+
<section>
53+
<Typography variant="h6" textAlign="center">{title}</Typography>
54+
{children}
55+
</section>
56+
)
57+
}
58+
5359
function Sidebar() {
5460
return (
5561
<Box component="aside" sx={{ width: { sm: "10%" }, flexShrink: { sm: 0 } }}>
@@ -61,32 +67,53 @@ function Sidebar() {
6167
<Paper elevation={0} square>
6268
<List>
6369
<ListItemLink to="/">Home</ListItemLink>
70+
<Divider />
71+
<SidebarSection title="Batches">
72+
<ListItemLink to="/batches">View All</ListItemLink>
73+
<ListItemLink to="/batches/new">Create New</ListItemLink>
74+
<ListItemLink to="/batches/view">View Batch</ListItemLink>
75+
</SidebarSection>
6476
</List>
6577
</Paper>
6678
</Drawer>
6779
</Box>
6880
);
6981
}
7082

83+
7184
export const SetTitleContext = React.createContext<
7285
(newTitle: string) => unknown
7386
>(() => {});
7487

7588
export default function AppFrameOutlet() {
7689
const [title, setTitle] = React.useState("");
7790

91+
useEffect(() => {
92+
document.title = `${title}${
93+
title.length > 0 ? " - " : ""
94+
}Wayback Archiver Server Data Viewer`;
95+
}, [title]);
96+
7897
return (
7998
<div>
8099
<Box sx={{ display: "flex" }}>
81100
<Sidebar />
82101
<Box component="main" sx={{ flexGrow: 1, p: 3, width: { sm: "90%" } }}>
83-
<Box sx={{ width: { sm: "100%" }, px: 3, pb: 1.5, textAlign: "center", borderBottom: "1px solid black" }}>
84-
<Box>
85-
<Typography variant="h1" sx={{fontSize: "200%"}}>
86-
{title} {title ?? "-"} Wayback Archiver Server Data Viewer
87-
</Typography>
88-
</Box>
89-
</Box>
102+
<Box
103+
sx={{
104+
width: { sm: "100%" },
105+
px: 3,
106+
pb: 1.5,
107+
textAlign: "center",
108+
borderBottom: "1px solid black",
109+
}}
110+
>
111+
<Box>
112+
<Typography variant="h1" sx={{ fontSize: "200%" }}>
113+
{title} {title && "-"} Wayback Archiver Server Data Viewer
114+
</Typography>
115+
</Box>
116+
</Box>
90117
<SetTitleContext.Provider value={setTitle}>
91118
<Outlet />
92119
</SetTitleContext.Provider>

frontend/src/api/api.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
11
import createClient from "openapi-fetch";
2-
import { paths } from "./schema"; // generated from openapi-typescript
2+
import { paths, components } from "./schema"; // generated from openapi-typescript
33

44
const basePath = import.meta.env.PROD ? "/" : "http://localhost:8000/";
55

66
const client = createClient<paths>({ baseUrl: basePath });
77

88
export const { GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, TRACE } = client;
99

10-
export type JobMaybe = paths["/current_job"]["get"]["responses"]["200"]["content"]["application/json"]["job"];
11-
export type Job = NonNullable<JobMaybe>;
12-
export type Stats = paths["/stats"]["get"]["responses"]["200"]["content"]["application/json"];
10+
export type Job = components["schemas"]["JobReturn"];
11+
export type JobMaybe = Job | null;
12+
export type Stats = components["schemas"]["Stats"];
13+
export type Batch = components["schemas"]["BatchReturn"];
14+
export type RepeatURL = components["schemas"]["RepeatURL"];
15+
16+
export interface Paginated<T> {
17+
data: T[];
18+
pagination: {
19+
current_page: number;
20+
total_pages: number;
21+
items: number;
22+
}
23+
}
24+
25+
export type PaginatedJob = Paginated<Job>;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { PropsWithChildren } from "react";
2+
import inlineSkeleton from "./inlineSkeleton";
3+
4+
export default function InlineSkeletonDisplay({ children }: PropsWithChildren) {
5+
console.log(children);
6+
return children !== null ? <b>{children}</b> : inlineSkeleton;
7+
}

frontend/src/misc/inlineSkeleton.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Skeleton } from "@mui/material";
2+
3+
const inlineSkeleton = (
4+
<Skeleton
5+
variant="text"
6+
width={50}
7+
sx={{ fontSize: "1rem", display: "inline-block" }}
8+
/>
9+
);
10+
11+
export default inlineSkeleton;

frontend/src/routes/404.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { Button, Typography, Box } from "@mui/material";
2+
import { useContext } from "react";
3+
import { useNavigate } from "react-router-dom";
4+
import { SetTitleContext } from "../AppFrame";
5+
6+
export default function Error404() {
7+
const nav = useNavigate();
8+
const setTitle = useContext(SetTitleContext);
9+
10+
setTitle("404 Not Found");
11+
12+
return (
13+
<Box
14+
display="flex"
15+
justifyContent="center"
16+
alignContent="center"
17+
flexDirection="column"
18+
>
19+
<div>
20+
<Typography variant="body1" fontSize="200%">
21+
The page you requested does not exist.
22+
</Typography>
23+
</div>
24+
<div>
25+
<Button variant="contained" onClick={() => nav(-1)}>
26+
Go back
27+
</Button>
28+
</div>
29+
</Box>
30+
);
31+
}

0 commit comments

Comments
 (0)