import { type LoaderFunctionArgs, type ActionFunctionArgs, } from "@remix-run/server-runtime"; import { Plus, Copy } from "lucide-react"; import { Button } from "~/components/ui"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, } from "~/components/ui/dialog"; import { useFetcher } from "@remix-run/react"; import { Input } from "~/components/ui/input"; import { useState } from "react"; import { parse } from "@conform-to/zod"; import { json } from "@remix-run/node"; import { z } from "zod"; import { createPersonalAccessToken, getValidPersonalAccessTokens, revokePersonalAccessToken, } from "~/services/personalAccessToken.server"; import { requireUserId } from "~/services/session.server"; import { useTypedLoaderData } from "remix-typedjson"; import { APITable } from "~/components/api"; export const APIKeyBodyRequest = z.object({ name: z.string(), }); export const APIKeyDeleteBodyRequest = z.object({ id: z.string(), }); export async function action({ request }: ActionFunctionArgs) { const userId = await requireUserId(request); if (request.method === "DELETE") { const formData = await request.formData(); const submission = parse(formData, { schema: APIKeyDeleteBodyRequest, }); if (!submission.value || submission.intent !== "submit") { return json(submission); } const results = await revokePersonalAccessToken(submission.value.id); return json(results); } const formData = await request.formData(); const submission = parse(formData, { schema: APIKeyBodyRequest, }); if (!submission.value || submission.intent !== "submit") { return json(submission); } const results = await createPersonalAccessToken({ name: submission.value.name, userId, }); return json(results); } export async function loader({ request }: LoaderFunctionArgs) { const userId = await requireUserId(request); const personalAccessTokens = await getValidPersonalAccessTokens(userId); return personalAccessTokens; } export default function API() { const personalAccessTokens = useTypedLoaderData(); const [open, setOpen] = useState(false); const [showToken, setShowToken] = useState(false); const fetcher = useFetcher<{ token: string }>(); const isSubmitting = fetcher.state !== "idle"; const [name, setName] = useState(""); const onSubmit = async (event: React.FormEvent) => { fetcher.submit({ name }, { method: "POST", action: "/settings/api" }); setOpen(false); setShowToken(true); }; const copyToClipboard = (text: string | undefined) => { text && navigator.clipboard.writeText(text); }; return (

API Keys

Create and manage API keys to access your data programmatically. API keys allow secure access to your workspace's data and functionality through our REST API.

Create API Key
setName(e.target.value)} name="name" placeholder="Enter API key name" className="mt-1" required />
Your New API Key

Make sure to copy your API key now. You won't be able to see it again!

{fetcher.data?.token}
); }