'use client'; import { zodResolver } from '@hookform/resolvers/zod'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { Loader2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { EmptyStateWithBorder } from '@/components/layout/empty'; import { ErrorInline } from '@/components/layout/error'; import { LoadingStateWithBorder } from '@/components/layout/loading'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import type { TlsCertificateItem } from '@/lib/services/openflare'; import { TlsCertificateService } from '@/lib/services/openflare'; import { defaultManualImportValues, type ManualImportFormValues, manualImportSchema, } from './schemas'; import { getErrorMessage, toManualPayload } from './website-utils'; const certificatesQueryKey = ['openflare', 'tls-certificates']; interface CertificateEditorDialogProps { certificateId: number | null; open: boolean; onOpenChange: (open: boolean) => void; onSaved?: (certificate: TlsCertificateItem) => void; onConvert?: (certificate: TlsCertificateItem) => void; } export function CertificateEditorDialog({ certificateId, open, onOpenChange, onSaved, onConvert, }: CertificateEditorDialogProps) { const queryClient = useQueryClient(); const form = useForm({ resolver: zodResolver(manualImportSchema), defaultValues: defaultManualImportValues, }); const certificateQuery = useQuery({ queryKey: ['openflare', 'tls-certificates', 'content', certificateId], queryFn: () => TlsCertificateService.getContent(certificateId as number), enabled: open && certificateId !== null, }); const updateMutation = useMutation({ mutationFn: (values: ManualImportFormValues) => TlsCertificateService.update( certificateId as number, toManualPayload(values), ), onSuccess: async (certificate) => { await Promise.all([ queryClient.invalidateQueries({ queryKey: certificatesQueryKey }), ]); onSaved?.(certificate); handleClose(); }, }); useEffect(() => { if (!open || !certificateQuery.data) return; form.reset({ name: certificateQuery.data.name, cert_pem: certificateQuery.data.cert_pem, key_pem: certificateQuery.data.key_pem, remark: certificateQuery.data.remark || '', }); }, [certificateQuery.data, form, open]); const handleSubmit = form.handleSubmit((values) => { updateMutation.mutate(values); }); const handleClose = () => { updateMutation.reset(); form.reset(defaultManualImportValues); onOpenChange(false); }; const canConvert = certificateQuery.data?.provider === 'upload' && certificateQuery.data.apply_status !== 'applying'; return ( !next && handleClose()}> 编辑证书 可以修改证书名称、备注,以及重新上传 PEM 证书和私钥内容。 {certificateQuery.isLoading ? ( ) : certificateQuery.isError ? ( ) : !certificateQuery.data ? ( ) : (
{updateMutation.isError ? (

{getErrorMessage(updateMutation.error)}

) : null}