Parallel Job View in Queue

This commit is contained in:
Manish Tanwar 2025-10-10 21:45:57 +05:30
parent 7c972e8cd8
commit ab5fd32287
7 changed files with 114 additions and 48 deletions

View file

@ -108,8 +108,8 @@ const QueueManager = ({ userEmail }) => {
return job.progress || 0;
};
const isActiveJob = (job) => {
const activeStatuses = [
const isProcessingJob = (job) => {
const processingStatuses = [
JOB_STATUS.STARTING,
JOB_STATUS.UPLOADING_IMAGE,
JOB_STATUS.GENERATING,
@ -119,15 +119,32 @@ const QueueManager = ({ userEmail }) => {
'retry_2_of_3',
'retry_3_of_3'
];
return activeStatuses.includes(job.status) || job.status.startsWith('retry_');
return processingStatuses.includes(job.status) || job.status.startsWith('retry_');
};
const getMostRecentActiveJob = () => {
return jobs.find(job => isActiveJob(job));
const isQueuedJob = (job) => {
return job.status === JOB_STATUS.QUEUED;
};
const isHistoricalJob = (job) => {
return job.status === JOB_STATUS.COMPLETED ||
job.status === JOB_STATUS.FAILED ||
job.status === JOB_STATUS.CANCELLED;
};
const getProcessingJobs = () => {
return jobs.filter(job => isProcessingJob(job))
.sort((a, b) => new Date(a.created_at) - new Date(b.created_at)); // FIFO order
};
const getQueuedJobs = () => {
return jobs.filter(job => isQueuedJob(job))
.sort((a, b) => new Date(a.created_at) - new Date(b.created_at)); // FIFO order
};
const getHistoricalJobs = () => {
return jobs.filter(job => !isActiveJob(job));
return jobs.filter(job => isHistoricalJob(job))
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); // Most recent first
};
const renderDownloadButtons = (job) => {
@ -170,19 +187,28 @@ const QueueManager = ({ userEmail }) => {
return <Box sx={{ mt: 1 }}>{buttons}</Box>;
};
const renderJobItem = (job, isActive = false) => {
const renderJobItem = (job, jobType = 'history', queuePosition = null) => {
const isProcessing = jobType === 'processing';
const isQueued = jobType === 'queued';
return (
<ListItem
sx={{
flexDirection: 'column',
alignItems: 'stretch',
py: 2,
...(isActive && {
...(isProcessing && {
border: '2px solid',
borderColor: 'primary.main',
borderRadius: 2,
backgroundColor: 'primary.50',
mb: 2
}),
...(isQueued && {
border: '1px solid',
borderColor: 'warning.main',
borderRadius: 2,
backgroundColor: 'warning.50',
mb: 1
})
}}
>
@ -197,9 +223,10 @@ const QueueManager = ({ userEmail }) => {
color={getStatusColor(job.status)}
size="small"
/>
{job.status === JOB_STATUS.QUEUED && job.queue_position > 0 && (
{isQueued && queuePosition && (
<Chip
label={`Position: ${job.queue_position}`}
label={`Queue Position: ${queuePosition}`}
color="warning"
variant="outlined"
size="small"
/>
@ -229,26 +256,40 @@ const QueueManager = ({ userEmail }) => {
{job.message || 'Processing...'}
</Typography>
{/* Enhanced Progress Bar for Active Jobs */}
{/* Progress Bar */}
<LinearProgress
variant="determinate"
value={getProgressValue(job)}
variant={isQueued ? "indeterminate" : "determinate"}
value={isQueued ? 0 : getProgressValue(job)}
sx={{
mb: 1,
...(isActive && {
...(isProcessing && {
height: 8,
borderRadius: 4,
backgroundColor: 'rgba(25, 118, 210, 0.1)'
}),
...(isQueued && {
height: 4,
borderRadius: 2,
backgroundColor: 'rgba(237, 108, 2, 0.1)',
'& .MuiLinearProgress-bar': {
backgroundColor: 'warning.main'
}
})
}}
/>
{isActive && (
{isProcessing && (
<Typography variant="caption" color="primary.main" sx={{ mb: 1, fontWeight: 'bold' }}>
{getProgressValue(job)}% complete
</Typography>
)}
{isQueued && (
<Typography variant="caption" color="warning.main" sx={{ mb: 1, fontWeight: 'bold' }}>
Waiting in queue...
</Typography>
)}
{/* Download Buttons */}
{renderDownloadButtons(job)}
@ -359,47 +400,72 @@ const QueueManager = ({ userEmail }) => {
</Typography>
) : (
<>
{/* Active Job Section */}
{getMostRecentActiveJob() && (
{/* Processing Jobs Section */}
{getProcessingJobs().length > 0 && (
<>
<Typography variant="h6" sx={{ mb: 2, color: 'primary.main' }}>
Current Video Generation
<Typography variant="h6" sx={{ mb: 2, color: 'primary.main', display: 'flex', alignItems: 'center', gap: 1 }}>
<PlayArrowRounded />
Currently Processing ({getProcessingJobs().length})
</Typography>
<List>
{renderJobItem(getMostRecentActiveJob(), true)}
{getProcessingJobs().map((job, index) => (
<React.Fragment key={job.job_id}>
{renderJobItem(job, 'processing')}
{index < getProcessingJobs().length - 1 && <Divider sx={{ my: 1 }} />}
</React.Fragment>
))}
</List>
</>
)}
{/* Queued Jobs Section */}
{getQueuedJobs().length > 0 && (
<>
{getProcessingJobs().length > 0 && <Divider sx={{ my: 3, borderWidth: 1 }} />}
<Typography variant="h6" sx={{ mb: 2, color: 'warning.main', display: 'flex', alignItems: 'center', gap: 1 }}>
<HourglassEmptyRounded />
In Queue ({getQueuedJobs().length})
</Typography>
<List>
{getQueuedJobs().map((job, index) => (
<React.Fragment key={job.job_id}>
{renderJobItem(job, 'queued', index + 1)}
{index < getQueuedJobs().length - 1 && <Divider sx={{ my: 1 }} />}
</React.Fragment>
))}
</List>
{getHistoricalJobs().length > 0 && (
<>
<Divider
sx={{
my: 3,
borderWidth: 2,
borderColor: 'divider',
'&::before, &::after': {
borderColor: 'divider',
borderWidth: 2
}
}}
/>
<Typography variant="h6" sx={{ mb: 2, color: 'text.secondary' }}>
Job History
</Typography>
</>
)}
</>
)}
{/* Historical Jobs Section */}
{getHistoricalJobs().length > 0 && (
<List>
{getHistoricalJobs().map((job, index) => (
<React.Fragment key={job.job_id}>
{renderJobItem(job, false)}
{index < getHistoricalJobs().length - 1 && <Divider />}
</React.Fragment>
))}
</List>
<>
{(getProcessingJobs().length > 0 || getQueuedJobs().length > 0) && (
<Divider
sx={{
my: 3,
borderWidth: 2,
borderColor: 'divider',
'&::before, &::after': {
borderColor: 'divider',
borderWidth: 2
}
}}
/>
)}
<Typography variant="h6" sx={{ mb: 2, color: 'text.secondary', display: 'flex', alignItems: 'center', gap: 1 }}>
<CheckCircleRounded />
History ({getHistoricalJobs().length})
</Typography>
<List>
{getHistoricalJobs().map((job, index) => (
<React.Fragment key={job.job_id}>
{renderJobItem(job, 'history')}
{index < getHistoricalJobs().length - 1 && <Divider sx={{ my: 1 }} />}
</React.Fragment>
))}
</List>
</>
)}
</>
)}

View file

@ -432,7 +432,7 @@ const VideoForm = ({ onSubmit, isGenerating, userJobs = [], queueLimit = 4 }) =>
>
{userJobs.length >= queueLimit
? 'Queue Full'
: userJobs.some(job => ['starting', 'uploading_image', 'generating', 'processing', 'downloading'].includes(job.status))
: userJobs.some(job => ['starting', 'uploading_image', 'generating', 'processing', 'downloading', 'queued'].includes(job.status))
? 'Add to Queue'
: 'Generate Video'
}