certificate display
This commit is contained in:
63
ui/src/components/certificate/CertificateDetail.tsx
Normal file
63
ui/src/components/certificate/CertificateDetail.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import { Sheet, SheetContent, SheetHeader, SheetTitle } from "../ui/sheet";
|
||||
|
||||
import { Certificate } from "@/domain/certificate";
|
||||
import { Textarea } from "../ui/textarea";
|
||||
import { Button } from "../ui/button";
|
||||
import { Label } from "../ui/label";
|
||||
import { CustomFile, saveFiles2ZIP } from "@/lib/file";
|
||||
|
||||
type WorkflowLogDetailProps = {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
certificate?: Certificate;
|
||||
};
|
||||
const CertificateDetail = ({ open, onOpenChange, certificate }: WorkflowLogDetailProps) => {
|
||||
const handleDownloadClick = async () => {
|
||||
const zipName = `${certificate?.id}-${certificate?.san}.zip`;
|
||||
const files: CustomFile[] = [
|
||||
{
|
||||
name: `${certificate?.san}.pem`,
|
||||
content: certificate?.certificate ? certificate?.certificate : "",
|
||||
},
|
||||
{
|
||||
name: `${certificate?.san}.key`,
|
||||
content: certificate?.privateKey ? certificate?.privateKey : "",
|
||||
},
|
||||
];
|
||||
|
||||
await saveFiles2ZIP(zipName, files);
|
||||
};
|
||||
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={onOpenChange}>
|
||||
<SheetContent className="sm:max-w-2xl">
|
||||
<SheetHeader>
|
||||
<SheetTitle></SheetTitle>
|
||||
</SheetHeader>
|
||||
|
||||
<div className="flex flex-col space-y-5 mt-9">
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
size={"sm"}
|
||||
onClick={() => {
|
||||
handleDownloadClick();
|
||||
}}
|
||||
>
|
||||
下载证书
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-col space-y-3">
|
||||
<Label>证书</Label>
|
||||
<Textarea value={certificate?.certificate} rows={10} readOnly={true} />
|
||||
</div>
|
||||
<div className="flex flex-col space-y-3">
|
||||
<Label>密钥</Label>
|
||||
<Textarea value={certificate?.privateKey} rows={10} readOnly={true} />
|
||||
</div>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
};
|
||||
|
||||
export default CertificateDetail;
|
||||
@@ -31,7 +31,7 @@ const WorkflowLog = () => {
|
||||
const succeed: boolean = row.getValue("succeed");
|
||||
if (succeed) {
|
||||
return (
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex items-center space-x-2 min-w-[150px]">
|
||||
<div className="text-white bg-green-500 w-8 h-8 rounded-full flex items-center justify-center">
|
||||
<Check size={18} />
|
||||
</div>
|
||||
@@ -40,7 +40,7 @@ const WorkflowLog = () => {
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex items-center space-x-2 min-w-[150px]">
|
||||
<div className="text-white bg-red-500 w-8 h-8 rounded-full flex items-center justify-center">
|
||||
<X size={18} />
|
||||
</div>
|
||||
@@ -58,7 +58,7 @@ const WorkflowLog = () => {
|
||||
if (!error) {
|
||||
error = "";
|
||||
}
|
||||
return <div className="min-w-[250px] truncate">{error}</div>;
|
||||
return <div className="max-w-[300px] truncate text-red-500">{error}</div>;
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -89,4 +89,3 @@ const WorkflowLog = () => {
|
||||
};
|
||||
|
||||
export default WorkflowLog;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { WorkflowOutput, WorkflowRunLog, WorkflowRunLogItem } from "@/domain/workflow";
|
||||
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "../ui/sheet";
|
||||
import { Sheet, SheetContent, SheetHeader, SheetTitle } from "../ui/sheet";
|
||||
import { Check, X } from "lucide-react";
|
||||
import { ScrollArea } from "../ui/scroll-area";
|
||||
|
||||
type WorkflowLogDetailProps = {
|
||||
open: boolean;
|
||||
@@ -18,7 +19,7 @@ const WorkflowLogDetail = ({ open, onOpenChange, log }: WorkflowLogDetailProps)
|
||||
<div className="flex flex-col">
|
||||
{log?.succeed ? (
|
||||
<div className="mt-5 flex justify-between bg-green-100 p-5 rounded-md items-center">
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="flex space-x-2 items-center min-w-[150px]">
|
||||
<div className="w-8 h-8 bg-green-500 flex items-center justify-center rounded-full text-white">
|
||||
<Check size={18} />
|
||||
</div>
|
||||
@@ -28,49 +29,51 @@ const WorkflowLogDetail = ({ open, onOpenChange, log }: WorkflowLogDetailProps)
|
||||
<div className="text-muted-foreground">{new Date(log.created).toLocaleString()}</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-5 flex justify-between bg-green-100 p-5 rounded-md items-center">
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="mt-5 flex justify-between bg-red-100 p-5 rounded-md items-center">
|
||||
<div className="flex space-x-2 items-center min-w-[150px]">
|
||||
<div className="w-8 h-8 bg-red-500 flex items-center justify-center rounded-full text-white">
|
||||
<X size={18} />
|
||||
</div>
|
||||
<div className="text-stone-700">失败</div>
|
||||
</div>
|
||||
|
||||
<div className="text-red-500">{log?.error}</div>
|
||||
<div className="text-red-500 max-w-[400px] truncate">{log?.error}</div>
|
||||
|
||||
<div className="text-muted-foreground">{log?.created && new Date(log.created).toLocaleString()}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="bg-black p-5 mt-5 rounded-md text-stone-200 flex flex-col space-y-3">
|
||||
{log?.log.map((item: WorkflowRunLogItem, i) => {
|
||||
return (
|
||||
<div key={i} className="flex flex-col space-y-2">
|
||||
<div className="">{item.nodeName}</div>
|
||||
<div className="flex flex-col space-y-1">
|
||||
{item.outputs.map((output: WorkflowOutput) => {
|
||||
return (
|
||||
<>
|
||||
<div className="flex text-sm space-x-2">
|
||||
<div>[{output.time}]</div>
|
||||
{output.error ? (
|
||||
<>
|
||||
<div className="text-red-500">{output.error}</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div>{output.content}</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
})}
|
||||
<ScrollArea className="h-[80vh] mt-5 bg-black p-5 rounded-md">
|
||||
<div className=" text-stone-200 flex flex-col space-y-3">
|
||||
{log?.log.map((item: WorkflowRunLogItem, i) => {
|
||||
return (
|
||||
<div key={i} className="flex flex-col space-y-2">
|
||||
<div className="">{item.nodeName}</div>
|
||||
<div className="flex flex-col space-y-1">
|
||||
{item.outputs.map((output: WorkflowOutput) => {
|
||||
return (
|
||||
<>
|
||||
<div className="flex text-sm space-x-2">
|
||||
<div>[{output.time}]</div>
|
||||
{output.error ? (
|
||||
<>
|
||||
<div className="text-red-500 max-w-[70%]">{output.error}</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div>{output.content}</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
@@ -78,4 +81,3 @@ const WorkflowLogDetail = ({ open, onOpenChange, log }: WorkflowLogDetailProps)
|
||||
};
|
||||
|
||||
export default WorkflowLogDetail;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user