Replace SQLite with BadgerDB

This commit is contained in:
David Stotijn
2022-01-21 11:45:54 +01:00
parent 8a3b3cbf02
commit d84d2d0905
49 changed files with 2496 additions and 2677 deletions

View File

@ -24,9 +24,19 @@ const useStyles = makeStyles((theme: Theme) =>
})
);
const CREATE_PROJECT = gql`
mutation CreateProject($name: String!) {
createProject(name: $name) {
id
name
}
}
`;
const OPEN_PROJECT = gql`
mutation OpenProject($name: String!) {
openProject(name: $name) {
mutation OpenProject($id: ID!) {
openProject(id: $id) {
id
name
isActive
}
@ -37,8 +47,15 @@ function NewProject(): JSX.Element {
const classes = useStyles();
const [input, setInput] = useState(null);
const [openProject, { error, loading }] = useMutation(OPEN_PROJECT, {
onError: () => {},
const [createProject, { error: createProjErr, loading: createProjLoading }] = useMutation(CREATE_PROJECT, {
onError: () => { },
onCompleted(data) {
input.value = "";
openProject({ variables: { id: data.createProject.id } });
},
});
const [openProject, { error: openProjErr, loading: openProjLoading }] = useMutation(OPEN_PROJECT, {
onError: () => { },
onCompleted() {
input.value = "";
},
@ -47,10 +64,11 @@ function NewProject(): JSX.Element {
fields: {
activeProject() {
const activeProjRef = cache.writeFragment({
id: openProject.name,
id: openProject.id,
data: openProject,
fragment: gql`
fragment ActiveProject on Project {
id
name
isActive
type
@ -61,10 +79,11 @@ function NewProject(): JSX.Element {
},
projects(_, { DELETE }) {
cache.writeFragment({
id: openProject.name,
id: openProject.id,
data: openProject,
fragment: gql`
fragment OpenProject on Project {
id
name
isActive
type
@ -78,9 +97,9 @@ function NewProject(): JSX.Element {
},
});
const handleNewProjectForm = (e: React.SyntheticEvent) => {
const handleCreateAndOpenProjectForm = (e: React.SyntheticEvent) => {
e.preventDefault();
openProject({ variables: { name: input.value } });
createProject({ variables: { name: input.value } });
};
return (
@ -88,7 +107,7 @@ function NewProject(): JSX.Element {
<Box mb={3}>
<Typography variant="h6">New project</Typography>
</Box>
<form onSubmit={handleNewProjectForm} autoComplete="off">
<form onSubmit={handleCreateAndOpenProjectForm} autoComplete="off">
<TextField
className={classes.projectName}
color="secondary"
@ -100,8 +119,8 @@ function NewProject(): JSX.Element {
}}
label="Project name"
placeholder="Project name…"
error={Boolean(error)}
helperText={error && error.message}
error={Boolean(createProjErr || openProjErr)}
helperText={createProjErr && createProjErr.message || openProjErr && openProjErr.message}
/>
<Button
className={classes.button}
@ -109,8 +128,8 @@ function NewProject(): JSX.Element {
variant="contained"
color="secondary"
size="large"
disabled={loading}
startIcon={loading ? <CircularProgress size={22} /> : <AddIcon />}
disabled={createProjLoading || openProjLoading}
startIcon={createProjLoading || openProjLoading ? <CircularProgress size={22} /> : <AddIcon />}
>
Create & open project
</Button>

View File

@ -48,6 +48,7 @@ const useStyles = makeStyles((theme: Theme) =>
const PROJECTS = gql`
query Projects {
projects {
id
name
isActive
}
@ -55,8 +56,9 @@ const PROJECTS = gql`
`;
const OPEN_PROJECT = gql`
mutation OpenProject($name: String!) {
openProject(name: $name) {
mutation OpenProject($id: ID!) {
openProject(id: $id) {
id
name
isActive
}
@ -72,8 +74,8 @@ const CLOSE_PROJECT = gql`
`;
const DELETE_PROJECT = gql`
mutation DeleteProject($name: String!) {
deleteProject(name: $name) {
mutation DeleteProject($id: ID!) {
deleteProject(id: $id) {
success
}
}
@ -89,7 +91,7 @@ function ProjectList(): JSX.Element {
{ error: openProjErr, loading: openProjLoading },
] = useMutation(OPEN_PROJECT, {
errorPolicy: "all",
onError: () => {},
onError: () => { },
update(cache, { data: { openProject } }) {
cache.modify({
fields: {
@ -98,6 +100,7 @@ function ProjectList(): JSX.Element {
data: openProject,
fragment: gql`
fragment ActiveProject on Project {
id
name
isActive
type
@ -108,10 +111,11 @@ function ProjectList(): JSX.Element {
},
projects(_, { DELETE }) {
cache.writeFragment({
id: openProject.name,
id: openProject.id,
data: openProject,
fragment: gql`
fragment OpenProject on Project {
id
name
isActive
type
@ -129,7 +133,7 @@ function ProjectList(): JSX.Element {
});
const [closeProject, { error: closeProjErr }] = useMutation(CLOSE_PROJECT, {
errorPolicy: "all",
onError: () => {},
onError: () => { },
update(cache) {
cache.modify({
fields: {
@ -151,7 +155,7 @@ function ProjectList(): JSX.Element {
{ loading: deleteProjLoading, error: deleteProjErr },
] = useMutation(DELETE_PROJECT, {
errorPolicy: "all",
onError: () => {},
onError: () => { },
update(cache) {
cache.modify({
fields: {
@ -165,14 +169,14 @@ function ProjectList(): JSX.Element {
},
});
const [deleteProjName, setDeleteProjName] = useState(null);
const [deleteProj, setDeleteProj] = useState(null);
const [deleteDiagOpen, setDeleteDiagOpen] = useState(false);
const handleDeleteButtonClick = (name: string) => {
setDeleteProjName(name);
const handleDeleteButtonClick = (project: any) => {
setDeleteProj(project);
setDeleteDiagOpen(true);
};
const handleDeleteConfirm = () => {
deleteProject({ variables: { name: deleteProjName } });
deleteProject({ variables: { id: deleteProj.id } });
};
const handleDeleteCancel = () => {
setDeleteDiagOpen(false);
@ -190,7 +194,7 @@ function ProjectList(): JSX.Element {
<div>
<Dialog open={deleteDiagOpen} onClose={handleDeleteCancel}>
<DialogTitle>
Delete project <strong>{deleteProjName}</strong>?
Delete project <strong>{deleteProj?.name}</strong>?
</DialogTitle>
<DialogContent>
<DialogContentText>
@ -223,7 +227,7 @@ function ProjectList(): JSX.Element {
onClose={handleCloseDeleteNotif}
>
<Alert onClose={handleCloseDeleteNotif} severity="info">
Project <strong>{deleteProjName}</strong> was deleted.
Project <strong>{deleteProj?.name}</strong> was deleted.
</Alert>
</Snackbar>
@ -253,7 +257,7 @@ function ProjectList(): JSX.Element {
{projData?.projects.length > 0 && (
<List className={classes.projectsList}>
{projData.projects.map((project) => (
<ListItem key={project.name}>
<ListItem key={project.id}>
<ListItemAvatar>
<Avatar
className={
@ -281,7 +285,7 @@ function ProjectList(): JSX.Element {
disabled={openProjLoading || projLoading}
onClick={() =>
openProject({
variables: { name: project.name },
variables: { id: project.id },
})
}
>
@ -293,7 +297,7 @@ function ProjectList(): JSX.Element {
<Tooltip title="Delete project">
<span>
<IconButton
onClick={() => handleDeleteButtonClick(project.name)}
onClick={() => handleDeleteButtonClick(project)}
disabled={project.isActive}
>
<DeleteIcon />

View File

@ -32,7 +32,7 @@ const HTTP_REQUEST_LOG = gql`
`;
interface Props {
requestId: number;
requestId: string;
}
function LogDetail({ requestId: id }: Props): JSX.Element {

View File

@ -15,12 +15,10 @@ import { useHttpRequestLogs } from "./hooks/useHttpRequestLogs";
function LogsOverview(): JSX.Element {
const router = useRouter();
const detailReqLogId =
router.query.id && parseInt(router.query.id as string, 10);
const detailReqLogId = router.query.id as string | undefined;
const { loading, error, data } = useHttpRequestLogs();
const handleLogClick = (reqId: number) => {
const handleLogClick = (reqId: string) => {
router.push("/proxy/logs?id=" + reqId, undefined, {
shallow: false,
});

View File

@ -31,8 +31,8 @@ const useStyles = makeStyles((theme: Theme) =>
interface Props {
logs: Array<any>;
selectedReqLogId?: number;
onLogClick(requestId: number): void;
selectedReqLogId?: string;
onLogClick(requestId: string): void;
theme: Theme;
}
@ -63,8 +63,8 @@ function RequestList({
interface RequestListTableProps {
logs?: any;
selectedReqLogId?: number;
onLogClick(requestId: number): void;
selectedReqLogId?: string;
onLogClick(requestId: string): void;
theme: Theme;
}

View File

@ -9,13 +9,7 @@ function createApolloClient() {
link: new HttpLink({
uri: "/api/graphql/",
}),
cache: new InMemoryCache({
typePolicies: {
Project: {
keyFields: ["name"],
},
},
}),
cache: new InMemoryCache(),
});
}

View File

@ -1,30 +1,17 @@
import {
Avatar,
Box,
Button,
CircularProgress,
createStyles,
List,
ListItem,
ListItemAvatar,
ListItemText,
makeStyles,
TextField,
Theme,
Typography,
} from "@material-ui/core";
import AddIcon from "@material-ui/icons/Add";
import FolderIcon from "@material-ui/icons/Folder";
import DescriptionIcon from "@material-ui/icons/Description";
import PlayArrowIcon from "@material-ui/icons/PlayArrow";
import Link from "next/link";
import { useState } from "react";
import { gql, useMutation, useQuery } from "@apollo/client";
import { useRouter } from "next/router";
import Layout, { Page } from "../components/Layout";
import { Alert } from "@material-ui/lab";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@ -37,107 +24,14 @@ const useStyles = makeStyles((theme: Theme) =>
lineHeight: 2,
marginBottom: theme.spacing(5),
},
projectName: {
marginTop: -6,
marginRight: theme.spacing(2),
},
button: {
marginRight: theme.spacing(2),
},
activeProject: {
color: theme.palette.getContrastText(theme.palette.secondary.main),
backgroundColor: theme.palette.secondary.main,
},
})
);
const ACTIVE_PROJECT = gql`
query ActiveProject {
activeProject {
name
}
}
`;
const OPEN_PROJECT = gql`
mutation OpenProject($name: String!) {
openProject(name: $name) {
name
isActive
}
}
`;
function Index(): JSX.Element {
const classes = useStyles();
const router = useRouter();
const [input, setInput] = useState(null);
const { error: activeProjErr, data: activeProjData } = useQuery(
ACTIVE_PROJECT,
{
pollInterval: 1000,
}
);
const [
openProject,
{ error: openProjErr, data: openProjData, loading: openProjLoading },
] = useMutation(OPEN_PROJECT, {
onError: () => {},
onCompleted({ openProject }) {
if (openProject) {
router.push("/get-started");
}
},
update(cache, { data: { openProject } }) {
cache.modify({
fields: {
activeProject() {
const activeProjRef = cache.writeFragment({
id: openProject.name,
data: openProject,
fragment: gql`
fragment ActiveProject on Project {
name
isActive
type
}
`,
});
return activeProjRef;
},
projects(_, { DELETE }) {
cache.writeFragment({
id: openProject.name,
data: openProject,
fragment: gql`
fragment OpenProject on Project {
name
isActive
type
}
`,
});
return DELETE;
},
},
});
},
});
const handleForm = (e: React.SyntheticEvent) => {
e.preventDefault();
openProject({ variables: { name: input.value } });
};
if (activeProjErr) {
return (
<Layout page={Page.Home} title="">
<Alert severity="error">
Error fetching active project: {activeProjErr.message}
</Alert>
</Layout>
);
}
return (
<Layout page={Page.Home} title="">
@ -157,97 +51,18 @@ function Index(): JSX.Element {
<code>:8080</code>
</Typography>
{activeProjData?.activeProject?.name ? (
<div>
<Box mb={1}>
<Typography variant="h6">Active project:</Typography>
</Box>
<Box ml={-2} mb={2}>
<List>
<ListItem>
<ListItemAvatar>
<Avatar className={classes.activeProject}>
<DescriptionIcon />
</Avatar>
</ListItemAvatar>
<ListItemText primary={activeProjData.activeProject.name} />
</ListItem>
</List>
</Box>
<div>
<Link href="/get-started" passHref>
<Button
className={classes.button}
variant="outlined"
component="a"
color="secondary"
size="large"
startIcon={<PlayArrowIcon />}
>
Get started
</Button>
</Link>
<Link href="/projects" passHref>
<Button
className={classes.button}
variant="outlined"
component="a"
size="large"
startIcon={<FolderIcon />}
>
Manage projects
</Button>
</Link>
</div>
</div>
) : (
<form onSubmit={handleForm} autoComplete="off">
<TextField
className={classes.projectName}
color="secondary"
inputProps={{
id: "projectName",
ref: (node) => {
setInput(node);
},
}}
label="Project name"
placeholder="Project name…"
error={Boolean(openProjErr)}
helperText={openProjErr && openProjErr.message}
/>
<Button
className={classes.button}
type="submit"
variant="contained"
color="secondary"
size="large"
disabled={
openProjLoading || Boolean(openProjData?.openProject?.name)
}
startIcon={
openProjLoading || openProjData?.openProject ? (
<CircularProgress size={22} />
) : (
<AddIcon />
)
}
>
Create project
</Button>
<Link href="/projects" passHref>
<Button
className={classes.button}
variant="outlined"
component="a"
size="large"
startIcon={<FolderIcon />}
>
Open project
</Button>
</Link>
</form>
)}
<Link href="/projects" passHref>
<Button
className={classes.button}
variant="contained"
color="secondary"
component="a"
size="large"
startIcon={<FolderIcon />}
>
Manage projects
</Button>
</Link>
</Box>
</Layout>
);

View File

@ -12,7 +12,7 @@ function Index(): JSX.Element {
</Box>
<Typography paragraph>
Projects contain settings and data generated/processed by Hetty. They
are stored as SQLite database files on disk.
are stored in a single database on disk.
</Typography>
<Box my={4}>
<Divider />