mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-09 09:06:36 +08:00
feat: 添加证书PEM和私钥PEM复制功能,优化证书详情模态框
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { EmptyState } from '@/components/feedback/empty-state';
|
import { EmptyState } from '@/components/feedback/empty-state';
|
||||||
import { ErrorState } from '@/components/feedback/error-state';
|
import { ErrorState } from '@/components/feedback/error-state';
|
||||||
|
import { InlineMessage } from '@/components/feedback/inline-message';
|
||||||
import { LoadingState } from '@/components/feedback/loading-state';
|
import { LoadingState } from '@/components/feedback/loading-state';
|
||||||
import { AppModal } from '@/components/ui/app-modal';
|
import { AppModal } from '@/components/ui/app-modal';
|
||||||
import { StatusBadge } from '@/components/ui/status-badge';
|
import { StatusBadge } from '@/components/ui/status-badge';
|
||||||
@@ -37,6 +39,8 @@ export function CertificateDetailModal({
|
|||||||
onDelete,
|
onDelete,
|
||||||
deleting = false,
|
deleting = false,
|
||||||
}: CertificateDetailModalProps) {
|
}: CertificateDetailModalProps) {
|
||||||
|
const [copyMessage, setCopyMessage] = useState<string | null>(null);
|
||||||
|
|
||||||
const certificateQuery = useQuery({
|
const certificateQuery = useQuery({
|
||||||
queryKey: ['tls-certificates', 'detail', certificateId],
|
queryKey: ['tls-certificates', 'detail', certificateId],
|
||||||
queryFn: () => getTlsCertificate(certificateId as number),
|
queryFn: () => getTlsCertificate(certificateId as number),
|
||||||
@@ -53,10 +57,22 @@ export function CertificateDetailModal({
|
|||||||
const content = contentQuery.data;
|
const content = contentQuery.data;
|
||||||
const status = certificate ? getCertificateStatus(certificate) : null;
|
const status = certificate ? getCertificateStatus(certificate) : null;
|
||||||
|
|
||||||
|
const handleCopy = async (value: string, message: string) => {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(value);
|
||||||
|
setCopyMessage(message);
|
||||||
|
} catch (error) {
|
||||||
|
setCopyMessage(getErrorMessage(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppModal
|
<AppModal
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onClose={onClose}
|
onClose={() => {
|
||||||
|
setCopyMessage(null);
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
title="证书详情"
|
title="证书详情"
|
||||||
description="查看证书元信息、备注以及当前保存的 PEM 内容。"
|
description="查看证书元信息、备注以及当前保存的 PEM 内容。"
|
||||||
size="xl"
|
size="xl"
|
||||||
@@ -82,6 +98,10 @@ export function CertificateDetailModal({
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
{copyMessage ? (
|
||||||
|
<InlineMessage tone="success" message={copyMessage} />
|
||||||
|
) : null}
|
||||||
|
|
||||||
{certificateQuery.isLoading || contentQuery.isLoading ? (
|
{certificateQuery.isLoading || contentQuery.isLoading ? (
|
||||||
<LoadingState />
|
<LoadingState />
|
||||||
) : certificateQuery.isError || contentQuery.isError ? (
|
) : certificateQuery.isError || contentQuery.isError ? (
|
||||||
@@ -146,17 +166,39 @@ export function CertificateDetailModal({
|
|||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<p className="mb-2 text-sm font-medium text-[var(--foreground-primary)]">
|
<div className="mb-2 flex items-center justify-between gap-3">
|
||||||
证书 PEM
|
<p className="text-sm font-medium text-[var(--foreground-primary)]">
|
||||||
</p>
|
证书 PEM
|
||||||
|
</p>
|
||||||
|
<SecondaryButton
|
||||||
|
type="button"
|
||||||
|
className="px-3 py-2 text-xs"
|
||||||
|
onClick={() =>
|
||||||
|
void handleCopy(content.cert_pem, '证书 PEM 已复制。')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
复制
|
||||||
|
</SecondaryButton>
|
||||||
|
</div>
|
||||||
<CodeBlock className="max-h-56 overflow-y-auto whitespace-pre-wrap break-all">
|
<CodeBlock className="max-h-56 overflow-y-auto whitespace-pre-wrap break-all">
|
||||||
{content.cert_pem}
|
{content.cert_pem}
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="mb-2 text-sm font-medium text-[var(--foreground-primary)]">
|
<div className="mb-2 flex items-center justify-between gap-3">
|
||||||
私钥 PEM
|
<p className="text-sm font-medium text-[var(--foreground-primary)]">
|
||||||
</p>
|
私钥 PEM
|
||||||
|
</p>
|
||||||
|
<SecondaryButton
|
||||||
|
type="button"
|
||||||
|
className="px-3 py-2 text-xs"
|
||||||
|
onClick={() =>
|
||||||
|
void handleCopy(content.key_pem, '私钥 PEM 已复制。')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
复制
|
||||||
|
</SecondaryButton>
|
||||||
|
</div>
|
||||||
<CodeBlock className="max-h-56 overflow-y-auto whitespace-pre-wrap break-all">
|
<CodeBlock className="max-h-56 overflow-y-auto whitespace-pre-wrap break-all">
|
||||||
{content.key_pem}
|
{content.key_pem}
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
|
|||||||
Reference in New Issue
Block a user