feat: status dropdown on task detail page

This commit is contained in:
Gros Frumos 2026-03-15 18:17:57 +02:00
parent 9cbb3cec37
commit 6e872121eb
4 changed files with 102 additions and 0 deletions

View file

@ -6,6 +6,16 @@ async function get<T>(path: string): Promise<T> {
return res.json()
}
async function patch<T>(path: string, body: unknown): Promise<T> {
const res = await fetch(`${BASE}${path}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
})
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`)
return res.json()
}
async function post<T>(path: string, body: unknown): Promise<T> {
const res = await fetch(`${BASE}${path}`, {
method: 'POST',
@ -148,4 +158,6 @@ export const api = {
post<AuditResult>(`/projects/${projectId}/audit`, {}),
auditApply: (projectId: string, taskIds: string[]) =>
post<{ updated: string[]; count: number }>(`/projects/${projectId}/audit/apply`, { task_ids: taskIds }),
patchTask: (id: string, data: { status: string }) =>
patch<Task>(`/tasks/${id}`, data),
}

View file

@ -185,6 +185,21 @@ async function runPipeline() {
const hasSteps = computed(() => (task.value?.pipeline_steps?.length ?? 0) > 0)
const isRunning = computed(() => task.value?.status === 'in_progress')
const statusChanging = ref(false)
async function changeStatus(newStatus: string) {
if (!task.value || newStatus === task.value.status) return
statusChanging.value = true
try {
const updated = await api.patchTask(props.id, { status: newStatus })
task.value = { ...task.value, ...updated }
} catch (e: any) {
error.value = e.message
} finally {
statusChanging.value = false
}
}
</script>
<template>
@ -202,6 +217,18 @@ const isRunning = computed(() => task.value?.status === 'in_progress')
<h1 class="text-xl font-bold text-gray-100">{{ task.id }}</h1>
<span class="text-gray-400">{{ task.title }}</span>
<Badge :text="task.status" :color="statusColor(task.status)" />
<select
:value="task.status"
@change="changeStatus(($event.target as HTMLSelectElement).value)"
:disabled="statusChanging"
class="text-xs bg-gray-800 border border-gray-700 text-gray-300 rounded px-2 py-0.5 disabled:opacity-50"
>
<option value="pending">pending</option>
<option value="in_progress">in_progress</option>
<option value="review">review</option>
<option value="done">done</option>
<option value="blocked">blocked</option>
</select>
<span v-if="isRunning" class="inline-block w-2 h-2 bg-blue-500 rounded-full animate-pulse"></span>
<span class="text-xs text-gray-600">pri {{ task.priority }}</span>
</div>