'use client' import type { Environment } from '@dify/contracts/enterprise/types.gen' import type { ButtonProps } from '@langgenius/dify-ui/button' import type { FormEvent, ReactNode } from 'react' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { Dialog, DialogCloseButton, DialogContent, DialogDescription, DialogTitle, } from '@langgenius/dify-ui/dialog' import { Input } from '@langgenius/dify-ui/input' import { Select, SelectContent, SelectItem, SelectItemIndicator, SelectItemText, SelectLabel, SelectTrigger, } from '@langgenius/dify-ui/select' import { toast } from '@langgenius/dify-ui/toast' import { useMutation } from '@tanstack/react-query' import { useAtomValue } from 'jotai' import { useEffect, useId, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { consoleQuery } from '@/service/client' import { deploymentRouteAppInstanceIdAtom } from '../../../route-state' import { generateApiTokenName } from './api-token-name' export function ApiKeyGenerateMenu({ environments, onCreatedToken, triggerVariant = 'secondary', triggerClassName, children, }: { environments: Environment[] onCreatedToken: (token: string) => void triggerVariant?: ButtonProps['variant'] triggerClassName?: string children?: (props: { trigger: ReactNode }) => ReactNode }) { const { t } = useTranslation('deployments') const appInstanceId = useAtomValue(deploymentRouteAppInstanceIdAtom) const nameInputId = useId() const nameInputRef = useRef(null) const [createDialogOpen, setCreateDialogOpen] = useState(false) const [selectedEnvironmentId, setSelectedEnvironmentId] = useState() const [draftName, setDraftName] = useState('') const [nameError, setNameError] = useState(false) const generateApiKey = useMutation(consoleQuery.enterprise.accessService.createApiKey.mutationOptions()) const selectableEnvironments = environments const selectedEnvironment = selectedEnvironmentId ? selectableEnvironments.find(env => env.id === selectedEnvironmentId) : undefined const disabled = !appInstanceId || selectableEnvironments.length === 0 const isCreating = generateApiKey.isPending useEffect(() => { if (createDialogOpen) nameInputRef.current?.focus() }, [createDialogOpen]) function handleOpenCreateDialog() { const firstEnvironment = selectableEnvironments[0] if (!firstEnvironment) return setSelectedEnvironmentId(firstEnvironment.id) setDraftName(generateApiTokenName()) setNameError(false) setCreateDialogOpen(true) } function handleEnvironmentChange(environmentId: string) { setSelectedEnvironmentId(environmentId) setNameError(false) } function handleDraftNameChange(nextDraftName: string) { setDraftName(nextDraftName) if (nameError && nextDraftName.trim()) setNameError(false) } function resetCreateDialog() { setCreateDialogOpen(false) setSelectedEnvironmentId(undefined) setDraftName('') setNameError(false) } function handleDialogOpenChange(nextOpen: boolean) { if (nextOpen || isCreating) return resetCreateDialog() } function handleGenerateApiKey(event: FormEvent) { event.preventDefault() const name = draftName.trim() if (!appInstanceId || !selectedEnvironmentId || !name) { setNameError(true) return } generateApiKey.mutate( { params: { appInstanceId, environmentId: selectedEnvironmentId, }, body: { appInstanceId, environmentId: selectedEnvironmentId, displayName: name, }, }, { onSuccess: (response) => { if (response.token) onCreatedToken(response.token) resetCreateDialog() }, onError: () => { toast.error(t('access.api.createFailed')) }, }, ) } const trigger = ( ) return ( <> {children ? children({ trigger }) : trigger}
{t('access.api.createKeyTitle')} {t('access.api.description')}
{ handleDraftNameChange(event.target.value) }} /> {nameError && (
{t('access.api.nameRequired')}
)}
) }