Files
TaskPool/web/src/pages/Scripts.tsx
T
admin 2f76060c39
Build-Deploy-Server / build (base, debian, ) (push) Failing after 7s
Build-Docker-ARM64 / build (base, debian, ) (push) Failing after 11s
Build-Docker-ARM64 / build (base-debian13, debian13, -debian13) (push) Failing after 11s
Build-Docker-ARM64 / build (base-minimal, minimal, -minimal) (push) Failing after 10s
Deploy VitePress to Pages / build (push) Has been cancelled
Deploy VitePress to Pages / Deploy (push) Has been cancelled
feat: complete all page components
- Dashboard: system stats with cards
- Tasks: task management table with filters
- Scripts: script management grid
- Logs: execution log viewer
- Interconnect: node management
- Terminal: xterm.js integration
- Settings: theme and site config
- Login: authentication page
2026-07-19 18:47:35 +00:00

167 lines
5.1 KiB
TypeScript

import { useScripts, useDeleteScript } from '@/api/hooks'
import { Plus, Trash2, FileCode, RefreshCw } from 'lucide-react'
import type { Script } from '@/api/types'
export default function Scripts() {
const { data: scripts, isLoading, refetch } = useScripts()
const deleteScript = useDeleteScript()
const handleDelete = async (id: number) => {
if (confirm('Delete this script?')) {
await deleteScript.mutateAsync(id)
}
}
if (isLoading) {
return <div style={{ color: 'var(--text-muted)', padding: 20 }}>Loading...</div>
}
return (
<div>
{/* Header */}
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 24 }}>
<h1 style={{ fontSize: 24, fontWeight: 600 }}>Scripts</h1>
<div style={{ display: 'flex', gap: 8 }}>
<button
onClick={() => refetch()}
style={{
display: 'flex',
alignItems: 'center',
gap: 6,
padding: '8px 12px',
background: 'var(--bg-secondary)',
border: '1px solid var(--border)',
borderRadius: 6,
color: 'var(--text-secondary)',
cursor: 'pointer',
fontSize: 13,
}}
>
<RefreshCw size={14} strokeWidth={1.5} />
Refresh
</button>
<button
style={{
display: 'flex',
alignItems: 'center',
gap: 6,
padding: '8px 12px',
background: 'var(--bg-accent)',
border: 'none',
borderRadius: 6,
color: 'white',
cursor: 'pointer',
fontSize: 13,
}}
>
<Plus size={14} strokeWidth={1.5} />
Add Script
</button>
</div>
</div>
{/* Grid */}
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', gap: 16 }}>
{scripts?.map(script => (
<ScriptCard key={script.id} script={script} onDelete={() => handleDelete(script.id)} />
))}
{(!scripts || scripts.length === 0) && (
<div style={{
gridColumn: '1 / -1',
padding: 48,
textAlign: 'center',
color: 'var(--text-muted)',
background: 'var(--bg-secondary)',
border: '1px solid var(--border)',
borderRadius: 8,
}}>
No scripts found
</div>
)}
</div>
</div>
)
}
function ScriptCard({ script, onDelete }: { script: Script; onDelete: () => void }) {
const formatDate = (date: string) => {
return new Date(date).toLocaleDateString()
}
const getLanguageColor = (lang: string) => {
const colors: Record<string, string> = {
python: '#3776ab',
javascript: '#f7df1e',
typescript: '#3178c6',
go: '#00add8',
bash: '#4eaa25',
shell: '#4eaa25',
}
return colors[lang?.toLowerCase()] || '#6b7280'
}
return (
<div style={{
background: 'var(--bg-secondary)',
border: '1px solid var(--border)',
borderRadius: 8,
padding: 16,
transition: 'border-color 0.15s',
}}>
<div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 12 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<div style={{
width: 40,
height: 40,
borderRadius: 6,
background: `${getLanguageColor(script.language)}15`,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}>
<FileCode size={20} strokeWidth={1.5} style={{ color: getLanguageColor(script.language) }} />
</div>
<div>
<div style={{ fontWeight: 500, marginBottom: 2 }}>{script.name}</div>
<div style={{ fontSize: 12, color: 'var(--text-muted)', fontFamily: 'monospace' }}>{script.filename}</div>
</div>
</div>
<button
onClick={onDelete}
title="Delete"
style={{
width: 28,
height: 28,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: 'transparent',
border: 'none',
borderRadius: 4,
color: 'var(--text-secondary)',
cursor: 'pointer',
}}
>
<Trash2 size={14} strokeWidth={1.5} />
</button>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
<span style={{
padding: '4px 8px',
background: `${getLanguageColor(script.language)}15`,
borderRadius: 4,
fontSize: 11,
color: getLanguageColor(script.language),
fontWeight: 500,
}}>
{script.language || 'Unknown'}
</span>
</div>
<div style={{ fontSize: 12, color: 'var(--text-muted)' }}>
Updated: {formatDate(script.updated_at)}
</div>
</div>
)
}