diff --git a/.dev_session/SESSION_INFO b/.dev_session/SESSION_INFO
index 8216acd3..067d6a68 100644
--- a/.dev_session/SESSION_INFO
+++ b/.dev_session/SESSION_INFO
@@ -1 +1 @@
-{"task_id": "2f488f42-8544-802f-8311-ee72ef1aac2f", "token": "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", "session_start_time": "2026-01-27T10:44:04.509525"}
\ No newline at end of file
+{"task_id": "2f388f42-8544-80b7-9c71-e7c8f319990a", "token": "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", "session_start_time": "2026-01-27T11:18:14.201030"}
\ No newline at end of file
diff --git a/company-explorer/backend/app.py b/company-explorer/backend/app.py
index 8261a591..881fe9d0 100644
--- a/company-explorer/backend/app.py
+++ b/company-explorer/backend/app.py
@@ -107,6 +107,22 @@ def list_companies(
query = query.order_by(Company.name.asc())
items = query.offset(skip).limit(limit).all()
+
+ # Efficiently check for pending mistakes
+ company_ids = [c.id for c in items]
+ if company_ids:
+ pending_mistakes = db.query(ReportedMistake.company_id).filter(
+ ReportedMistake.company_id.in_(company_ids),
+ ReportedMistake.status == 'PENDING'
+ ).distinct().all()
+ companies_with_pending_mistakes = {row[0] for row in pending_mistakes}
+ else:
+ companies_with_pending_mistakes = set()
+
+ # Add the flag to each company object
+ for company in items:
+ company.has_pending_mistakes = company.id in companies_with_pending_mistakes
+
return {"total": total, "items": items}
except Exception as e:
logger.error(f"List Companies Error: {e}", exc_info=True)
@@ -251,6 +267,7 @@ def list_job_roles(db: Session = Depends(get_db)):
@app.get("/api/mistakes")
def list_reported_mistakes(
status: Optional[str] = Query(None),
+ company_id: Optional[int] = Query(None),
skip: int = 0,
limit: int = 50,
db: Session = Depends(get_db)
@@ -260,6 +277,9 @@ def list_reported_mistakes(
if status:
query = query.filter(ReportedMistake.status == status.upper())
+ if company_id:
+ query = query.filter(ReportedMistake.company_id == company_id)
+
total = query.count()
items = query.order_by(ReportedMistake.created_at.desc()).offset(skip).limit(limit).all()
diff --git a/company-explorer/frontend/src/components/CompanyTable.tsx b/company-explorer/frontend/src/components/CompanyTable.tsx
index 30526482..5698652e 100644
--- a/company-explorer/frontend/src/components/CompanyTable.tsx
+++ b/company-explorer/frontend/src/components/CompanyTable.tsx
@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react'
import axios from 'axios'
import {
Building, Search, Upload, Globe, MapPin, Play, Search as SearchIcon, Loader2,
- LayoutGrid, List, ChevronLeft, ChevronRight, ArrowDownUp
+ LayoutGrid, List, ChevronLeft, ChevronRight, ArrowDownUp, Flag
} from 'lucide-react'
import clsx from 'clsx'
@@ -16,6 +16,7 @@ interface Company {
industry_ai: string | null
created_at: string
updated_at: string
+ has_pending_mistakes: boolean
}
interface CompanyTableProps {
@@ -124,7 +125,10 @@ export function CompanyTable({ apiBase, onRowClick, refreshKey, onImportClick }:
style={{ borderLeftColor: c.status === 'ENRICHED' ? '#22c55e' : c.status === 'DISCOVERED' ? '#3b82f6' : '#94a3b8' }}>
-
{c.name}
+
{c.city && c.country ? (<> {c.city} ({c.country})>) : (-)}
@@ -163,7 +167,12 @@ export function CompanyTable({ apiBase, onRowClick, refreshKey, onImportClick }:
{data.map((c) => (
onRowClick(c.id)} className="hover:bg-slate-50 dark:hover:bg-slate-800/50 cursor-pointer">
- | {c.name} |
+
+
+
+ {c.name}
+
+ |
{c.city && c.country ? `${c.city}, (${c.country})` : '-'}
|
diff --git a/company-explorer/frontend/src/components/Inspector.tsx b/company-explorer/frontend/src/components/Inspector.tsx
index f9789f23..0237a7b6 100644
--- a/company-explorer/frontend/src/components/Inspector.tsx
+++ b/company-explorer/frontend/src/components/Inspector.tsx
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'
import axios from 'axios'
-import { X, ExternalLink, Bot, Briefcase, Calendar, Globe, Users, DollarSign, MapPin, Tag, RefreshCw as RefreshCwIcon, Search as SearchIcon, Pencil, Check, Download, Clock, Lock, Unlock, Calculator, Ruler, Database, Trash2, Flag } from 'lucide-react'
+import { X, ExternalLink, Bot, Briefcase, Calendar, Globe, Users, DollarSign, MapPin, Tag, RefreshCw as RefreshCwIcon, Search as SearchIcon, Pencil, Check, Download, Clock, Lock, Unlock, Calculator, Ruler, Database, Trash2, Flag, AlertTriangle } from 'lucide-react'
import clsx from 'clsx'
import { ContactsManager, Contact } from './ContactsManager'
@@ -48,6 +48,20 @@ type CompanyDetail = {
metric_confidence_reason: string | null
}
+// NEW
+type ReportedMistake = {
+ id: number;
+ field_name: string;
+ wrong_value: string | null;
+ corrected_value: string | null;
+ source_url: string | null;
+ quote: string | null;
+ user_comment: string | null;
+ status: 'PENDING' | 'APPROVED' | 'REJECTED';
+ created_at: string;
+};
+
+
export function Inspector({ companyId, initialContactId, onClose, apiBase }: InspectorProps) {
const [data, setData] = useState(null)
const [loading, setLoading] = useState(false)
@@ -56,6 +70,7 @@ export function Inspector({ companyId, initialContactId, onClose, apiBase }: Ins
// NEW: Report Mistake State
const [isReportingMistake, setIsReportingMistake] = useState(false)
+ const [existingMistakes, setExistingMistakes] = useState([])
const [reportedFieldName, setReportedFieldName] = useState("")
const [reportedWrongValue, setReportedWrongValue] = useState("")
const [reportedCorrectedValue, setReportedCorrectedValue] = useState("")
@@ -100,11 +115,14 @@ export function Inspector({ companyId, initialContactId, onClose, apiBase }: Ins
if (!companyId) return
if (!silent) setLoading(true)
- axios.get(`${apiBase}/companies/${companyId}`)
- .then(res => {
- const newData = res.data
- console.log("FETCHED COMPANY DATA:", newData) // DEBUG: Log raw data from API
+ const companyRequest = axios.get(`${apiBase}/companies/${companyId}`)
+ const mistakesRequest = axios.get(`${apiBase}/mistakes?company_id=${companyId}`)
+
+ Promise.all([companyRequest, mistakesRequest])
+ .then(([companyRes, mistakesRes]) => {
+ const newData = companyRes.data
setData(newData)
+ setExistingMistakes(mistakesRes.data.items)
// Auto-stop processing if status changes to ENRICHED or we see data
if (isProcessing) {
@@ -296,7 +314,15 @@ export function Inspector({ companyId, initialContactId, onClose, apiBase }: Ins
}
}
- const handleLockToggle = async (sourceType: string, currentLockStatus: boolean) => {\n if (!companyId) return\n try {\n await axios.post(`${apiBase}/enrichment/${companyId}/${sourceType}/lock?locked=${!currentLockStatus}`)\n fetchData(true) // Silent refresh\n } catch (e) {\n console.error(\"Lock toggle failed\", e)\n }\n }\n\n // NEW: Interface for reporting mistakes\n interface ReportedMistakeRequest {\n field_name: string;\n wrong_value?: string | null;\n corrected_value?: string | null;\n source_url?: string | null;\n quote?: string | null;\n user_comment?: string | null;\n }\n\n const handleReportMistake = async () => {\n if (!companyId) return;\n if (!reportedFieldName) {\n alert(\"Field Name is required.\");\n return;\n }\n\n setIsProcessing(true);\n try {\n const payload: ReportedMistakeRequest = {\n field_name: reportedFieldName,\n wrong_value: reportedWrongValue || null,\n corrected_value: reportedCorrectedValue || null,\n source_url: reportedSourceUrl || null,\n quote: reportedQuote || null,\n user_comment: reportedComment || null,\n };\n\n await axios.post(`${apiBase}/companies/${companyId}/report-mistake`, payload);\n alert(\"Mistake reported successfully!\");\n setIsReportingMistake(false);\n // Reset form fields\n setReportedFieldName(\"\");\n setReportedWrongValue(\"\");\ setReportedCorrectedValue(\"\");\n setReportedSourceUrl(\"\");\n setReportedQuote(\"\");\n setReportedComment(\"\");\n } catch (e) {\n alert(\"Failed to report mistake.\");\n console.error(e);\n } finally {\n setIsProcessing(false);\n }\n };
+ const handleLockToggle = async (sourceType: string, currentLockStatus: boolean) => {
+ if (!companyId) return
+ try {
+ await axios.post(`${apiBase}/enrichment/${companyId}/${sourceType}/lock?locked=${!currentLockStatus}`)
+ fetchData(true) // Silent refresh
+ } catch (e) {
+ console.error("Lock toggle failed", e)
+ }
+ }
// NEW: Interface for reporting mistakes
interface ReportedMistakeRequest {
@@ -336,6 +362,7 @@ export function Inspector({ companyId, initialContactId, onClose, apiBase }: Ins
setReportedSourceUrl("");
setReportedQuote("");
setReportedComment("");
+ fetchData(true); // Re-fetch to show the new mistake
} catch (e) {
alert("Failed to report mistake.");
console.error(e);
@@ -478,6 +505,36 @@ export function Inspector({ companyId, initialContactId, onClose, apiBase }: Ins
)}
+ {/* Reported Mistakes Section */}
+ {existingMistakes.length > 0 && (
+
+
+
+ Existing Correction Proposals
+
+
+ {existingMistakes.map(mistake => (
+
+
+ {mistake.field_name}
+
+ {mistake.status}
+
+
+
+ {mistake.wrong_value || 'N/A'} → {mistake.corrected_value || 'N/A'}
+
+ {mistake.user_comment &&
"{mistake.user_comment}"
}
+
+ ))}
+
+
+ )}
+
{/* Tab Navigation */}