110 lines
4.3 KiB
Svelte
110 lines
4.3 KiB
Svelte
<!-- [DEF:TaskList:Component] -->
|
|
<!--
|
|
@SEMANTICS: tasks, list, status, history
|
|
@PURPOSE: Displays a list of tasks with their status and execution details.
|
|
@LAYER: Component
|
|
@RELATION: USES -> api.js
|
|
-->
|
|
|
|
<script lang="ts">
|
|
import { createEventDispatcher } from 'svelte';
|
|
import { formatDistanceToNow } from 'date-fns';
|
|
import { t } from '../lib/i18n';
|
|
|
|
export let tasks: Array<any> = [];
|
|
export let loading: boolean = false;
|
|
|
|
const dispatch = createEventDispatcher();
|
|
|
|
// [DEF:getStatusColor:Function]
|
|
// @PURPOSE: Returns the CSS color class for a given task status.
|
|
// @PRE: status string is provided.
|
|
// @POST: Returns tailwind color class string.
|
|
function getStatusColor(status: string) {
|
|
switch (status) {
|
|
case 'SUCCESS': return 'bg-green-100 text-green-800';
|
|
case 'FAILED': return 'bg-red-100 text-red-800';
|
|
case 'RUNNING': return 'bg-blue-100 text-blue-800 animate-pulse';
|
|
case 'PENDING': return 'bg-gray-100 text-gray-800';
|
|
case 'AWAITING_INPUT':
|
|
case 'AWAITING_MAPPING': return 'bg-yellow-100 text-yellow-800';
|
|
default: return 'bg-gray-100 text-gray-800';
|
|
}
|
|
}
|
|
// [/DEF:getStatusColor:Function]
|
|
|
|
// [DEF:formatTime:Function]
|
|
// @PURPOSE: Formats a date string using date-fns.
|
|
// @PRE: dateStr is a valid date string or null.
|
|
// @POST: Returns human-readable relative time string.
|
|
function formatTime(dateStr: string | null) {
|
|
if (!dateStr) return 'N/A';
|
|
try {
|
|
return formatDistanceToNow(new Date(dateStr), { addSuffix: true });
|
|
} catch (e) {
|
|
return 'Invalid date';
|
|
}
|
|
}
|
|
// [/DEF:formatTime:Function]
|
|
|
|
// [DEF:handleTaskClick:Function]
|
|
// @PURPOSE: Dispatches a select event when a task is clicked.
|
|
// @PRE: taskId is provided.
|
|
// @POST: 'select' event is dispatched with task ID.
|
|
function handleTaskClick(taskId: string) {
|
|
dispatch('select', { id: taskId });
|
|
}
|
|
// [/DEF:handleTaskClick:Function]
|
|
</script>
|
|
|
|
<div class="bg-white shadow overflow-hidden sm:rounded-md">
|
|
{#if loading && tasks.length === 0}
|
|
<div class="p-4 text-center text-gray-500">{$t.tasks?.loading || 'Loading...'}</div>
|
|
{:else if tasks.length === 0}
|
|
<div class="p-4 text-center text-gray-500">{$t.tasks?.no_tasks || 'No tasks found.'}</div>
|
|
{:else}
|
|
<ul class="divide-y divide-gray-200">
|
|
{#each tasks as task (task.id)}
|
|
<li>
|
|
<button
|
|
class="block hover:bg-gray-50 w-full text-left transition duration-150 ease-in-out focus:outline-none"
|
|
on:click={() => handleTaskClick(task.id)}
|
|
>
|
|
<div class="px-4 py-4 sm:px-6">
|
|
<div class="flex items-center justify-between">
|
|
<div class="text-sm font-medium text-blue-600 truncate">
|
|
{task.plugin_id.toUpperCase()}
|
|
<span class="ml-2 text-xs text-gray-400 font-mono">{task.id.substring(0, 8)}</span>
|
|
</div>
|
|
<div class="ml-2 flex-shrink-0 flex">
|
|
<p class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full {getStatusColor(task.status)}">
|
|
{task.status}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="mt-2 sm:flex sm:justify-between">
|
|
<div class="sm:flex">
|
|
<p class="flex items-center text-sm text-gray-500">
|
|
{#if task.params?.environment_id || task.params?.source_env_id}
|
|
<span class="mr-2">Env: {task.params.environment_id || task.params.source_env_id}</span>
|
|
{/if}
|
|
</p>
|
|
</div>
|
|
<div class="mt-2 flex items-center text-sm text-gray-500 sm:mt-0">
|
|
<svg class="flex-shrink-0 mr-1.5 h-5 w-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clip-rule="evenodd" />
|
|
</svg>
|
|
<p>
|
|
{($t.tasks?.started || "").replace('{time}', formatTime(task.started_at))}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</button>
|
|
</li>
|
|
{/each}
|
|
</ul>
|
|
{/if}
|
|
</div>
|
|
|
|
<!-- [/DEF:TaskList:Component] --> |