'use client' import React, { useState, useEffect } from 'react' import { Button } from '@payloadcms/ui' interface WorkflowRun { id: string status: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled' startedAt: string completedAt?: string error?: string triggeredBy: string } interface WorkflowExecutionStatusProps { workflowId: string | number } export const WorkflowExecutionStatus: React.FC = ({ workflowId }) => { const [runs, setRuns] = useState([]) const [loading, setLoading] = useState(true) const [expanded, setExpanded] = useState(false) useEffect(() => { const fetchRecentRuns = async () => { try { const response = await fetch(`/api/workflow-runs?where[workflow][equals]=${workflowId}&limit=5&sort=-startedAt`) if (response.ok) { const data = await response.json() setRuns(data.docs || []) } } catch (error) { console.warn('Failed to fetch workflow runs:', error) } finally { setLoading(false) } } fetchRecentRuns() }, [workflowId]) if (loading) { return (
Loading execution history...
) } if (runs.length === 0) { return (
📋 No execution history yet
This workflow hasn't been triggered yet.
) } const getStatusIcon = (status: string) => { switch (status) { case 'pending': return 'âŗ' case 'running': return '🔄' case 'completed': return '✅' case 'failed': return '❌' case 'cancelled': return 'âšī¸' default: return '❓' } } const getStatusColor = (status: string) => { switch (status) { case 'pending': return '#6B7280' case 'running': return '#3B82F6' case 'completed': return '#10B981' case 'failed': return '#EF4444' case 'cancelled': return '#F59E0B' default: return '#6B7280' } } const formatDate = (dateString: string) => { const date = new Date(dateString) const now = new Date() const diffMs = now.getTime() - date.getTime() if (diffMs < 60000) { // Less than 1 minute return 'Just now' } else if (diffMs < 3600000) { // Less than 1 hour return `${Math.floor(diffMs / 60000)} min ago` } else if (diffMs < 86400000) { // Less than 1 day return `${Math.floor(diffMs / 3600000)} hrs ago` } else { return date.toLocaleDateString() } } const getDuration = (startedAt: string, completedAt?: string) => { const start = new Date(startedAt) const end = completedAt ? new Date(completedAt) : new Date() const diffMs = end.getTime() - start.getTime() if (diffMs < 1000) return '<1s' if (diffMs < 60000) return `${Math.floor(diffMs / 1000)}s` if (diffMs < 3600000) return `${Math.floor(diffMs / 60000)}m ${Math.floor((diffMs % 60000) / 1000)}s` return `${Math.floor(diffMs / 3600000)}h ${Math.floor((diffMs % 3600000) / 60000)}m` } const recentRun = runs[0] const recentStatus = getStatusIcon(recentRun.status) const recentColor = getStatusColor(recentRun.status) return (
{/* Summary Header */}
{recentStatus}
Last run: {recentRun.status}
{formatDate(recentRun.startedAt)} â€ĸ Duration: {getDuration(recentRun.startedAt, recentRun.completedAt)}
{/* Detailed History */} {expanded && (

Recent Executions

{runs.map((run, index) => (
{getStatusIcon(run.status)}
{run.status.charAt(0).toUpperCase() + run.status.slice(1)}
{formatDate(run.startedAt)} â€ĸ {run.triggeredBy}
{getDuration(run.startedAt, run.completedAt)}
{run.error && (
Error
)}
))}
)}
) }