Implement job metadata extraction and task management features. Add validation for frame range limits, enhance job and task data structures, and introduce new API endpoints for metadata and task retrieval. Update client-side components to handle metadata extraction and display task statuses. Improve error handling in API responses.

This commit is contained in:
2025-11-22 06:37:32 -06:00
parent 27a09aedd6
commit c9ade39ad9
10 changed files with 1078 additions and 88 deletions

View File

@@ -5,6 +5,7 @@ import VideoPlayer from './VideoPlayer';
export default function JobDetails({ job, onClose, onUpdate }) {
const [jobDetails, setJobDetails] = useState(job);
const [files, setFiles] = useState([]);
const [tasks, setTasks] = useState([]);
const [loading, setLoading] = useState(true);
const [videoUrl, setVideoUrl] = useState(null);
const [selectedTaskId, setSelectedTaskId] = useState(null);
@@ -42,12 +43,14 @@ export default function JobDetails({ job, onClose, onUpdate }) {
const loadDetails = async () => {
try {
const [details, fileList] = await Promise.all([
const [details, fileList, taskList] = await Promise.all([
jobs.get(job.id),
jobs.getFiles(job.id),
jobs.getTasks(job.id),
]);
setJobDetails(details);
setFiles(fileList);
setTasks(taskList);
// Check if there's an MP4 output file
const mp4File = fileList.find(
@@ -151,6 +154,16 @@ export default function JobDetails({ job, onClose, onUpdate }) {
}
};
const getTaskStatusColor = (status) => {
const colors = {
pending: 'bg-yellow-100 text-yellow-800',
running: 'bg-blue-100 text-blue-800',
completed: 'bg-green-100 text-green-800',
failed: 'bg-red-100 text-red-800',
};
return colors[status] || 'bg-gray-100 text-gray-800';
};
const outputFiles = files.filter((f) => f.file_type === 'output');
const inputFiles = files.filter((f) => f.file_type === 'input');
@@ -269,9 +282,42 @@ export default function JobDetails({ job, onClose, onUpdate }) {
<div>
<h3 className="text-lg font-semibold text-gray-900 mb-3">
Task Execution
Tasks
</h3>
<div className="space-y-4">
{tasks.length > 0 && (
<div className="bg-gray-50 rounded-lg p-4 mb-4">
<h4 className="font-medium text-gray-900 mb-2">Task List</h4>
<div className="space-y-2 max-h-64 overflow-y-auto">
{tasks.map((task) => (
<div
key={task.id}
onClick={() => handleTaskClick(task.id)}
className={`flex items-center justify-between p-3 bg-white rounded cursor-pointer hover:bg-gray-100 transition-colors ${
selectedTaskId === task.id ? 'ring-2 ring-purple-600' : ''
}`}
>
<div className="flex items-center gap-3">
<span className={`px-2 py-1 rounded text-xs font-medium ${getTaskStatusColor(task.status)}`}>
{task.status}
</span>
<span className="font-medium text-gray-900">
Frame {task.frame_start}
{task.frame_end !== task.frame_start ? `-${task.frame_end}` : ''}
</span>
{task.task_type && task.task_type !== 'render' && (
<span className="text-xs text-gray-500">({task.task_type})</span>
)}
</div>
<div className="text-sm text-gray-600">
{task.runner_id && `Runner ${task.runner_id}`}
</div>
</div>
))}
</div>
</div>
)}
{taskSteps.length > 0 && (
<div className="bg-gray-50 rounded-lg p-4">
<h4 className="font-medium text-gray-900 mb-2">Steps</h4>