This commit is contained in:
Philipinho
2025-10-07 19:56:21 +01:00
parent 3882faec72
commit f6f11cde52
7 changed files with 69 additions and 27 deletions

View File

@ -554,5 +554,6 @@
"Select expiration date": "Select expiration date",
"This action cannot be undone. Any applications using this API key will stop working.": "This action cannot be undone. Any applications using this API key will stop working.",
"Token name": "Token name",
"Update API key": "Update API key"
"Update API key": "Update API key",
"Manage API keys for all users in the workspace": "Manage API keys for all users in the workspace"
}

View File

@ -31,9 +31,8 @@ export function ApiKeyCreatedModal({
<Modal
opened={opened}
onClose={onClose}
title={t("API ley created")}
title={t("API key created")}
size="lg"
closeOnClickOutside={false}
>
<Stack gap="md">
<Alert
@ -64,17 +63,6 @@ export function ApiKeyCreatedModal({
</Group>
</div>
<div>
<Text size="sm">
{t("Token name")}: {apiKey.name}
</Text>
{apiKey.expiresAt && (
<Text size="sm">
{t("Expires")}: {new Date(apiKey.expiresAt).toLocaleString()}
</Text>
)}
</div>
<Button fullWidth onClick={onClose} mt="md">
{t("I've saved my API key")}
</Button>

View File

@ -22,7 +22,7 @@ interface CreateApiKeyModalProps {
const formSchema = z.object({
name: z.string().min(1, "Name is required"),
expiresAt: z.date().nullable().optional(),
expiresAt: z.string().optional(),
});
type FormValues = z.infer<typeof formSchema>;
@ -39,7 +39,7 @@ export function CreateApiKeyModal({
validate: zodResolver(formSchema),
initialValues: {
name: "",
expiresAt: null as Date | null,
expiresAt: "",
},
});
@ -48,7 +48,7 @@ export function CreateApiKeyModal({
return undefined;
}
if (expirationOption === "custom") {
return form.values.expiresAt?.toISOString();
return form.values.expiresAt;
}
const days = parseInt(expirationOption);
const date = new Date();
@ -113,6 +113,7 @@ export function CreateApiKeyModal({
<TextInput
label={t("Name")}
placeholder={t("Enter a descriptive name")}
data-autofocus
required
{...form.getInputProps("name")}
/>

View File

@ -18,9 +18,9 @@ export function RevokeApiKeyModal({
const { t } = useTranslation();
const revokeApiKeyMutation = useRevokeApiKeyMutation();
const handleRevoke = () => {
const handleRevoke = async () => {
if (!apiKey) return;
revokeApiKeyMutation.mutate({
await revokeApiKeyMutation.mutateAsync({
apiKeyId: apiKey.id,
});
onClose();

View File

@ -5,6 +5,7 @@ import { z } from "zod";
import { useTranslation } from "react-i18next";
import { useUpdateApiKeyMutation } from "@/ee/api-key/queries/api-key-query";
import { IApiKey } from "@/ee/api-key";
import { useEffect } from "react";
const formSchema = z.object({
name: z.string().min(1, "Name is required"),
@ -28,22 +29,24 @@ export function UpdateApiKeyModal({
const form = useForm<FormValues>({
validate: zodResolver(formSchema),
initialValues: {
name: apiKey?.name,
name: "",
},
});
useEffect(() => {
if (opened && apiKey) {
form.setValues({ name: apiKey.name });
}
}, [opened, apiKey]);
const handleSubmit = async (data: { name?: string }) => {
const apiKeyData = {
apiKeyId: apiKey.id,
name: data.name,
};
try {
await updateApiKeyMutation.mutateAsync(apiKeyData);
onClose();
} catch (err) {
//
}
await updateApiKeyMutation.mutateAsync(apiKeyData);
onClose();
};
return (

View File

@ -1,10 +1,13 @@
import React, { useState } from "react";
import { Space } from "@mantine/core";
import { Button, Group, Space, Text } from "@mantine/core";
import { Helmet } from "react-helmet-async";
import { useTranslation } from "react-i18next";
import SettingsTitle from "@/components/settings/settings-title";
import { getAppName } from "@/lib/config";
import { ApiKeyTable } from "@/ee/api-key/components/api-key-table";
import { CreateApiKeyModal } from "@/ee/api-key/components/create-api-key-modal";
import { ApiKeyCreatedModal } from "@/ee/api-key/components/api-key-created-modal";
import { UpdateApiKeyModal } from "@/ee/api-key/components/update-api-key-modal";
import { RevokeApiKeyModal } from "@/ee/api-key/components/revoke-api-key-modal";
import Paginate from "@/components/common/paginate";
import { usePaginateAndSearch } from "@/hooks/use-paginate-and-search";
@ -15,6 +18,9 @@ import useUserRole from '@/hooks/use-user-role.tsx';
export default function WorkspaceApiKeys() {
const { t } = useTranslation();
const { page, setPage } = usePaginateAndSearch();
const [createModalOpened, setCreateModalOpened] = useState(false);
const [createdApiKey, setCreatedApiKey] = useState<IApiKey | null>(null);
const [updateModalOpened, setUpdateModalOpened] = useState(false);
const [revokeModalOpened, setRevokeModalOpened] = useState(false);
const [selectedApiKey, setSelectedApiKey] = useState<IApiKey | null>(null);
const { data, isLoading } = useGetApiKeysQuery({ page, adminView: true });
@ -24,6 +30,15 @@ export default function WorkspaceApiKeys() {
return null;
}
const handleCreateSuccess = (response: IApiKey) => {
setCreatedApiKey(response);
};
const handleUpdate = (apiKey: IApiKey) => {
setSelectedApiKey(apiKey);
setUpdateModalOpened(true);
};
const handleRevoke = (apiKey: IApiKey) => {
setSelectedApiKey(apiKey);
setRevokeModalOpened(true);
@ -39,10 +54,21 @@ export default function WorkspaceApiKeys() {
<SettingsTitle title={t("API management")} />
<Text size="md" c="dimmed" mb="md">
{t("Manage API keys for all users in the workspace")}
</Text>
<Group justify="flex-end" mb="md">
<Button onClick={() => setCreateModalOpened(true)}>
{t("Create API Key")}
</Button>
</Group>
<ApiKeyTable
apiKeys={data?.items}
isLoading={isLoading}
showUserColumn
onUpdate={handleUpdate}
onRevoke={handleRevoke}
/>
@ -57,6 +83,27 @@ export default function WorkspaceApiKeys() {
/>
)}
<CreateApiKeyModal
opened={createModalOpened}
onClose={() => setCreateModalOpened(false)}
onSuccess={handleCreateSuccess}
/>
<ApiKeyCreatedModal
opened={!!createdApiKey}
onClose={() => setCreatedApiKey(null)}
apiKey={createdApiKey}
/>
<UpdateApiKeyModal
opened={updateModalOpened}
onClose={() => {
setUpdateModalOpened(false);
setSelectedApiKey(null);
}}
apiKey={selectedApiKey}
/>
<RevokeApiKeyModal
opened={revokeModalOpened}
onClose={() => {

View File

@ -24,6 +24,8 @@ export function useGetApiKeysQuery(
return useQuery({
queryKey: ["api-key-list", params],
queryFn: () => getApiKeys(params),
staleTime: 0,
gcTime: 0,
placeholderData: keepPreviousData,
});
}