feat: Add manual re-validation button

This commit is contained in:
gpt-engineer-app[bot]
2025-10-17 15:58:22 +00:00
parent 1e60d6c6b6
commit 197f1a3f4a
3 changed files with 21 additions and 4 deletions

View File

@@ -20,6 +20,7 @@ interface ItemReviewCardProps {
export function ItemReviewCard({ item, onEdit, onStatusChange, submissionId }: ItemReviewCardProps) { export function ItemReviewCard({ item, onEdit, onStatusChange, submissionId }: ItemReviewCardProps) {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const [validationResult, setValidationResult] = useState<ValidationResult | null>(null); const [validationResult, setValidationResult] = useState<ValidationResult | null>(null);
const [validationKey, setValidationKey] = useState(0);
const handleValidationChange = useCallback((result: ValidationResult) => { const handleValidationChange = useCallback((result: ValidationResult) => {
setValidationResult(result); setValidationResult(result);
@@ -131,6 +132,7 @@ export function ItemReviewCard({ item, onEdit, onStatusChange, submissionId }: I
}} }}
onValidationChange={handleValidationChange} onValidationChange={handleValidationChange}
compact={false} compact={false}
validationKey={validationKey}
/> />
</div> </div>

View File

@@ -62,6 +62,7 @@ export function SubmissionReviewManager({
const [validationResults, setValidationResults] = useState<Map<string, ValidationResult>>(new Map()); const [validationResults, setValidationResults] = useState<Map<string, ValidationResult>>(new Map());
const [userConfirmedWarnings, setUserConfirmedWarnings] = useState(false); const [userConfirmedWarnings, setUserConfirmedWarnings] = useState(false);
const [hasBlockingErrors, setHasBlockingErrors] = useState(false); const [hasBlockingErrors, setHasBlockingErrors] = useState(false);
const [globalValidationKey, setGlobalValidationKey] = useState(0);
const { toast } = useToast(); const { toast } = useToast();
const { isAdmin, isSuperuser } = useUserRole(); const { isAdmin, isSuperuser } = useUserRole();
@@ -374,6 +375,7 @@ export function SubmissionReviewManager({
setShowEditDialog(false); setShowEditDialog(false);
setEditingItem(null); setEditingItem(null);
await loadSubmissionItems(); await loadSubmissionItems();
setGlobalValidationKey(prev => prev + 1);
}; };
const handleItemStatusChange = async (itemId: string, status: 'approved' | 'rejected') => { const handleItemStatusChange = async (itemId: string, status: 'approved' | 'rejected') => {

View File

@@ -1,6 +1,7 @@
import { useEffect, useState, useMemo } from 'react'; import { useEffect, useState, useMemo } from 'react';
import { AlertCircle, CheckCircle, Info, AlertTriangle } from 'lucide-react'; import { AlertCircle, CheckCircle, Info, AlertTriangle, RefreshCw } from 'lucide-react';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
import { validateEntityData, ValidationResult } from '@/lib/entityValidationSchemas'; import { validateEntityData, ValidationResult } from '@/lib/entityValidationSchemas';
@@ -13,12 +14,14 @@ interface ValidationSummaryProps {
}; };
onValidationChange?: (result: ValidationResult) => void; onValidationChange?: (result: ValidationResult) => void;
compact?: boolean; compact?: boolean;
validationKey?: number;
} }
export function ValidationSummary({ item, onValidationChange, compact = false }: ValidationSummaryProps) { export function ValidationSummary({ item, onValidationChange, compact = false, validationKey }: ValidationSummaryProps) {
const [validationResult, setValidationResult] = useState<ValidationResult | null>(null); const [validationResult, setValidationResult] = useState<ValidationResult | null>(null);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [isExpanded, setIsExpanded] = useState(false); const [isExpanded, setIsExpanded] = useState(false);
const [manualTriggerCount, setManualTriggerCount] = useState(0);
// Create stable reference for item_data to prevent unnecessary re-validations // Create stable reference for item_data to prevent unnecessary re-validations
const itemDataString = useMemo( const itemDataString = useMemo(
@@ -68,7 +71,7 @@ export function ValidationSummary({ item, onValidationChange, compact = false }:
} }
validate(); validate();
}, [item.item_type, itemDataString, item.id]); }, [item.item_type, itemDataString, item.id, validationKey, manualTriggerCount]);
// Auto-expand when there are blocking errors or warnings // Auto-expand when there are blocking errors or warnings
useEffect(() => { useEffect(() => {
@@ -158,7 +161,7 @@ export function ValidationSummary({ item, onValidationChange, compact = false }:
return ( return (
<div className="space-y-3"> <div className="space-y-3">
{/* Summary Badge */} {/* Summary Badge */}
<div className="flex items-center gap-2"> <div className="flex items-center gap-2 flex-wrap">
{validationResult.isValid && !hasWarnings && !hasSuggestions && ( {validationResult.isValid && !hasWarnings && !hasSuggestions && (
<Badge variant="secondary" className="bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300 border-green-300 dark:border-green-700"> <Badge variant="secondary" className="bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300 border-green-300 dark:border-green-700">
<CheckCircle className="w-4 h-4 mr-1" /> <CheckCircle className="w-4 h-4 mr-1" />
@@ -183,6 +186,16 @@ export function ValidationSummary({ item, onValidationChange, compact = false }:
{validationResult.suggestions.length} Suggestion{validationResult.suggestions.length !== 1 ? 's' : ''} {validationResult.suggestions.length} Suggestion{validationResult.suggestions.length !== 1 ? 's' : ''}
</Badge> </Badge>
)} )}
<Button
variant="outline"
size="sm"
onClick={() => setManualTriggerCount(prev => prev + 1)}
className="text-xs h-7"
>
<RefreshCw className="w-3 h-3 mr-1" />
Re-validate
</Button>
</div> </div>
{/* Detailed Issues */} {/* Detailed Issues */}