Files
ss-tools/frontend/src/routes/dashboards/[id]/components/DashboardTaskHistory.svelte
busya f07cc433b0 refactor(dashboards): extract dashboard detail components
Split the large dashboard detail page into smaller, focused components: DashboardHeader, DashboardGitManager, DashboardLinkedResources, and DashboardTaskHistory to improve maintainability.
2026-04-21 08:36:48 +03:00

105 lines
4.2 KiB
Svelte

<!-- [DEF:DashboardTaskHistory:Component] -->
<script>
/**
* @COMPLEXITY: 2
* @PURPOSE: Block for recent tasks table.
* @LAYER: UI
*/
import { t } from "$lib/i18n";
let {
isTaskHistoryLoading,
taskHistoryError,
taskHistory,
loadTaskHistory,
getValidationStatus,
toTaskTypeLabel,
getTaskStatusClasses,
getValidationStatusClasses,
formatDate,
openLlmReport
} = $props();
</script>
<div class="rounded-xl border border-slate-200 bg-white p-4">
<div class="mb-3 flex items-center justify-between">
<h2 class="text-sm font-semibold uppercase tracking-wide text-slate-500">
{$t.tasks?.recent || "Recent tasks"}
</h2>
<button
class="rounded-md border border-slate-300 px-2 py-1 text-xs text-slate-700 hover:bg-slate-50"
onclick={loadTaskHistory}
disabled={isTaskHistoryLoading}
>
{$t.common?.refresh || "Refresh"}
</button>
</div>
{#if isTaskHistoryLoading}
<div class="space-y-2">
{#each Array(4) as _}
<div class="h-10 animate-pulse rounded bg-slate-100"></div>
{/each}
</div>
{:else if taskHistoryError}
<div class="rounded-lg border border-rose-200 bg-rose-50 px-3 py-2 text-sm text-rose-700">
{taskHistoryError}
</div>
{:else if taskHistory.length === 0}
<div class="rounded-lg border border-slate-200 bg-slate-50 px-3 py-6 text-center text-sm text-slate-500">
{$t.tasks?.select_task || "No backup/LLM tasks yet"}
</div>
{:else}
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-slate-200 text-sm">
<thead class="bg-slate-50">
<tr>
<th class="px-3 py-2 text-left font-semibold text-slate-600">{$t.common?.type || "Type"}</th>
<th class="px-3 py-2 text-left font-semibold text-slate-600">{$t.common?.status || "Status"}</th>
<th class="px-3 py-2 text-left font-semibold text-slate-600">{$t.tasks?.result || "Check"}</th>
<th class="px-3 py-2 text-left font-semibold text-slate-600">{$t.common?.started || "Started"}</th>
<th class="px-3 py-2 text-left font-semibold text-slate-600">{$t.common?.finished || "Finished"}</th>
<th class="px-3 py-2 text-left font-semibold text-slate-600">{$t.common?.actions || "Actions"}</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100">
{#each taskHistory as task}
{@const validation = getValidationStatus(task)}
<tr>
<td class="px-3 py-2 text-slate-800">{toTaskTypeLabel(task.plugin_id)}</td>
<td class="px-3 py-2">
<span class={`rounded-full px-2 py-1 text-xs font-semibold uppercase ${getTaskStatusClasses(task.status)}`}>
{task.status}
</span>
</td>
<td class="px-3 py-2">
<span class={`inline-flex items-center gap-1 rounded-full border px-2 py-1 text-xs font-semibold uppercase ${getValidationStatusClasses(validation.level)}`}>
{#if validation.icon}
<span class="inline-flex min-w-[18px] items-center justify-center rounded-full bg-white/70 px-1 text-[10px] font-bold">
{validation.icon}
</span>
{/if}
{validation.label}
</span>
</td>
<td class="px-3 py-2 text-slate-700">{formatDate(task.started_at)}</td>
<td class="px-3 py-2 text-slate-700">{formatDate(task.finished_at)}</td>
<td class="px-3 py-2">
<div class="flex flex-wrap items-center gap-1">
{#if task.plugin_id === "llm_dashboard_validation"}
<button
class="inline-flex items-center gap-1 rounded-md border border-indigo-300 bg-indigo-50 px-2 py-1 text-xs text-indigo-700 hover:bg-indigo-100"
onclick={() => openLlmReport(task.id)}
>
{$t.tasks?.open_llm_report || "LLM report"}
</button>
{/if}
</div>
</td>
</tr>
{/each}
</tbody>
</table>
</div>
{/if}
</div>
<!-- [/DEF:DashboardTaskHistory:Component] -->