mirror of
https://github.com/Myzel394/kleckrelay-website.git
synced 2025-06-18 23:45:26 +02:00
commit
434eaf06d5
@ -96,8 +96,8 @@
|
||||
},
|
||||
"values": {
|
||||
"scopes": {
|
||||
"basic_profile": "Basic Profile",
|
||||
"full_profile": "Full Profile",
|
||||
"read_profile": "Read Profile",
|
||||
"update_profile": "Update Profile",
|
||||
|
||||
"read_preferences": "Read Preferences",
|
||||
"update_preferences": "Update Preferences",
|
||||
@ -108,7 +108,16 @@
|
||||
"delete_alias": "Delete Aliases",
|
||||
|
||||
"read_report": "Read Reports",
|
||||
"delete_report": "Delete Reports"
|
||||
"delete_report": "Delete Reports",
|
||||
|
||||
"read_admin_cron_report": "Read Cron Reports (Admin)",
|
||||
"read_admin_settings": "Read Settings (Admin)",
|
||||
"update_admin_settings": "Update Settings (Admin)",
|
||||
|
||||
"read_admin_reserved_alias": "Read Reserved Aliases (Admin)",
|
||||
"create_admin_reserved_alias": "Create Reserved Aliases (Admin)",
|
||||
"update_admin_reserved_alias": "Update Reserved Aliases (Admin)",
|
||||
"delete_admin_reserved_alias": "Delete Reserved Aliases (Admin)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {AliasNote} from "~/server-types"
|
||||
import {APIKeyScope, AliasNote} from "~/server-types"
|
||||
|
||||
export const LOCAL_REGEX = /^[a-zA-Z0-9!#$%&‘*+–/=?^_`.{|}~-]{1,64}$/g
|
||||
export const URL_REGEX =
|
||||
@ -16,9 +16,9 @@ export const DEFAULT_ALIAS_NOTE: AliasNote = {
|
||||
export const ERROR_SNACKBAR_SHOW_DURATION = 5000
|
||||
export const SUCCESS_SNACKBAR_SHOW_DURATION = 2000
|
||||
export const AUTHENTICATION_PATHS = ["/auth/login", "/auth/signup", "/auth/complete-account"]
|
||||
export const API_KEY_SCOPES = [
|
||||
"basic_profile",
|
||||
"full_profile",
|
||||
export const API_KEY_SCOPES: APIKeyScope[] = [
|
||||
"read:profile",
|
||||
"update:profile",
|
||||
|
||||
"read:preferences",
|
||||
"update:preferences",
|
||||
@ -31,3 +31,13 @@ export const API_KEY_SCOPES = [
|
||||
"read:report",
|
||||
"delete:report",
|
||||
]
|
||||
export const ADMIN_API_KEY_SCOPES: APIKeyScope[] = [
|
||||
"read:admin_cron_report",
|
||||
"read:admin_settings",
|
||||
"update:admin_settings",
|
||||
|
||||
"read:admin_reserved_alias",
|
||||
"create:admin_reserved_alias",
|
||||
"update:admin_reserved_alias",
|
||||
"delete:admin_reserved_alias",
|
||||
]
|
||||
|
@ -31,15 +31,17 @@ import {BiText} from "react-icons/bi"
|
||||
import {CgProfile} from "react-icons/cg"
|
||||
import {DatePicker} from "@mui/x-date-pickers"
|
||||
import {useLoaderData} from "react-router-dom"
|
||||
import {API_KEY_SCOPES} from "~/constants/values"
|
||||
import {FaMask} from "react-icons/fa"
|
||||
import {ADMIN_API_KEY_SCOPES, API_KEY_SCOPES} from "~/constants/values"
|
||||
import {FaMask, FaServer} from "react-icons/fa"
|
||||
import {MdAdd, MdCancel, MdDelete, MdEdit, MdTextSnippet} from "react-icons/md"
|
||||
import {GoSettings} from "react-icons/go"
|
||||
import {TiEye} from "react-icons/ti"
|
||||
import {useMutation} from "@tanstack/react-query"
|
||||
import {AxiosError} from "axios"
|
||||
import {parseFastAPIError} from "~/utils"
|
||||
import {useErrorSuccessSnacks} from "~/hooks"
|
||||
import {useErrorSuccessSnacks, useUser} from "~/hooks"
|
||||
import {HiDocumentReport} from "react-icons/hi"
|
||||
import {BsStarFill} from "react-icons/bs"
|
||||
import addDays from "date-fns/addDays"
|
||||
import diffInDays from "date-fns/differenceInDays"
|
||||
import set from "date-fns/set"
|
||||
@ -48,6 +50,9 @@ export interface CreateNewAPIKeyDialogProps {
|
||||
open: boolean
|
||||
onClose: () => void
|
||||
onCreated: (key: APIKey & {key: string}) => void
|
||||
|
||||
prefilledLabel: string
|
||||
prefilledScopes: APIKeyScope[]
|
||||
}
|
||||
|
||||
const PRESET_DAYS: number[] = [1, 7, 30, 180, 360]
|
||||
@ -57,6 +62,9 @@ const API_KEY_SCOPE_ICON_MAP: Record<string, ReactElement> = {
|
||||
alias: <FaMask />,
|
||||
report: <MdTextSnippet />,
|
||||
preferences: <GoSettings />,
|
||||
admin_cron_report: <HiDocumentReport />,
|
||||
admin_settings: <FaServer />,
|
||||
admin_reserved_alias: <BsStarFill />,
|
||||
}
|
||||
|
||||
const API_KEY_SCOPE_TYPE_ICON_MAP: Record<string, ReactElement> = {
|
||||
@ -76,12 +84,15 @@ const normalizeTime = (date: Date) =>
|
||||
|
||||
export default function CreateNewAPIKeyDialog({
|
||||
open,
|
||||
prefilledLabel,
|
||||
prefilledScopes,
|
||||
onClose,
|
||||
onCreated,
|
||||
}: CreateNewAPIKeyDialogProps): ReactElement {
|
||||
const {t} = useTranslation(["settings-api-keys", "common"])
|
||||
const serverSettings = useLoaderData() as ServerSettings
|
||||
const {showSuccess} = useErrorSuccessSnacks()
|
||||
const user = useUser()
|
||||
|
||||
const scheme = yup.object().shape({
|
||||
label: yup.string().required().label(t("create.form.label.label")),
|
||||
@ -108,9 +119,9 @@ export default function CreateNewAPIKeyDialog({
|
||||
const formik = useFormik<CreateAPIKeyData & {detail: string}>({
|
||||
validationSchema: scheme,
|
||||
initialValues: {
|
||||
label: "",
|
||||
label: prefilledLabel,
|
||||
expiresAt: addDays(new Date(), 30),
|
||||
scopes: [],
|
||||
scopes: [...prefilledScopes],
|
||||
detail: "",
|
||||
},
|
||||
onSubmit: async (values, {setErrors}) => {
|
||||
@ -121,6 +132,7 @@ export default function CreateNewAPIKeyDialog({
|
||||
}
|
||||
},
|
||||
})
|
||||
const availableScopes = [...API_KEY_SCOPES, ...(user.isAdmin ? ADMIN_API_KEY_SCOPES : [])]
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose}>
|
||||
@ -185,24 +197,20 @@ export default function CreateNewAPIKeyDialog({
|
||||
</Box>
|
||||
)}
|
||||
>
|
||||
{API_KEY_SCOPES.map(scope => (
|
||||
{availableScopes.map(scope => (
|
||||
<MenuItem key={scope} value={scope}>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<Badge
|
||||
badgeContent={
|
||||
API_KEY_SCOPE_TYPE_ICON_MAP[
|
||||
scope
|
||||
.replace(":", "_")
|
||||
.split("_")[0]
|
||||
scope.split(":")[0]
|
||||
]
|
||||
}
|
||||
>
|
||||
{
|
||||
API_KEY_SCOPE_ICON_MAP[
|
||||
scope
|
||||
.replace(":", "_")
|
||||
.split("_")[1]
|
||||
scope.split(":")[1]
|
||||
]
|
||||
}
|
||||
</Badge>
|
||||
|
@ -1,23 +1,46 @@
|
||||
import {ReactElement, useState} from "react"
|
||||
import {ReactElement, useLayoutEffect, useState} from "react"
|
||||
import {useTranslation} from "react-i18next"
|
||||
import {useQuery} from "@tanstack/react-query"
|
||||
import {APIKey, PaginationResult} from "~/server-types"
|
||||
import {APIKey, APIKeyScope, PaginationResult} from "~/server-types"
|
||||
import {AxiosError} from "axios"
|
||||
import {getAPIKeys} from "~/apis"
|
||||
import {QueryResult, SimplePage} from "~/components"
|
||||
import {Button, List} from "@mui/material"
|
||||
import {MdAdd} from "react-icons/md"
|
||||
import {useQueryParams} from "~/hooks"
|
||||
import {isArray} from "lodash"
|
||||
import {API_KEY_SCOPES} from "~/constants/values"
|
||||
import {useNavigate} from "react-router-dom"
|
||||
import APIKeyListItem from "~/route-widgets/SettingsAPIKeysRoute/APIKeyListItem"
|
||||
import CreateNewAPIKeyDialog from "../route-widgets/SettingsAPIKeysRoute/CreateNewAPIKeyDialog"
|
||||
import EmptyStateScreen from "~/route-widgets/SettingsAPIKeysRoute/EmptyStateScreen"
|
||||
|
||||
export default function SettingsAPIKeysRoute(): ReactElement {
|
||||
const {t} = useTranslation("settings-api-keys")
|
||||
const navigate = useNavigate()
|
||||
|
||||
const rawParams = useQueryParams<{action?: any; scopes?: any; label?: any}>()
|
||||
const params = {
|
||||
action: rawParams.action === "create-new" ? "create-new" : undefined,
|
||||
scopes: isArray(rawParams.scopes?.split(","))
|
||||
? rawParams.scopes
|
||||
.split(",")
|
||||
.filter((scope: APIKeyScope) => API_KEY_SCOPES.includes(scope))
|
||||
: [],
|
||||
label: rawParams.label,
|
||||
}
|
||||
|
||||
const queryKey = ["get_api_keys"]
|
||||
const query = useQuery<PaginationResult<APIKey>, AxiosError>(queryKey, () => getAPIKeys())
|
||||
|
||||
const [createdAPIKey, setCreatedAPIKey] = useState<(APIKey & {key: string}) | null>(null)
|
||||
const [createNew, setCreateNew] = useState<boolean>(false)
|
||||
const [createNew, setCreateNew] = useState<boolean>(params.action === "create-new")
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (params.action === "create-new") {
|
||||
navigate(location.pathname, {replace: true})
|
||||
}
|
||||
}, [params.action, navigate])
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -60,6 +83,8 @@ export default function SettingsAPIKeysRoute(): ReactElement {
|
||||
<CreateNewAPIKeyDialog
|
||||
key={createNew.toString()}
|
||||
open={createNew}
|
||||
prefilledScopes={params.scopes}
|
||||
prefilledLabel={params.label}
|
||||
onClose={() => setCreateNew(false)}
|
||||
onCreated={key => {
|
||||
query.refetch()
|
||||
|
@ -143,8 +143,8 @@ export interface AliasList {
|
||||
}
|
||||
|
||||
export type APIKeyScope =
|
||||
| "full_profile"
|
||||
| "basic_profile"
|
||||
| "read:profile"
|
||||
| "update:profile"
|
||||
| "read:preferences"
|
||||
| "update:preferences"
|
||||
| "read:alias"
|
||||
@ -153,6 +153,13 @@ export type APIKeyScope =
|
||||
| "delete:alias"
|
||||
| "read:report"
|
||||
| "delete:report"
|
||||
| "read:admin_cron_report"
|
||||
| "read:admin_settings"
|
||||
| "update:admin_settings"
|
||||
| "read:admin_reserved_alias"
|
||||
| "create:admin_reserved_alias"
|
||||
| "update:admin_reserved_alias"
|
||||
| "delete:admin_reserved_alias"
|
||||
|
||||
export interface APIKey {
|
||||
id: string
|
||||
|
Loading…
x
Reference in New Issue
Block a user