backup worked

This commit is contained in:
2025-12-30 22:02:51 +03:00
parent fce0941e98
commit a747a163c8
22 changed files with 768 additions and 191 deletions

View File

@@ -22,6 +22,12 @@
>
Migration
</a>
<a
href="/tasks"
class="text-gray-600 hover:text-blue-600 font-medium {$page.url.pathname.startsWith('/tasks') ? 'text-blue-600 border-b-2 border-blue-600' : ''}"
>
Tasks
</a>
<a
href="/settings"
class="text-gray-600 hover:text-blue-600 font-medium {$page.url.pathname === '/settings' ? 'text-blue-600 border-b-2 border-blue-600' : ''}"

View File

@@ -0,0 +1,94 @@
<!-- [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';
export let tasks: Array<any> = [];
export let loading: boolean = false;
const dispatch = createEventDispatcher();
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';
}
}
function formatTime(dateStr: string | null) {
if (!dateStr) return 'N/A';
try {
return formatDistanceToNow(new Date(dateStr), { addSuffix: true });
} catch (e) {
return 'Invalid date';
}
}
function handleTaskClick(taskId: string) {
dispatch('select', { id: taskId });
}
</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">Loading tasks...</div>
{:else if tasks.length === 0}
<div class="p-4 text-center text-gray-500">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>
Started {formatTime(task.started_at)}
</p>
</div>
</div>
</div>
</button>
</li>
{/each}
</ul>
{/if}
</div>
<!-- [/DEF:TaskList] -->