feat(PBI-59): SprintSubTasksPane component voor jobs-pagina
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
fa4192a28a
commit
6b64869cf3
1 changed files with 67 additions and 0 deletions
67
components/jobs/sprint-sub-tasks-pane.tsx
Normal file
67
components/jobs/sprint-sub-tasks-pane.tsx
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
'use client'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { JOB_STATUS_LABELS, JOB_STATUS_COLORS } from '@/components/shared/job-status'
|
||||
import type { ClaudeJobStatusApi } from '@/lib/job-status'
|
||||
|
||||
type SubTask = {
|
||||
id: string
|
||||
taskCode: string | null
|
||||
taskTitle: string
|
||||
status: string
|
||||
}
|
||||
|
||||
interface SprintSubTasksPaneProps {
|
||||
jobId: string | null
|
||||
isSprintJob: boolean
|
||||
}
|
||||
|
||||
function SubTaskList({ jobId }: { jobId: string }) {
|
||||
const [subTasks, setSubTasks] = useState<SubTask[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController()
|
||||
|
||||
fetch(`/api/jobs/${jobId}/sub-tasks`, { signal: controller.signal })
|
||||
.then(res => res.json())
|
||||
.then((data: SubTask[]) => {
|
||||
setSubTasks(data)
|
||||
setLoading(false)
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
|
||||
return () => controller.abort()
|
||||
}, [jobId])
|
||||
|
||||
if (loading) {
|
||||
return <div className="text-xs text-muted-foreground p-3">Laden…</div>
|
||||
}
|
||||
|
||||
if (subTasks.length === 0) return null
|
||||
|
||||
return (
|
||||
<div className="border-b p-2 space-y-1 max-h-44 overflow-y-auto shrink-0">
|
||||
{subTasks.map(t => {
|
||||
const apiStatus = t.status.toLowerCase() as ClaudeJobStatusApi
|
||||
return (
|
||||
<div key={t.id} className="flex items-center gap-2 py-1 px-2 rounded hover:bg-surface-container text-sm">
|
||||
<span className="text-xs font-mono text-muted-foreground w-16 shrink-0 truncate">{t.taskCode}</span>
|
||||
<span className="flex-1 truncate">{t.taskTitle}</span>
|
||||
<span className={cn('text-xs px-1.5 py-0.5 rounded-full border', JOB_STATUS_COLORS[apiStatus])}>
|
||||
{JOB_STATUS_LABELS[apiStatus] ?? t.status}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function SprintSubTasksPane({ jobId, isSprintJob }: SprintSubTasksPaneProps) {
|
||||
if (!isSprintJob || !jobId) return null
|
||||
return <SubTaskList key={jobId} jobId={jobId} />
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue