| 1 |
"use client"; |
| 2 |
|
| 3 |
import React, { useState, useEffect } from "react"; |
| 4 |
import { X, RefreshCw } from "lucide-react"; |
| 5 |
import { Button } from "./ui/Button"; |
| 6 |
|
| 7 |
const LogsModal = ({ isOpen, onClose, workflowId }) => { |
| 8 |
const [logs, setLogs] = useState([]); |
| 9 |
const [loading, setLoading] = useState(false); |
| 10 |
|
| 11 |
const fetchLogs = async () => { |
| 12 |
setLoading(true); |
| 13 |
try { |
| 14 |
let url = `${window.wpbotAutomator.apiUrl}/logs`; |
| 15 |
if (workflowId) { |
| 16 |
url += `?workflow_id=${workflowId}`; |
| 17 |
} |
| 18 |
|
| 19 |
const response = await fetch(url, { |
| 20 |
headers: { |
| 21 |
"X-WP-Nonce": window.wpbotAutomator.nonce, |
| 22 |
}, |
| 23 |
}); |
| 24 |
const data = await response.json(); |
| 25 |
setLogs(data.logs || (Array.isArray(data) ? data : [])); |
| 26 |
} catch (error) { |
| 27 |
console.error("Error fetching logs:", error); |
| 28 |
} finally { |
| 29 |
setLoading(false); |
| 30 |
} |
| 31 |
}; |
| 32 |
|
| 33 |
useEffect(() => { |
| 34 |
if (isOpen) { |
| 35 |
fetchLogs(); |
| 36 |
} |
| 37 |
}, [isOpen]); |
| 38 |
|
| 39 |
if (!isOpen) return null; |
| 40 |
|
| 41 |
return ( |
| 42 |
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50"> |
| 43 |
<div className="bg-background w-full max-w-4xl h-[80vh] rounded-lg shadow-lg flex flex-col font-sans"> |
| 44 |
<div className="flex items-center justify-between p-4 border-b border-border"> |
| 45 |
<h2 className="text-lg font-semibold">Execution Logs</h2> |
| 46 |
<div className="flex items-center gap-2"> |
| 47 |
<Button variant="outline" size="sm" onClick={fetchLogs} disabled={loading}> |
| 48 |
<RefreshCw className={`h-4 w-4 mr-2 ${loading ? "animate-spin" : ""}`} /> |
| 49 |
Refresh |
| 50 |
</Button> |
| 51 |
<Button variant="ghost" size="icon" onClick={onClose}> |
| 52 |
<X className="h-4 w-4" /> |
| 53 |
</Button> |
| 54 |
</div> |
| 55 |
</div> |
| 56 |
|
| 57 |
<div className="flex-1 overflow-auto p-4"> |
| 58 |
<table className="w-full text-sm text-left"> |
| 59 |
<thead className="bg-muted/50 text-muted-foreground uppercase text-xs"> |
| 60 |
<tr> |
| 61 |
<th className="px-4 py-2 w-48">Date</th> |
| 62 |
<th className="px-4 py-2">Workflow</th> |
| 63 |
<th className="px-4 py-2 w-32">Type</th> |
| 64 |
<th className="px-4 py-2 w-24">Status</th> |
| 65 |
<th className="px-4 py-2">Message</th> |
| 66 |
</tr> |
| 67 |
</thead> |
| 68 |
<tbody className="divide-y divide-border"> |
| 69 |
{logs.length === 0 ? ( |
| 70 |
<tr> |
| 71 |
<td colSpan="5" className="px-4 py-8 text-center text-muted-foreground"> |
| 72 |
{loading ? "Loading logs..." : "No logs found."} |
| 73 |
</td> |
| 74 |
</tr> |
| 75 |
) : ( |
| 76 |
logs.map((log) => ( |
| 77 |
<tr key={log.id} className="hover:bg-muted/10"> |
| 78 |
<td className="px-4 py-2 text-muted-foreground font-mono text-xs"> |
| 79 |
{log.created_at} |
| 80 |
</td> |
| 81 |
<td className="px-4 py-2 font-medium"> |
| 82 |
{log.workflow_name || `Workflow #${log.workflow_id}`} |
| 83 |
</td> |
| 84 |
<td className="px-4 py-2"> |
| 85 |
{log.trigger_type} |
| 86 |
</td> |
| 87 |
<td className="px-4 py-2"> |
| 88 |
<span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${ |
| 89 |
log.status === 'success' ? 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400' : 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400' |
| 90 |
}`}> |
| 91 |
{log.status} |
| 92 |
</span> |
| 93 |
</td> |
| 94 |
<td className="px-4 py-2 text-muted-foreground"> |
| 95 |
{log.error_message || log.log_data || "-"} |
| 96 |
</td> |
| 97 |
</tr> |
| 98 |
)) |
| 99 |
)} |
| 100 |
</tbody> |
| 101 |
</table> |
| 102 |
</div> |
| 103 |
</div> |
| 104 |
</div> |
| 105 |
); |
| 106 |
}; |
| 107 |
|
| 108 |
export default LogsModal; |
| 109 |
|