T-2: Extract getJobStatusColor() into utils/jobStatusMessages.ts; StatusBadge now uses the
shared helper (single source of truth for badge colors).
PR-7: GET /admin/production/queue-stats — returns Celery queue depths via Redis LLEN.
Production dashboard shows a live panel (10s refresh) with per-queue task counts.
PR-8: POST /admin/production/jobs/{id}/upload-final-vtt — Production/Admin can upload a
hand-crafted VTT to bypass AI, writing to GCS and advancing the job to PENDING_QC.
Upload modal added to FailuresList with language + type (captions/ad) selectors.
docker-compose.optical-dev.yml: enable USE_CELERY_FALLBACK=true, set worker replicas=1
for all pipeline workers (ffmpeg/tts/whisper) with WORKER_CONCURRENCY=2 so the full
pipeline runs on the 2-CPU optical-dev server until Cloud Run VPC Connector is ready.
Fix: remove unused effectiveMs variable in TimelinePreview (TS6133).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
190 lines
No EOL
5.7 KiB
TypeScript
190 lines
No EOL
5.7 KiB
TypeScript
/**
|
|
* Utility functions for generating user-friendly job status messages and toast notifications
|
|
*/
|
|
|
|
export interface StatusMessageConfig {
|
|
message: string;
|
|
type: 'success' | 'info' | 'warning' | 'error';
|
|
showToast: boolean;
|
|
}
|
|
|
|
/**
|
|
* Get user-friendly message and toast configuration for job status updates
|
|
*/
|
|
export function getStatusMessageConfig(
|
|
status: string,
|
|
jobTitle?: string,
|
|
customMessage?: string
|
|
): StatusMessageConfig {
|
|
const title = jobTitle ? `"${jobTitle}"` : 'Job';
|
|
const fallbackMessage = customMessage || '';
|
|
|
|
switch (status) {
|
|
case 'created':
|
|
return {
|
|
message: `${title} has been created and queued for processing`,
|
|
type: 'info',
|
|
showToast: true
|
|
};
|
|
|
|
case 'ingesting':
|
|
return {
|
|
message: `${title} is being ingested and prepared for AI processing`,
|
|
type: 'info',
|
|
showToast: true
|
|
};
|
|
|
|
case 'ai_processing':
|
|
return {
|
|
message: `${title} is being processed by AI to generate accessibility features`,
|
|
type: 'info',
|
|
showToast: true
|
|
};
|
|
|
|
case 'pending_qc':
|
|
return {
|
|
message: customMessage || `${title} is ready for quality control review`,
|
|
type: customMessage ? 'success' : 'info',
|
|
showToast: true
|
|
};
|
|
|
|
case 'approved_english':
|
|
case 'approved_source':
|
|
return {
|
|
message: `${title} source content has been approved - starting translation`,
|
|
type: 'success',
|
|
showToast: true
|
|
};
|
|
|
|
case 'rejected':
|
|
return {
|
|
message: `${title} has been rejected and requires revision`,
|
|
type: 'warning',
|
|
showToast: true
|
|
};
|
|
|
|
case 'translating':
|
|
return {
|
|
message: `${title} is being translated and transcreated into requested languages`,
|
|
type: 'info',
|
|
showToast: true
|
|
};
|
|
|
|
case 'tts_generating':
|
|
return {
|
|
message: `${title} is generating audio descriptions with text-to-speech`,
|
|
type: 'info',
|
|
showToast: true
|
|
};
|
|
|
|
case 'rendering_video':
|
|
return {
|
|
message: `${title} is rendering accessible video with embedded audio descriptions`,
|
|
type: 'info',
|
|
showToast: true
|
|
};
|
|
|
|
case 'rendering_qc':
|
|
return {
|
|
message: customMessage || `${title} is re-rendering accessible video with your changes`,
|
|
type: 'info',
|
|
showToast: true
|
|
};
|
|
|
|
case 'pending_final_review':
|
|
return {
|
|
message: `${title} is ready for final review before completion`,
|
|
type: 'info',
|
|
showToast: true
|
|
};
|
|
|
|
case 'qc_feedback':
|
|
return {
|
|
message: `${title} final review has been rejected - requires changes`,
|
|
type: 'warning',
|
|
showToast: true
|
|
};
|
|
|
|
case 'completed':
|
|
return {
|
|
message: `${title} has been completed successfully! 🎉 All files are ready for download`,
|
|
type: 'success',
|
|
showToast: true
|
|
};
|
|
|
|
default:
|
|
return {
|
|
message: fallbackMessage || `${title} status updated to ${status}`,
|
|
type: 'info',
|
|
showToast: !!fallbackMessage
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a shorter status message for progress updates
|
|
*/
|
|
export function getProgressMessage(status: string, progress?: number): string {
|
|
const progressText = progress !== undefined ? ` (${progress}%)` : '';
|
|
|
|
switch (status) {
|
|
case 'ingesting':
|
|
return `Ingesting video${progressText}`;
|
|
case 'ai_processing':
|
|
return `AI processing${progressText}`;
|
|
case 'translating':
|
|
return `Translating content${progressText}`;
|
|
case 'tts_generating':
|
|
return `Generating audio${progressText}`;
|
|
case 'rendering_video':
|
|
return `Rendering video${progressText}`;
|
|
default:
|
|
return status.replace(/_/g, ' ');
|
|
}
|
|
}
|
|
|
|
/** Single source of truth for human-readable job status labels. */
|
|
export const JOB_STATUS_LABELS: Record<string, string> = {
|
|
created: 'Created',
|
|
ingesting: 'Ingesting',
|
|
ai_processing: 'AI Processing',
|
|
pending_qc: 'Pending QC',
|
|
approved_english: 'Approved (EN)',
|
|
approved_source: 'Approved for Translation',
|
|
rejected: 'Rejected',
|
|
qc_feedback: 'QC Feedback',
|
|
translating: 'Translating',
|
|
tts_generating: 'Generating Audio',
|
|
tts_failed: 'TTS Failed',
|
|
rendering_video: 'Rendering Video',
|
|
render_failed: 'Render Failed',
|
|
pending_final_review: 'Pending Final Review',
|
|
completed: 'Completed',
|
|
};
|
|
|
|
export const getJobStatusLabel = (status: string): string =>
|
|
JOB_STATUS_LABELS[status] ?? status.replace(/_/g, ' ');
|
|
|
|
/** Tailwind classes for job status badges (bg + text). */
|
|
export function getJobStatusColor(status: string): string {
|
|
switch (status) {
|
|
case 'created': return 'bg-gray-100 text-gray-800';
|
|
case 'ingesting': return 'bg-blue-100 text-blue-800';
|
|
case 'ai_processing': return 'bg-purple-100 text-purple-800';
|
|
case 'pending_qc': return 'bg-yellow-100 text-yellow-800';
|
|
case 'approved_english':
|
|
case 'approved_source':
|
|
case 'completed': return 'bg-green-100 text-green-800';
|
|
case 'rejected':
|
|
case 'tts_failed':
|
|
case 'render_failed':
|
|
case 'processing_failed': return 'bg-red-100 text-red-800';
|
|
case 'qc_feedback': return 'bg-orange-100 text-orange-800';
|
|
case 'translating': return 'bg-blue-100 text-blue-800';
|
|
case 'tts_generating': return 'bg-indigo-100 text-indigo-800';
|
|
case 'rendering_video': return 'bg-violet-100 text-violet-800';
|
|
case 'rendering_qc': return 'bg-violet-100 text-violet-800';
|
|
case 'pending_final_review':return 'bg-orange-100 text-orange-800';
|
|
default: return 'bg-gray-100 text-gray-800';
|
|
}
|
|
} |