feat(extraction): édition et suppression des entités directement dans l’onglet Extraction

This commit is contained in:
4NK IA 2025-09-18 14:12:17 +00:00
parent c380ce31f0
commit a2b6e70e38

View File

@ -5,6 +5,7 @@ import { useAppDispatch, useAppSelector } from '../store'
import { setCurrentResultIndex } from '../store/documentSlice' import { setCurrentResultIndex } from '../store/documentSlice'
import { clearFolderCache, reprocessFolder } from '../services/folderApi' import { clearFolderCache, reprocessFolder } from '../services/folderApi'
import { Layout } from '../components/Layout' import { Layout } from '../components/Layout'
import { deleteEntity, updateEntity } from '../services/folderApi'
export default function ExtractionView() { export default function ExtractionView() {
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
@ -15,6 +16,7 @@ export default function ExtractionView() {
// Utiliser les résultats du dossier pour la navigation // Utiliser les résultats du dossier pour la navigation
const currentResult = folderResults[currentIndex] const currentResult = folderResults[currentIndex]
const [savingKey, setSavingKey] = useState<string | null>(null)
const gotoResult = (index: number) => { const gotoResult = (index: number) => {
if (index >= 0 && index < folderResults.length) { if (index >= 0 && index < folderResults.length) {
@ -194,17 +196,28 @@ export default function ExtractionView() {
Personnes ({extraction.extraction.entities.persons.length}) Personnes ({extraction.extraction.entities.persons.length})
</Typography> </Typography>
<List dense> <List dense>
{extraction.extraction.entities.persons.map((person: any, index: number) => { {extraction.extraction.entities.persons.map((p: any, i: number) => (
const label = <ListItem key={`p-${i}`} secondaryAction={
typeof person === 'string' <Box sx={{ display: 'flex', gap: 1 }}>
? person <Button size="small" variant="outlined" disabled={savingKey===`p-${i}`}
: [person.firstName, person.lastName].filter(Boolean).join(' ') || person?.id || 'Personne' onClick={async ()=>{
return ( try{
<ListItem key={index}> setSavingKey(`p-${i}`)
<ListItemText primary={label} secondary="Personne détectée" /> await updateEntity(currentFolderHash!, extraction.fileHash, 'person', { index: i, id: p.id, patch: { firstName: p.firstName, lastName: p.lastName } })
</ListItem> } finally { setSavingKey(null) }
) }}>Enregistrer</Button>
})} <Button size="small" color="error"
onClick={async ()=>{
await deleteEntity(currentFolderHash!, extraction.fileHash, 'person', { index: i, id: p.id })
}}>Supprimer</Button>
</Box>
}>
<Box sx={{ display: 'flex', gap: 1 }}>
<input style={{ padding: 4, width: 120 }} defaultValue={p.firstName} onChange={(e)=> (p.firstName=e.target.value)} />
<input style={{ padding: 4, width: 140 }} defaultValue={p.lastName} onChange={(e)=> (p.lastName=e.target.value)} />
</Box>
</ListItem>
))}
</List> </List>
</CardContent> </CardContent>
</Card> </Card>
@ -219,19 +232,30 @@ export default function ExtractionView() {
Adresses ({extraction.extraction.entities.addresses.length}) Adresses ({extraction.extraction.entities.addresses.length})
</Typography> </Typography>
<List dense> <List dense>
{extraction.extraction.entities.addresses.map((address: any, index: number) => { {extraction.extraction.entities.addresses.map((a: any, i: number) => (
const label = <ListItem key={`a-${i}`} secondaryAction={
typeof address === 'string' <Box sx={{ display: 'flex', gap: 1 }}>
? address <Button size="small" variant="outlined" disabled={savingKey===`a-${i}`}
: [address.street, address.postalCode, address.city] onClick={async ()=>{
.filter((v) => !!v && String(v).trim().length > 0) try{
.join(' ') || address?.id || 'Adresse' setSavingKey(`a-${i}`)
return ( await updateEntity(currentFolderHash!, extraction.fileHash, 'address', { index: i, id: a.id, patch: { street: a.street, city: a.city, postalCode: a.postalCode, country: a.country } })
<ListItem key={index}> } finally { setSavingKey(null) }
<ListItemText primary={label} secondary="Adresse détectée" /> }}>Enregistrer</Button>
</ListItem> <Button size="small" color="error"
) onClick={async ()=>{
})} await deleteEntity(currentFolderHash!, extraction.fileHash, 'address', { index: i, id: a.id })
}}>Supprimer</Button>
</Box>
}>
<Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>
<input style={{ padding: 4, width: 220 }} defaultValue={a.street} onChange={(e)=> (a.street=e.target.value)} />
<input style={{ padding: 4, width: 100 }} defaultValue={a.postalCode} onChange={(e)=> (a.postalCode=e.target.value)} />
<input style={{ padding: 4, width: 160 }} defaultValue={a.city} onChange={(e)=> (a.city=e.target.value)} />
<input style={{ padding: 4, width: 120 }} defaultValue={a.country||''} onChange={(e)=> (a.country=e.target.value)} />
</Box>
</ListItem>
))}
</List> </List>
</CardContent> </CardContent>
</Card> </Card>
@ -246,14 +270,27 @@ export default function ExtractionView() {
Entreprises ({extraction.extraction.entities.companies.length}) Entreprises ({extraction.extraction.entities.companies.length})
</Typography> </Typography>
<List dense> <List dense>
{extraction.extraction.entities.companies.map((company: any, index: number) => { {extraction.extraction.entities.companies.map((c: any, i: number) => (
const label = typeof company === 'string' ? company : company?.name || company?.id || 'Entreprise' <ListItem key={`c-${i}`} secondaryAction={
return ( <Box sx={{ display: 'flex', gap: 1 }}>
<ListItem key={index}> <Button size="small" variant="outlined" disabled={savingKey===`c-${i}`}
<ListItemText primary={label} secondary="Entreprise détectée" /> onClick={async ()=>{
</ListItem> try{
) setSavingKey(`c-${i}`)
})} await updateEntity(currentFolderHash!, extraction.fileHash, 'company', { index: i, id: c.id, patch: { name: c.name } })
} finally { setSavingKey(null) }
}}>Enregistrer</Button>
<Button size="small" color="error"
onClick={async ()=>{
await deleteEntity(currentFolderHash!, extraction.fileHash, 'company', { index: i, id: c.id })
}}>Supprimer</Button>
</Box>
}>
<Box sx={{ display: 'flex', gap: 1 }}>
<input style={{ padding: 4, width: 260 }} defaultValue={c.name} onChange={(e)=> (c.name=e.target.value)} />
</Box>
</ListItem>
))}
</List> </List>
</CardContent> </CardContent>
</Card> </Card>