diff --git a/apps/dashboard/src/components/dashboard-account-settings/api-keys/api-keys-page.tsx b/apps/dashboard/src/components/dashboard-account-settings/api-keys/api-keys-page.tsx new file mode 100644 index 000000000..f3de2fac1 --- /dev/null +++ b/apps/dashboard/src/components/dashboard-account-settings/api-keys/api-keys-page.tsx @@ -0,0 +1,158 @@ +'use client'; + +import { Button } from "@/components/ui/button"; +import { useState } from "react"; +import { CreateApiKeyDialog, ShowApiKeyDialog } from "../supporting/api-key-dialogs"; +import { ApiKeyTable } from "../supporting/api-key-table"; +import { useUser } from "@stackframe/stack"; +import { ApiKey, ApiKeyCreationOptions } from "../supporting/types"; +import { PageLayout } from "../page-layout"; + +export function ApiKeysPage({ + mockApiKeys, + mockMode, +}: { + mockApiKeys?: Array<{ + id: string, + description: string, + createdAt: string, + expiresAt?: string, + manuallyRevokedAt?: string, + }>, + mockMode?: boolean, +} = {}) { + const isInMockMode = !!(mockApiKeys || mockMode); + const user = useUser({ or: isInMockMode ? 'return-null' : 'redirect' }); + + if (isInMockMode) { + return ; + } + + if (!user) { + return null; + } + + return ; +} + +function ApiKeysPageInner({ + user, + mockApiKeys, + mockMode, +}: { + user: any; + mockApiKeys?: any[]; + mockMode: boolean; +}) { + const mockApiKeysData = mockApiKeys ? mockApiKeys.map(mockKey => ({ + id: mockKey.id, + description: mockKey.description, + createdAt: new Date(mockKey.createdAt), + expiresAt: mockKey.expiresAt ? new Date(mockKey.expiresAt) : undefined, + manuallyRevokedAt: mockKey.manuallyRevokedAt ? new Date(mockKey.manuallyRevokedAt) : null, + value: { + lastFour: mockKey.id.slice(-4).padStart(4, '0'), + }, + type: 'user' as const, + userId: 'mock-user-id', + update: async () => {}, + revoke: async () => {}, + isValid: () => { + const now = new Date(); + const isExpired = mockKey.expiresAt ? new Date(mockKey.expiresAt) < now : false; + const isRevoked = !!mockKey.manuallyRevokedAt; + return !isExpired && !isRevoked; + }, + whyInvalid: () => { + const now = new Date(); + if (mockKey.manuallyRevokedAt) return 'manually-revoked'; + if (mockKey.expiresAt && new Date(mockKey.expiresAt) < now) return 'expired'; + return null; + }, + })) : [ + { + id: 'key-1', + description: 'Development Key', + createdAt: new Date(Date.now() - 172800000), + expiresAt: undefined, + manuallyRevokedAt: null, + value: { + lastFour: 'ey-1'.slice(-4).padStart(4, '0'), + }, + type: 'user' as const, + userId: 'mock-user-id', + update: async () => {}, + revoke: async () => {}, + isValid: () => true, + whyInvalid: () => null, + } + ]; + + const apiKeys = mockMode ? mockApiKeysData : user.useApiKeys(); + + const [isNewApiKeyDialogOpen, setIsNewApiKeyDialogOpen] = useState(false); + const [returnedApiKey, setReturnedApiKey] = useState | null>(null); + + const CreateDialog = CreateApiKeyDialog<"user">; + const ShowDialog = ShowApiKeyDialog<"user">; + + const handleCreateApiKey = async (data: ApiKeyCreationOptions<"user">) => { + if (mockMode) { + const mockApiKey = { + id: `key-${Date.now()}`, + description: data.description, + createdAt: new Date().toISOString(), + expiresAt: data.expiresAt?.toISOString(), + value: 'sk_dev_mock_key_' + Math.random().toString(36).substring(2), + update: async () => {}, + revoke: async () => {}, + isValid: () => true, + whyInvalid: () => null, + type: 'user' as const, + userId: 'mock-user-id', + }; + return mockApiKey as any; + } + + return await user.createApiKey(data as any); + }; + + return ( + + + + + + User API Keys + + + Create and manage API keys to authenticate your user actions from scripts or backend environments. + + + setIsNewApiKeyDialogOpen(true)} + className="bg-black text-white hover:bg-zinc-800 dark:bg-white dark:text-black dark:hover:bg-zinc-200 rounded-xl px-4 py-2 w-full md:w-auto transition-colors duration-150" + > + Create API Key + + + + + + + + + + setReturnedApiKey(null)} + /> + + ); +}
+ Create and manage API keys to authenticate your user actions from scripts or backend environments. +