101 lines
4.3 KiB
TypeScript
101 lines
4.3 KiB
TypeScript
import type { DeidentifyTask } from '../DeidentifyPanel';
|
|
import { TABLE_HEADERS, getStatusBadgeClass } from '../DeidentifyPanel';
|
|
import { ProgressBar } from './ProgressBar';
|
|
|
|
interface TaskTableProps {
|
|
rows: DeidentifyTask[];
|
|
loading: boolean;
|
|
onAction: (action: string, task: DeidentifyTask) => void;
|
|
}
|
|
|
|
export function TaskTable({ rows, loading, onAction }: TaskTableProps) {
|
|
return (
|
|
<div className="overflow-auto">
|
|
<table className="w-full text-caption border-collapse">
|
|
<thead>
|
|
<tr className="bg-bg-elevated text-t3 uppercase tracking-wide">
|
|
{TABLE_HEADERS.map((h) => (
|
|
<th
|
|
key={h}
|
|
className="px-3 py-2 text-left font-medium border-b border-stroke whitespace-nowrap"
|
|
>
|
|
{h}
|
|
</th>
|
|
))}
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{loading && rows.length === 0
|
|
? Array.from({ length: 5 }).map((_, i) => (
|
|
<tr key={i} className="border-b border-stroke animate-pulse">
|
|
{TABLE_HEADERS.map((_, j) => (
|
|
<td key={j} className="px-3 py-2">
|
|
<div className="h-3 bg-bg-elevated rounded w-14" />
|
|
</td>
|
|
))}
|
|
</tr>
|
|
))
|
|
: rows.map((row) => (
|
|
<tr key={row.id} className="border-b border-stroke hover:bg-bg-surface/50">
|
|
<td className="px-3 py-2 text-t3 font-mono">{row.id}</td>
|
|
<td className="px-3 py-2 font-medium text-t1 whitespace-nowrap">{row.name}</td>
|
|
<td
|
|
className="px-3 py-2 text-t2 whitespace-nowrap max-w-[240px] truncate"
|
|
title={row.target}
|
|
>
|
|
{row.target}
|
|
</td>
|
|
<td className="px-3 py-2">
|
|
<span
|
|
className={`inline-block px-2 py-0.5 rounded text-label-2 font-medium ${getStatusBadgeClass(row.status)}`}
|
|
>
|
|
{row.status}
|
|
</span>
|
|
</td>
|
|
<td className="px-3 py-2 text-t2 whitespace-nowrap">{row.startTime}</td>
|
|
<td className="px-3 py-2 min-w-[120px]">
|
|
<ProgressBar value={row.progress} />
|
|
</td>
|
|
<td className="px-3 py-2 text-t2">{row.createdBy}</td>
|
|
<td className="px-3 py-2">
|
|
<div className="flex items-center gap-1 flex-wrap">
|
|
<button
|
|
onClick={() => onAction('detail', row)}
|
|
className="px-2 py-0.5 text-label-2 rounded bg-bg-elevated hover:bg-bg-card text-t2 transition-colors whitespace-nowrap"
|
|
>
|
|
상세보기
|
|
</button>
|
|
<button
|
|
onClick={() => onAction('download', row)}
|
|
className="px-2 py-0.5 text-label-2 rounded bg-bg-elevated hover:bg-bg-card text-t2 transition-colors whitespace-nowrap"
|
|
>
|
|
결과다운로드
|
|
</button>
|
|
<button
|
|
onClick={() => onAction('retry', row)}
|
|
className="px-2 py-0.5 text-label-2 rounded bg-bg-elevated hover:bg-bg-card text-t2 transition-colors whitespace-nowrap"
|
|
>
|
|
재실행
|
|
</button>
|
|
<button
|
|
onClick={() => onAction('delete', row)}
|
|
className="px-2 py-0.5 text-label-2 rounded bg-bg-elevated hover:bg-bg-card text-color-danger transition-colors whitespace-nowrap"
|
|
>
|
|
삭제
|
|
</button>
|
|
<button
|
|
onClick={() => onAction('audit', row)}
|
|
className="px-2 py-0.5 text-label-2 rounded bg-bg-elevated hover:bg-bg-card text-t2 transition-colors whitespace-nowrap"
|
|
>
|
|
감사로그
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
);
|
|
}
|