// ========================================
// Queue Page
// ========================================
// View and manage issue execution queues
import { useIntl } from 'react-intl';
import {
ListTodo,
RefreshCw,
AlertCircle,
CheckCircle,
Clock,
GitMerge,
} from 'lucide-react';
import { Card } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button';
import { Badge } from '@/components/ui/Badge';
import { QueueCard } from '@/components/issue/queue/QueueCard';
import { useIssueQueue, useQueueMutations } from '@/hooks';
import { cn } from '@/lib/utils';
// ========== Loading Skeleton ==========
function QueuePageSkeleton() {
return (
{/* Header Skeleton */}
{/* Stats Cards Skeleton */}
{[1, 2, 3, 4].map((i) => (
))}
{/* Queue Cards Skeleton */}
);
}
// ========== Empty State ==========
function QueueEmptyState() {
const { formatMessage } = useIntl();
return (
{formatMessage({ id: 'issues.queue.emptyState.title' })}
{formatMessage({ id: 'issues.queue.emptyState.description' })}
);
}
// ========== Main Page Component ==========
export function QueuePage() {
const { formatMessage } = useIntl();
const { data: queueData, isLoading, isFetching, refetch, error } = useIssueQueue();
const {
activateQueue,
deactivateQueue,
deleteQueue,
mergeQueues,
isActivating,
isDeactivating,
isDeleting,
isMerging,
} = useQueueMutations();
// Get queue data with proper type
const queue = queueData;
const taskCount = queue?.tasks?.length || 0;
const solutionCount = queue?.solutions?.length || 0;
const conflictCount = queue?.conflicts?.length || 0;
const groupCount = Object.keys(queue?.grouped_items || {}).length;
const totalItems = taskCount + solutionCount;
const handleActivate = async (queueId: string) => {
try {
await activateQueue(queueId);
} catch (err) {
console.error('Failed to activate queue:', err);
}
};
const handleDeactivate = async () => {
try {
await deactivateQueue();
} catch (err) {
console.error('Failed to deactivate queue:', err);
}
};
const handleDelete = async (queueId: string) => {
try {
await deleteQueue(queueId);
} catch (err) {
console.error('Failed to delete queue:', err);
}
};
const handleMerge = async (sourceId: string, targetId: string) => {
try {
await mergeQueues(sourceId, targetId);
} catch (err) {
console.error('Failed to merge queues:', err);
}
};
if (isLoading) {
return ;
}
if (error) {
return (
{formatMessage({ id: 'issues.queue.error.title' })}
{(error as Error).message || formatMessage({ id: 'issues.queue.error.message' })}
);
}
if (!queue || totalItems === 0) {
return ;
}
// Check if queue is active (has items and no conflicts)
const isActive = totalItems > 0 && conflictCount === 0;
return (
{/* Page Header */}
{formatMessage({ id: 'issues.queue.pageTitle' })}
{formatMessage({ id: 'issues.queue.description' })}
{/* Stats Cards */}
{totalItems}
{formatMessage({ id: 'issues.queue.stats.totalItems' })}
{groupCount}
{formatMessage({ id: 'issues.queue.stats.groups' })}
{taskCount}
{formatMessage({ id: 'issues.queue.stats.tasks' })}
{solutionCount}
{formatMessage({ id: 'issues.queue.stats.solutions' })}
{/* Conflicts Warning */}
{conflictCount > 0 && (
{formatMessage({ id: 'issues.queue.conflicts.title' })}
{conflictCount} {formatMessage({ id: 'issues.queue.conflicts.description' })}
)}
{/* Queue Card */}
{/* Status Footer */}
{isActive ? (
<>
{formatMessage({ id: 'issues.queue.status.ready' })}
>
) : (
<>
{formatMessage({ id: 'issues.queue.status.pending' })}
>
)}
{isActive ? (
) : (
)}
{isActive
? formatMessage({ id: 'issues.queue.status.active' })
: formatMessage({ id: 'issues.queue.status.inactive' })
}
);
}
export default QueuePage;