Skip to content

Commit

Permalink
chore: add kv browser
Browse files Browse the repository at this point in the history
  • Loading branch information
eldemcan committed Feb 25, 2024
1 parent 1accfab commit 57dfb19
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/layouts/AppLayout/menu_items.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ export const envMenuItems = ({
path: `${envPath}/feature-flags`,
isActive: pathname.includes("/feature-flags"),
},
{
text: "Key Value",
path: `${envPath}/key-value`,
isActive: pathname.includes("/key-value"),
},
];

items.push({
Expand Down
194 changes: 194 additions & 0 deletions src/pages/apps/[id]/environments/[env-id]/kv/Kv.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import {
Table,
TableCell,
TableContainer,
TableHead,
TableRow,
TableBody,
Button,
Grid,
Typography,
Box,
Accordion,
AccordionSummary,
AccordionDetails,
Alert,
LinearProgress,
} from "@mui/material";
import React, { useContext, useState } from "react";
import CodeMirror from "@uiw/react-codemirror";
import { AppContext } from "~/pages/apps/[id]/App.context";
import { EnvironmentContext } from "~/pages/apps/[id]/environments/Environment.context";
import { FetchValue, useFetchKeys } from "./actions";
import ManageSearchIcon from "@mui/icons-material/ManageSearch";
import ArrowForwardIosIcon from "@mui/icons-material/ArrowForwardIos";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import LightbulbIcon from "@mui/icons-material/Lightbulb";
import { json } from "@codemirror/lang-json";
import { instanceOf } from "prop-types";

export default function KV() {
const { app } = useContext(AppContext);
const { environment } = useContext(EnvironmentContext);
const [selectedKey, setSelectedKey] = useState(null);
const [viewData, setViewData] = useState<string | object | null>(null);
const { error, loading, keys } = useFetchKeys({
appId: app.id,
environmentId: environment.id!,
});
const curlCommand = `curl -X POST \
https://kv.stormkit.io/exec \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '["SET", "myKey", "Hello, Redis!"]'`;

const handleViewClick = (key: string) => {
FetchValue({ appId: app.id, environmentId: environment.id, key: key }).then((res) => {
if (typeof res === 'string') { // Use typeof for type checking strings
setViewData(res);
} else {
setViewData(JSON.stringify(res, null, 2) );
}
});
setSelectedKey(key);
};

return (
<>
<Accordion sx={{ marginBottom: "10px" }}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="info-box-content"
id="info-box-header"
color="white"
>
<Typography>
<LightbulbIcon />
Quick Start
</Typography>
</AccordionSummary>
<AccordionDetails sx={{ color: "white" }}>
<Typography sx={{ marginBottom: "10px" }}>
Create API key from settings and send POST request to
https://kv.stormkit.io/exec with JSON array to use Redis commands.
</Typography>
<CodeMirror
extensions={[json()]}
theme="dark"
readOnly={true}
// options={{lineWrapping: true}}
value={curlCommand}
minWidth="100%"
maxWidth="100%"
/>
<Typography sx={{ marginTop: "10px" }}>
Please check our documentation for further details
</Typography>
</AccordionDetails>
</Accordion>

{loading && <LinearProgress color="secondary" />}
{error && (
<Alert color="error">
<Box>{error}</Box>
</Alert>
)}
<Grid container>
<Grid item xs={6}>
<TableContainer
style={{
height: "400px",
overflowY: "auto",
backgroundColor: "rgba(0,0,0,0.3)",
}}
>
<Table>
<TableHead>
<TableRow>
<TableCell>Keys</TableCell>
</TableRow>
</TableHead>
<TableBody>
{keys.map((key, idx) => (
<TableRow
sx={{
"&:hover": {
backgroundColor: "rgba(255, 255, 255, 0.1)",
},
borderBottom: "1px dotted black",
backgroundColor:
selectedKey == key
? "rgba(255, 255, 255, 0.1)"
: "transparent",
}}
key={`${idx}row`}
onClick={() => handleViewClick(key)}
>
<TableCell>
<Box
key={idx}
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
}}
>
{key}
</Box>
<Box sx={{ alignItems: "right" }}>
<Button sx={{ color: "white" }}>
<ArrowForwardIosIcon fontSize="small" />
</Button>
</Box>
</Box>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Grid>

<Grid item xs={6}>
<Box>
{viewData ? (
<>
<Box sx={{ marginLeft: "10px" }}>
<CodeMirror
value={viewData}
extensions={[json()]}
theme="dark"
readOnly={true}
minWidth="100%"
maxWidth="100%"
/>
</Box>
</>
) : (
<Box
display={"grid"}
sx={{ placeItems: "center", color: "white" }}
>
<ManageSearchIcon style={{ fontSize: "2rem" }} />
<Typography>Select a key from the list</Typography>
</Box>
)}
</Box>
</Grid>
</Grid>
</>
);
}
70 changes: 70 additions & 0 deletions src/pages/apps/[id]/environments/[env-id]/kv/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { I } from "dist/assets/Grow.cd8761d3";
import { useEffect, useState } from "react";
import api from "~/utils/api/Api";

interface FetchKeysArgs {
appId?: string;
environmentId?: string;
}

interface FetchValueArgs {
appId?: string;
environmentId?: string;
key?: string;
}

interface FetchValueReturn {
val: string
}

interface FetchKeysReturnValue {
keys: string[];
error: string | null;
loading: boolean;
}

export const FetchValue = ({appId, environmentId, key}: FetchValueArgs): Promise<FetchValueReturn> => {
return api.post<FetchValueReturn>(`/apps/${appId}/envs/${environmentId}/value`, {appId: appId, envId: environmentId, key: key})
};

export const useFetchKeys = ({
appId,
environmentId,
}: FetchKeysArgs): FetchKeysReturnValue => {
const [keys, setKeys] = useState<string[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);

useEffect(() => {
if (!appId || !environmentId) {
return;
}

let unmounted = false;
setLoading(true);

api
.fetch<{ keys: string[] }>(`/apps/${appId}/envs/${environmentId}/keys`)
.then(result => {
if (!unmounted) {
setKeys(result.keys);
}
})
.catch(() => {
if (!unmounted) {
setError("Something went wrong while fetching keys");
}
})
.finally(() => {
if (!unmounted) {
setLoading(false);
}
});

return () => {
unmounted = true;
};
}, [appId, environmentId]);

return { keys, loading, error };
};
1 change: 1 addition & 0 deletions src/pages/apps/[id]/environments/[env-id]/kv/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./Kv";
6 changes: 6 additions & 0 deletions src/pages/apps/[id]/environments/[env-id]/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ const routes: Array<RouteProps> = [
() => import("~/pages/apps/[id]/environments/[env-id]/feature-flags")
),
},
{
path: "/key-value",
element: Async(
() => import("~/pages/apps/[id]/environments/[env-id]/kv")
),
},
{
path: "/function-triggers",
element: Async(
Expand Down

0 comments on commit 57dfb19

Please sign in to comment.