123 lines
4.1 KiB
TypeScript
123 lines
4.1 KiB
TypeScript
'use client'
|
|
|
|
import { useState, useEffect } from 'react'
|
|
|
|
interface HistoryEntry {
|
|
id: string
|
|
task: string
|
|
command: string
|
|
project: string
|
|
action: string
|
|
createdAt: string
|
|
status: string
|
|
reply?: string
|
|
}
|
|
|
|
const projects = ['all', 'sitemente', 'holacompi', 'arabredox', 'infrastructure', 'trading']
|
|
|
|
export function TaskHistoryPanel() {
|
|
const [history, setHistory] = useState<HistoryEntry[]>([])
|
|
const [loading, setLoading] = useState(true)
|
|
const [selectedProject, setSelectedProject] = useState<string>('all')
|
|
|
|
useEffect(() => {
|
|
loadHistory()
|
|
}, [selectedProject])
|
|
|
|
const loadHistory = async () => {
|
|
setLoading(true)
|
|
try {
|
|
const url = selectedProject === 'all'
|
|
? '/api/command-history'
|
|
: `/api/command-history?project=${selectedProject}`
|
|
const response = await fetch(url)
|
|
if (response.ok) {
|
|
const data = await response.json()
|
|
setHistory(data.history || [])
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to load history:', error)
|
|
}
|
|
setLoading(false)
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
{/* Project Filter Tabs */}
|
|
<div className="flex gap-2 flex-wrap">
|
|
{projects.map(project => (
|
|
<button
|
|
key={project}
|
|
onClick={() => setSelectedProject(project)}
|
|
className={`px-4 py-2 rounded-lg text-sm font-medium transition ${
|
|
selectedProject === project
|
|
? 'bg-brand-pink text-white'
|
|
: 'bg-white/10 text-white/70 hover:bg-white/20'
|
|
}`}
|
|
>
|
|
{project === 'all' ? 'All Projects' : project.charAt(0).toUpperCase() + project.slice(1)}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{/* History List */}
|
|
<div className="border border-white/20 rounded-lg p-4 bg-white/5">
|
|
<h3 className="text-lg font-bold mb-4 flex items-center gap-2">
|
|
📜 TASK HISTORY
|
|
<span className="text-sm font-normal text-white/50">({history.length} entries)</span>
|
|
</h3>
|
|
|
|
{loading ? (
|
|
<p className="text-white/50 text-center py-8">Loading...</p>
|
|
) : history.length === 0 ? (
|
|
<p className="text-white/50 text-center py-8">
|
|
No history for this project.
|
|
</p>
|
|
) : (
|
|
<div className="space-y-4 max-h-[500px] overflow-y-auto">
|
|
{history.slice().reverse().map((entry) => (
|
|
<div
|
|
key={entry.id}
|
|
className="p-4 rounded-lg bg-white/5 border border-white/10"
|
|
>
|
|
<div className="flex items-start justify-between mb-2">
|
|
<div>
|
|
<p className="font-medium text-brand-pink">{entry.task}</p>
|
|
<p className="text-xs text-white/40">
|
|
{new Date(entry.createdAt).toLocaleString()}
|
|
</p>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<span className="px-2 py-1 rounded text-xs bg-white/10 text-white/70">
|
|
{entry.project}
|
|
</span>
|
|
<span className={`px-2 py-1 rounded text-xs ${
|
|
entry.status === 'completed'
|
|
? 'bg-green-500/20 text-green-400'
|
|
: 'bg-white/10 text-white/50'
|
|
}`}>
|
|
{entry.status}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-3 p-3 rounded bg-black/30 border border-white/10">
|
|
<p className="text-xs text-white/50 mb-1">You sent:</p>
|
|
<p className="text-sm">{entry.command}</p>
|
|
</div>
|
|
|
|
{entry.reply && (
|
|
<div className="mt-2 p-3 rounded bg-brand-pink/10 border border-brand-pink/30">
|
|
<p className="text-xs text-brand-pink mb-1">Horus replied:</p>
|
|
<p className="text-sm text-white/90">{entry.reply}</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|