1 changed files with 124 additions and 0 deletions
@ -0,0 +1,124 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
const route = useRoute() |
||||
|
const id = route.params.id as string |
||||
|
|
||||
|
const { data, refresh } = await useHttpFetch(`/api/scheduler/tasks/${id}`) |
||||
|
const task = computed(() => data.value?.task) |
||||
|
const recentExecutions = computed(() => data.value?.recentExecutions ?? []) |
||||
|
|
||||
|
async function handleTrigger() { |
||||
|
await $fetch(`/api/scheduler/tasks/${id}/trigger`, { method: "POST" }) |
||||
|
} |
||||
|
|
||||
|
async function handleToggle() { |
||||
|
if (!task.value) return |
||||
|
await $fetch(`/api/scheduler/tasks/${id}/toggle`, { |
||||
|
method: "POST", |
||||
|
body: { enabled: !task.value.enabled }, |
||||
|
}) |
||||
|
refresh() |
||||
|
} |
||||
|
|
||||
|
function statusColor(status: string) { |
||||
|
switch (status) { |
||||
|
case "success": return "green" |
||||
|
case "failed": return "red" |
||||
|
case "running": return "yellow" |
||||
|
default: return "gray" |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function timeAgo(ts: number): string { |
||||
|
const diff = Date.now() - ts |
||||
|
const mins = Math.floor(diff / 60000) |
||||
|
if (mins < 1) return "just now" |
||||
|
if (mins < 60) return `${mins}m ago` |
||||
|
const hours = Math.floor(mins / 60) |
||||
|
if (hours < 24) return `${hours}h ago` |
||||
|
return `${Math.floor(hours / 24)}d ago` |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<div class="p-6 max-w-4xl mx-auto"> |
||||
|
<div class="mb-4"> |
||||
|
<ULink to="/admin/scheduler" class="text-sm text-gray-500">← Back to tasks</ULink> |
||||
|
</div> |
||||
|
|
||||
|
<div v-if="task" class="space-y-6"> |
||||
|
<!-- Task header --> |
||||
|
<div class="flex items-center justify-between"> |
||||
|
<div> |
||||
|
<h1 class="text-2xl font-bold">{{ task.name }}</h1> |
||||
|
<p class="text-sm text-gray-500 mt-1"> |
||||
|
{{ task.cronExpression }} · {{ task.type }} |
||||
|
</p> |
||||
|
</div> |
||||
|
<div class="flex gap-2"> |
||||
|
<UButton variant="outline" @click="handleTrigger">Trigger Now</UButton> |
||||
|
<UButton variant="outline" @click="handleToggle"> |
||||
|
{{ task.enabled ? 'Pause' : 'Resume' }} |
||||
|
</UButton> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- Task config --> |
||||
|
<div class="rounded-lg border p-4"> |
||||
|
<h2 class="font-semibold mb-3">Configuration</h2> |
||||
|
<dl class="grid grid-cols-2 gap-2 text-sm"> |
||||
|
<dt class="text-gray-500">Type</dt> |
||||
|
<dd>{{ task.type }}</dd> |
||||
|
<template v-if="task.type === 'function'"> |
||||
|
<dt class="text-gray-500">Function</dt> |
||||
|
<dd>{{ task.functionName }}</dd> |
||||
|
<dt class="text-gray-500">Payload</dt> |
||||
|
<dd><code>{{ task.functionPayload }}</code></dd> |
||||
|
</template> |
||||
|
<template v-if="task.type === 'http'"> |
||||
|
<dt class="text-gray-500">Method</dt> |
||||
|
<dd>{{ task.httpMethod }}</dd> |
||||
|
<dt class="text-gray-500">URL</dt> |
||||
|
<dd>{{ task.httpUrl }}</dd> |
||||
|
</template> |
||||
|
<dt class="text-gray-500">Catch Up</dt> |
||||
|
<dd>{{ task.catchUp ? 'Yes' : 'No' }}</dd> |
||||
|
<dt class="text-gray-500">Retries</dt> |
||||
|
<dd>{{ task.maxRetries }}</dd> |
||||
|
<dt class="text-gray-500">Timeout</dt> |
||||
|
<dd>{{ task.timeoutSeconds }}s</dd> |
||||
|
<dt class="text-gray-500">Created</dt> |
||||
|
<dd>{{ new Date(task.createdAt).toLocaleString() }}</dd> |
||||
|
</dl> |
||||
|
</div> |
||||
|
|
||||
|
<!-- Execution history --> |
||||
|
<div class="rounded-lg border"> |
||||
|
<h2 class="font-semibold p-4 border-b">Recent Executions</h2> |
||||
|
<div v-if="recentExecutions.length === 0" class="p-4 text-sm text-gray-400"> |
||||
|
No executions yet |
||||
|
</div> |
||||
|
<div v-else> |
||||
|
<div |
||||
|
v-for="log in recentExecutions" |
||||
|
:key="log.id" |
||||
|
class="flex items-center gap-3 p-3 border-b last:border-b-0" |
||||
|
> |
||||
|
<UBadge :color="statusColor(log.status)" variant="subtle" size="sm"> |
||||
|
{{ log.status }} |
||||
|
</UBadge> |
||||
|
<span class="text-sm text-gray-500 flex-1"> |
||||
|
{{ timeAgo(log.startedAt) }} |
||||
|
</span> |
||||
|
<span v-if="log.resultSummary" class="text-sm text-gray-600"> |
||||
|
{{ log.resultSummary }} |
||||
|
</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div v-else-if="data" class="text-gray-400"> |
||||
|
Task not found. |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
Loading…
Reference in new issue