Parallel Job View in Queue
This commit is contained in:
parent
7c972e8cd8
commit
ab5fd32287
7 changed files with 114 additions and 48 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue