mirror of
https://github.com/Myzel394/kleckrelay-website.git
synced 2025-06-19 07:55:25 +02:00
feat(api-keys): Add API overview
This commit is contained in:
parent
7cd798a343
commit
eeb6ba4892
10
public/locales/en-US/settings-api-keys.json
Normal file
10
public/locales/en-US/settings-api-keys.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"title": "Manage your API Keys",
|
||||||
|
"create": {
|
||||||
|
"label": "Create a new API Key"
|
||||||
|
},
|
||||||
|
"emptyState": {
|
||||||
|
"title": "Welcome to your API Keys",
|
||||||
|
"description": "Create an API Key to get started with the API."
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,6 @@
|
|||||||
"actions": {
|
"actions": {
|
||||||
"enable2fa": "Two-Factor-Authentication",
|
"enable2fa": "Two-Factor-Authentication",
|
||||||
"aliasPreferences": "Alias Preferences",
|
"aliasPreferences": "Alias Preferences",
|
||||||
"apiKeys": "Edit API Keys"
|
"apiKeys": "Manage API Keys"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import ReservedAliasDetailRoute from "~/routes/ReservedAliasDetailRoute"
|
|||||||
import ReservedAliasesRoute from "~/routes/ReservedAliasesRoute"
|
import ReservedAliasesRoute from "~/routes/ReservedAliasesRoute"
|
||||||
import RootRoute from "~/routes/Root"
|
import RootRoute from "~/routes/Root"
|
||||||
import Settings2FARoute from "~/routes/Settings2FARoute"
|
import Settings2FARoute from "~/routes/Settings2FARoute"
|
||||||
|
import SettingsAPIKeysRoute from "~/routes/SettingsAPIKeysRoute"
|
||||||
import SettingsAliasPreferencesRoute from "~/routes/SettingsAliasPreferencesRoute"
|
import SettingsAliasPreferencesRoute from "~/routes/SettingsAliasPreferencesRoute"
|
||||||
import SettingsRoute from "~/routes/SettingsRoute"
|
import SettingsRoute from "~/routes/SettingsRoute"
|
||||||
import SignupRoute from "~/routes/SignupRoute"
|
import SignupRoute from "~/routes/SignupRoute"
|
||||||
@ -105,6 +106,10 @@ const router = createBrowserRouter([
|
|||||||
path: "/settings/2fa",
|
path: "/settings/2fa",
|
||||||
element: <Settings2FARoute />,
|
element: <Settings2FARoute />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/settings/api-keys",
|
||||||
|
element: <SettingsAPIKeysRoute />,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/reports",
|
path: "/reports",
|
||||||
loader: getServerSettings,
|
loader: getServerSettings,
|
||||||
|
24
src/route-widgets/SettingsAPIKeysRoute/APIKeyListItem.tsx
Normal file
24
src/route-widgets/SettingsAPIKeysRoute/APIKeyListItem.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {ReactElement} from "react"
|
||||||
|
import {APIKey} from "~/server-types"
|
||||||
|
import {IconButton, ListItem, ListItemSecondaryAction, ListItemText} from "@mui/material"
|
||||||
|
import {useTranslation} from "react-i18next"
|
||||||
|
import {MdDelete} from "react-icons/md"
|
||||||
|
|
||||||
|
export interface APIKeyListItemProps {
|
||||||
|
apiKey: APIKey
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function APIKeyListItem({apiKey}: APIKeyListItemProps): ReactElement {
|
||||||
|
const {t} = useTranslation("settings-api-keys")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText primary={apiKey.label} secondary={apiKey.expiresAt.toString()} />
|
||||||
|
<ListItemSecondaryAction>
|
||||||
|
<IconButton edge="end">
|
||||||
|
<MdDelete />
|
||||||
|
</IconButton>
|
||||||
|
</ListItemSecondaryAction>
|
||||||
|
</ListItem>
|
||||||
|
)
|
||||||
|
}
|
35
src/route-widgets/SettingsAPIKeysRoute/EmptyStateScreen.tsx
Normal file
35
src/route-widgets/SettingsAPIKeysRoute/EmptyStateScreen.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import {ReactElement} from "react"
|
||||||
|
import {useTranslation} from "react-i18next"
|
||||||
|
|
||||||
|
import {Container, Grid, Typography} from "@mui/material"
|
||||||
|
import {MdVpnKey} from "react-icons/md"
|
||||||
|
|
||||||
|
export default function EmptyStateScreen(): ReactElement {
|
||||||
|
const {t} = useTranslation("settings-api-keys")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container maxWidth="xs">
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={4}
|
||||||
|
direction="column"
|
||||||
|
alignItems="center"
|
||||||
|
maxWidth="80%"
|
||||||
|
alignSelf="center"
|
||||||
|
marginX="auto"
|
||||||
|
>
|
||||||
|
<Grid item>
|
||||||
|
<Typography variant="h6" component="h2">
|
||||||
|
{t("emptyState.title")}
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
<Grid item>
|
||||||
|
<MdVpnKey size={40} />
|
||||||
|
</Grid>
|
||||||
|
<Grid item>
|
||||||
|
<Typography variant="body1">{t("emptyState.description")}</Typography>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
48
src/routes/SettingsAPIKeysRoute.tsx
Normal file
48
src/routes/SettingsAPIKeysRoute.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import {ReactElement} from "react"
|
||||||
|
import {useTranslation} from "react-i18next"
|
||||||
|
import {useQuery} from "@tanstack/react-query"
|
||||||
|
import {APIKey, PaginationResult} from "~/server-types"
|
||||||
|
import {AxiosError} from "axios"
|
||||||
|
import {getAPIKeys} from "~/apis"
|
||||||
|
import {QueryResult, SimplePage} from "~/components"
|
||||||
|
import {Button, List} from "@mui/material"
|
||||||
|
import {Link} from "react-router-dom"
|
||||||
|
import APIKeyListItem from "~/route-widgets/SettingsAPIKeysRoute/APIKeyListItem"
|
||||||
|
import EmptyStateScreen from "~/route-widgets/SettingsAPIKeysRoute/EmptyStateScreen"
|
||||||
|
|
||||||
|
export default function SettingsAPIKeysRoute(): ReactElement {
|
||||||
|
const {t} = useTranslation("settings-api-keys")
|
||||||
|
const query = useQuery<PaginationResult<APIKey>, AxiosError>(["get_api_keys"], () =>
|
||||||
|
getAPIKeys(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SimplePage
|
||||||
|
title={t("title")}
|
||||||
|
actions={
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
component={Link}
|
||||||
|
to="/settings/api-keys/new"
|
||||||
|
>
|
||||||
|
{t("create.label")}
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<QueryResult<PaginationResult<APIKey>, AxiosError> query={query}>
|
||||||
|
{({items: apiKeys}) =>
|
||||||
|
apiKeys.length > 0 ? (
|
||||||
|
<List>
|
||||||
|
{apiKeys.map(apiKey => (
|
||||||
|
<APIKeyListItem apiKey={apiKey} key={apiKey.id} />
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
) : (
|
||||||
|
<EmptyStateScreen />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</QueryResult>
|
||||||
|
</SimplePage>
|
||||||
|
)
|
||||||
|
}
|
@ -141,6 +141,13 @@ export interface AliasList {
|
|||||||
type: AliasType
|
type: AliasType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface APIKey {
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
expiresAt: Date
|
||||||
|
scopes: string[]
|
||||||
|
}
|
||||||
|
|
||||||
export interface Report {
|
export interface Report {
|
||||||
id: string
|
id: string
|
||||||
encryptedContent: string
|
encryptedContent: string
|
||||||
|
Loading…
x
Reference in New Issue
Block a user