mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 11:51:14 -05:00
Fix: Correctly drop and recreate claim_next_submission function
This commit is contained in:
@@ -173,11 +173,10 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
|
|||||||
reviewer_id,
|
reviewer_id,
|
||||||
reviewer_notes,
|
reviewer_notes,
|
||||||
escalated,
|
escalated,
|
||||||
priority,
|
|
||||||
assigned_to,
|
assigned_to,
|
||||||
locked_until
|
locked_until
|
||||||
`)
|
`)
|
||||||
.order('priority', { ascending: false })
|
.order('escalated', { ascending: false })
|
||||||
.order('created_at', { ascending: true });
|
.order('created_at', { ascending: true });
|
||||||
|
|
||||||
// Apply tab-based status filtering
|
// Apply tab-based status filtering
|
||||||
@@ -2025,15 +2024,11 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
|
|||||||
<CardContent className="p-4">
|
<CardContent className="p-4">
|
||||||
<div className="flex flex-col sm:flex-row gap-4 items-start sm:items-center justify-between">
|
<div className="flex flex-col sm:flex-row gap-4 items-start sm:items-center justify-between">
|
||||||
{/* Stats Grid */}
|
{/* Stats Grid */}
|
||||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4 flex-1">
|
<div className="grid grid-cols-2 sm:grid-cols-3 gap-4 flex-1">
|
||||||
<div className="text-center sm:text-left">
|
<div className="text-center sm:text-left">
|
||||||
<div className="text-2xl font-bold text-primary">{queue.queueStats.pendingCount}</div>
|
<div className="text-2xl font-bold text-primary">{queue.queueStats.pendingCount}</div>
|
||||||
<div className="text-xs text-muted-foreground">Pending</div>
|
<div className="text-xs text-muted-foreground">Pending</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-center sm:text-left">
|
|
||||||
<div className="text-2xl font-bold text-amber-600 dark:text-amber-400">{queue.queueStats.highPriorityCount}</div>
|
|
||||||
<div className="text-xs text-muted-foreground">High Priority</div>
|
|
||||||
</div>
|
|
||||||
<div className="text-center sm:text-left">
|
<div className="text-center sm:text-left">
|
||||||
<div className="text-2xl font-bold text-blue-600 dark:text-blue-400">{queue.queueStats.assignedToMe}</div>
|
<div className="text-2xl font-bold text-blue-600 dark:text-blue-400">{queue.queueStats.assignedToMe}</div>
|
||||||
<div className="text-xs text-muted-foreground">Assigned to Me</div>
|
<div className="text-xs text-muted-foreground">Assigned to Me</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Clock, AlertTriangle, CheckCircle, Users } from 'lucide-react';
|
import { Clock, CheckCircle, Users } from 'lucide-react';
|
||||||
import { useModerationQueue } from '@/hooks/useModerationQueue';
|
import { useModerationQueue } from '@/hooks/useModerationQueue';
|
||||||
|
|
||||||
export function QueueStatsDashboard() {
|
export function QueueStatsDashboard() {
|
||||||
@@ -19,7 +19,7 @@ export function QueueStatsDashboard() {
|
|||||||
const slaStatus = getSLAStatus(queueStats.avgWaitHours);
|
const slaStatus = getSLAStatus(queueStats.avgWaitHours);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 mb-6">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
<CardTitle className="text-sm font-medium">Pending Queue</CardTitle>
|
<CardTitle className="text-sm font-medium">Pending Queue</CardTitle>
|
||||||
@@ -70,21 +70,6 @@ export function QueueStatsDashboard() {
|
|||||||
</p>
|
</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card>
|
|
||||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
||||||
<CardTitle className="text-sm font-medium">High Priority</CardTitle>
|
|
||||||
<AlertTriangle className="h-4 w-4 text-muted-foreground" />
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="text-2xl font-bold text-destructive">
|
|
||||||
{queueStats.highPriorityCount}
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-muted-foreground mt-1">
|
|
||||||
Escalated submissions
|
|
||||||
</p>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { useToast } from './use-toast';
|
|||||||
interface QueuedSubmission {
|
interface QueuedSubmission {
|
||||||
submission_id: string;
|
submission_id: string;
|
||||||
submission_type: string;
|
submission_type: string;
|
||||||
priority: number;
|
|
||||||
waiting_time: string; // PostgreSQL interval format
|
waiting_time: string; // PostgreSQL interval format
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,7 +19,6 @@ interface QueueStats {
|
|||||||
pendingCount: number;
|
pendingCount: number;
|
||||||
assignedToMe: number;
|
assignedToMe: number;
|
||||||
avgWaitHours: number;
|
avgWaitHours: number;
|
||||||
highPriorityCount: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useModerationQueue = () => {
|
export const useModerationQueue = () => {
|
||||||
@@ -67,16 +65,14 @@ export const useModerationQueue = () => {
|
|||||||
(acc, row) => ({
|
(acc, row) => ({
|
||||||
pendingCount: acc.pendingCount + (row.pending_count || 0),
|
pendingCount: acc.pendingCount + (row.pending_count || 0),
|
||||||
avgWaitHours: acc.avgWaitHours + (row.avg_wait_hours || 0),
|
avgWaitHours: acc.avgWaitHours + (row.avg_wait_hours || 0),
|
||||||
highPriorityCount: acc.highPriorityCount + (row.escalated_count || 0),
|
|
||||||
}),
|
}),
|
||||||
{ pendingCount: 0, avgWaitHours: 0, highPriorityCount: 0 }
|
{ pendingCount: 0, avgWaitHours: 0 }
|
||||||
);
|
);
|
||||||
|
|
||||||
setQueueStats({
|
setQueueStats({
|
||||||
pendingCount: totals.pendingCount,
|
pendingCount: totals.pendingCount,
|
||||||
assignedToMe: assignedCount || 0,
|
assignedToMe: assignedCount || 0,
|
||||||
avgWaitHours: slaData.length > 0 ? totals.avgWaitHours / slaData.length : 0,
|
avgWaitHours: slaData.length > 0 ? totals.avgWaitHours / slaData.length : 0,
|
||||||
highPriorityCount: totals.highPriorityCount,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -166,7 +162,7 @@ export const useModerationQueue = () => {
|
|||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: 'Submission Claimed',
|
title: 'Submission Claimed',
|
||||||
description: `Priority ${claimed.priority} ${claimed.submission_type} (waiting ${formatInterval(claimed.waiting_time)})`,
|
description: `${claimed.submission_type} submission (waiting ${formatInterval(claimed.waiting_time)})`,
|
||||||
});
|
});
|
||||||
|
|
||||||
return claimed.submission_id;
|
return claimed.submission_id;
|
||||||
@@ -279,7 +275,6 @@ export const useModerationQueue = () => {
|
|||||||
escalated_at: new Date().toISOString(),
|
escalated_at: new Date().toISOString(),
|
||||||
escalated_by: user.id,
|
escalated_by: user.id,
|
||||||
escalation_reason: reason,
|
escalation_reason: reason,
|
||||||
priority: 10, // Max priority
|
|
||||||
})
|
})
|
||||||
.eq('id', submissionId);
|
.eq('id', submissionId);
|
||||||
|
|
||||||
|
|||||||
@@ -220,7 +220,6 @@ export type Database = {
|
|||||||
id: string
|
id: string
|
||||||
locked_until: string | null
|
locked_until: string | null
|
||||||
original_submission_id: string | null
|
original_submission_id: string | null
|
||||||
priority: number
|
|
||||||
resolved_at: string | null
|
resolved_at: string | null
|
||||||
review_count: number | null
|
review_count: number | null
|
||||||
reviewed_at: string | null
|
reviewed_at: string | null
|
||||||
@@ -246,7 +245,6 @@ export type Database = {
|
|||||||
id?: string
|
id?: string
|
||||||
locked_until?: string | null
|
locked_until?: string | null
|
||||||
original_submission_id?: string | null
|
original_submission_id?: string | null
|
||||||
priority?: number
|
|
||||||
resolved_at?: string | null
|
resolved_at?: string | null
|
||||||
review_count?: number | null
|
review_count?: number | null
|
||||||
reviewed_at?: string | null
|
reviewed_at?: string | null
|
||||||
@@ -272,7 +270,6 @@ export type Database = {
|
|||||||
id?: string
|
id?: string
|
||||||
locked_until?: string | null
|
locked_until?: string | null
|
||||||
original_submission_id?: string | null
|
original_submission_id?: string | null
|
||||||
priority?: number
|
|
||||||
resolved_at?: string | null
|
resolved_at?: string | null
|
||||||
review_count?: number | null
|
review_count?: number | null
|
||||||
reviewed_at?: string | null
|
reviewed_at?: string | null
|
||||||
@@ -2640,10 +2637,6 @@ export type Database = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Functions: {
|
Functions: {
|
||||||
calculate_submission_priority: {
|
|
||||||
Args: { submission_id: string }
|
|
||||||
Returns: number
|
|
||||||
}
|
|
||||||
can_approve_submission_item: {
|
can_approve_submission_item: {
|
||||||
Args: { item_id: string }
|
Args: { item_id: string }
|
||||||
Returns: boolean
|
Returns: boolean
|
||||||
@@ -2675,7 +2668,6 @@ export type Database = {
|
|||||||
claim_next_submission: {
|
claim_next_submission: {
|
||||||
Args: { lock_duration?: unknown; moderator_id: string }
|
Args: { lock_duration?: unknown; moderator_id: string }
|
||||||
Returns: {
|
Returns: {
|
||||||
priority: number
|
|
||||||
submission_id: string
|
submission_id: string
|
||||||
submission_type: string
|
submission_type: string
|
||||||
waiting_time: unknown
|
waiting_time: unknown
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
-- Remove priority system entirely
|
||||||
|
|
||||||
|
-- Drop the priority calculation function
|
||||||
|
DROP FUNCTION IF EXISTS public.calculate_submission_priority(UUID);
|
||||||
|
|
||||||
|
-- Drop the existing claim_next_submission function completely
|
||||||
|
DROP FUNCTION IF EXISTS public.claim_next_submission(UUID, INTERVAL);
|
||||||
|
|
||||||
|
-- Recreate claim_next_submission without priority logic
|
||||||
|
CREATE OR REPLACE FUNCTION public.claim_next_submission(
|
||||||
|
moderator_id UUID,
|
||||||
|
lock_duration INTERVAL DEFAULT '15 minutes'
|
||||||
|
)
|
||||||
|
RETURNS TABLE (
|
||||||
|
submission_id UUID,
|
||||||
|
submission_type TEXT,
|
||||||
|
waiting_time INTERVAL
|
||||||
|
)
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
SECURITY DEFINER
|
||||||
|
SET search_path = public
|
||||||
|
AS $$
|
||||||
|
BEGIN
|
||||||
|
-- Simple FIFO with escalation priority
|
||||||
|
RETURN QUERY
|
||||||
|
UPDATE content_submissions
|
||||||
|
SET
|
||||||
|
assigned_to = moderator_id,
|
||||||
|
assigned_at = NOW(),
|
||||||
|
locked_until = NOW() + lock_duration,
|
||||||
|
first_reviewed_at = COALESCE(first_reviewed_at, NOW())
|
||||||
|
WHERE id = (
|
||||||
|
SELECT cs.id FROM content_submissions cs
|
||||||
|
WHERE cs.status IN ('pending', 'partially_approved')
|
||||||
|
AND (cs.assigned_to IS NULL OR cs.locked_until < NOW())
|
||||||
|
ORDER BY
|
||||||
|
cs.escalated DESC, -- Escalated items first
|
||||||
|
cs.submitted_at ASC -- Then oldest first
|
||||||
|
LIMIT 1
|
||||||
|
FOR UPDATE SKIP LOCKED
|
||||||
|
)
|
||||||
|
RETURNING
|
||||||
|
content_submissions.id,
|
||||||
|
content_submissions.submission_type,
|
||||||
|
NOW() - content_submissions.submitted_at;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- Drop the priority column from content_submissions
|
||||||
|
ALTER TABLE public.content_submissions DROP COLUMN IF EXISTS priority;
|
||||||
Reference in New Issue
Block a user