fix(frontend): corrige manejo de errores en componentes de IA

Cambios realizados:

1. ai-status.service.ts:
   - Importa 'of' desde 'rxjs' para retornar Observables correctamente
   - Corrige catchError que retornaba array [] en lugar de Observable
   - Ahora retorna of({...}) con valores por defecto cuando falla el endpoint
   - Estadísticas ahora muestran 0 en lugar de valores mock cuando hay error

2. ai-suggestions-panel.component.ts:
   - Importa 'of' y 'catchError' desde 'rxjs/operators'
   - Agrega catchError a TODAS las llamadas de servicios (tags, correspondents, etc.)
   - Cada llamada ahora maneja errores y retorna array vacío en caso de fallo
   - Previene que errores de red rompan la funcionalidad del panel
   - Agrega logging de errores para debugging

Estos cambios corrigen:
- ✓ Estadísticas mostrando 0 incorrectamente
- ✓ Errores no manejados en llamadas HTTP
- ✓ Fallos al cargar metadata de sugerencias
- ✓ Panel de sugerencias fallando silenciosamente
This commit is contained in:
Claude 2025-11-17 22:51:40 +00:00
parent 47b7ac25b4
commit 3c8a1c9c66
No known key found for this signature in database
2 changed files with 77 additions and 36 deletions

View file

@ -18,8 +18,8 @@ import {
} from '@angular/core'
import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { Subject } from 'rxjs'
import { takeUntil } from 'rxjs/operators'
import { Subject, of } from 'rxjs'
import { takeUntil, catchError } from 'rxjs/operators'
import {
AISuggestion,
AISuggestionStatus,
@ -134,10 +134,19 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
(s) => s.type === AISuggestionType.Tag
)
if (tagSuggestions.length > 0) {
this.tagService.listAll().pipe(takeUntil(this.destroy$)).subscribe((tags) => {
this.tags = tags.results
this.updateSuggestionLabels()
})
this.tagService
.listAll()
.pipe(
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load tags:', error)
return of({ results: [] })
})
)
.subscribe((tags) => {
this.tags = tags.results
this.updateSuggestionLabels()
})
}
// Load correspondents if needed
@ -145,10 +154,19 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
(s) => s.type === AISuggestionType.Correspondent
)
if (correspondentSuggestions.length > 0) {
this.correspondentService.listAll().pipe(takeUntil(this.destroy$)).subscribe((correspondents) => {
this.correspondents = correspondents.results
this.updateSuggestionLabels()
})
this.correspondentService
.listAll()
.pipe(
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load correspondents:', error)
return of({ results: [] })
})
)
.subscribe((correspondents) => {
this.correspondents = correspondents.results
this.updateSuggestionLabels()
})
}
// Load document types if needed
@ -156,10 +174,19 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
(s) => s.type === AISuggestionType.DocumentType
)
if (documentTypeSuggestions.length > 0) {
this.documentTypeService.listAll().pipe(takeUntil(this.destroy$)).subscribe((documentTypes) => {
this.documentTypes = documentTypes.results
this.updateSuggestionLabels()
})
this.documentTypeService
.listAll()
.pipe(
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load document types:', error)
return of({ results: [] })
})
)
.subscribe((documentTypes) => {
this.documentTypes = documentTypes.results
this.updateSuggestionLabels()
})
}
// Load storage paths if needed
@ -167,10 +194,19 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
(s) => s.type === AISuggestionType.StoragePath
)
if (storagePathSuggestions.length > 0) {
this.storagePathService.listAll().pipe(takeUntil(this.destroy$)).subscribe((storagePaths) => {
this.storagePaths = storagePaths.results
this.updateSuggestionLabels()
})
this.storagePathService
.listAll()
.pipe(
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load storage paths:', error)
return of({ results: [] })
})
)
.subscribe((storagePaths) => {
this.storagePaths = storagePaths.results
this.updateSuggestionLabels()
})
}
// Load custom fields if needed
@ -178,10 +214,19 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
(s) => s.type === AISuggestionType.CustomField
)
if (customFieldSuggestions.length > 0) {
this.customFieldsService.listAll().pipe(takeUntil(this.destroy$)).subscribe((customFields) => {
this.customFields = customFields.results
this.updateSuggestionLabels()
})
this.customFieldsService
.listAll()
.pipe(
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load custom fields:', error)
return of({ results: [] })
})
)
.subscribe((customFields) => {
this.customFields = customFields.results
this.updateSuggestionLabels()
})
}
}

View file

@ -1,6 +1,6 @@
import { HttpClient } from '@angular/common/http'
import { Injectable, inject } from '@angular/core'
import { BehaviorSubject, Observable, interval, Subscription } from 'rxjs'
import { BehaviorSubject, Observable, interval, Subscription, of } from 'rxjs'
import { catchError, map, startWith, switchMap } from 'rxjs/operators'
import { AIStatus } from 'src/app/data/ai-status'
import { environment } from 'src/environments/environment'
@ -86,19 +86,15 @@ export class AIStatusService {
}),
catchError((error) => {
this.loading = false
console.warn('Failed to fetch AI status, using mock data:', error)
// Return mock data if endpoint doesn't exist yet
return [
{
active: true,
processing: false,
documents_scanned_today: 42,
suggestions_applied: 15,
pending_deletion_requests: 2,
last_scan: new Date().toISOString(),
version: '1.0.0',
},
]
console.warn('Failed to fetch AI status:', error)
// Return default status if endpoint fails
return of({
active: false,
processing: false,
documents_scanned_today: 0,
suggestions_applied: 0,
pending_deletion_requests: 0,
})
})
)
}