From 3ea6ea772e1adac7b348c0e25ea0b67f3bc58c17 Mon Sep 17 00:00:00 2001 From: enlineawork Date: Wed, 9 Sep 2026 11:06:14 -0300 Subject: [PATCH] feat(f6): show exact classification findings in asset dossier --- .../assets/AssetFindingCatalogPanel.tsx | 126 +++++++++++------- 1 file changed, 81 insertions(+), 45 deletions(-) diff --git a/web-v2/src/features/assets/AssetFindingCatalogPanel.tsx b/web-v2/src/features/assets/AssetFindingCatalogPanel.tsx index c7f8ef2..bf6c186 100644 --- a/web-v2/src/features/assets/AssetFindingCatalogPanel.tsx +++ b/web-v2/src/features/assets/AssetFindingCatalogPanel.tsx @@ -1,59 +1,95 @@ import { useEffect, useMemo, useState } from 'react'; +import { Link } from 'react-router'; import { Alert, LoadingBlock, errorMessage } from '../../components/Feedback'; import { Icon } from '../../components/Icon'; -import { getFindingCatalogAssetSelection, replaceFindingCatalogAssetSelection } from '../../lib/api'; -import type { FindingCatalogAssetSelection } from '../../lib/api'; +import { + getInventoryFamilyFindings, + getInventoryTechnicalValues, +} from '../../lib/inventoryStructureApi'; +import type { + InventoryFamilyFinding, + InventoryTechnicalValues, +} from '../../lib/inventoryStructureApi'; +import { AssetTechnicalDataPanel } from './AssetTechnicalDataPanel'; export function AssetFindingCatalogPanel({ assetId, canManage }: { assetId: string; canManage: boolean }) { - const [selection, setSelection] = useState(null); - const [enabled, setEnabled] = useState>(new Set()); - const [reason, setReason] = useState(''); + const [technical, setTechnical] = useState(null); + const [items, setItems] = useState([]); const [search, setSearch] = useState(''); const [loading, setLoading] = useState(true); - const [saving, setSaving] = useState(false); + const [unsupported, setUnsupported] = useState(false); const [error, setError] = useState(''); - const [success, setSuccess] = useState(''); - const load = () => getFindingCatalogAssetSelection(assetId).then((loaded) => { - setSelection(loaded); - setEnabled(new Set(loaded.items.filter((item) => item.enabled).map((item) => item.id))); - }); - - useEffect(() => { load().catch((requestError) => setError(errorMessage(requestError))).finally(() => setLoading(false)); }, [assetId]); + useEffect(() => { + let active = true; + setLoading(true); + setUnsupported(false); + setError(''); + getInventoryTechnicalValues(assetId) + .then(async (loaded) => { + const findings = await getInventoryFamilyFindings(loaded.family.id); + if (!active) return; + setTechnical(loaded); + setItems(findings.items); + }) + .catch((requestError) => { + if (!active) return; + const message = errorMessage(requestError); + if (message.includes('no tiene clasificación técnica')) setUnsupported(true); + else setError(message); + }) + .finally(() => active && setLoading(false)); + return () => { active = false; }; + }, [assetId]); const visible = useMemo(() => { const needle = search.trim().toLocaleLowerCase(); - return selection?.items.filter((item) => !needle || [item.title, item.code, item.categoryName] - .some((value) => value.toLocaleLowerCase().includes(needle))) ?? []; - }, [selection, search]); + if (!needle) return items; + return items.filter((item) => [item.title, item.code, item.categoryName, item.legalBasis ?? ''] + .some((value) => value.toLocaleLowerCase().includes(needle))); + }, [items, search]); - const toggle = (id: string) => setEnabled((current) => { - const next = new Set(current); - if (next.has(id)) next.delete(id); else next.add(id); - return next; - }); - - const save = async () => { - setSaving(true); setError(''); setSuccess(''); - try { - const saved = await replaceFindingCatalogAssetSelection(assetId, { enabledItemIds: [...enabled], reason }); - setSelection(saved); - setEnabled(new Set(saved.items.filter((item) => item.enabled).map((item) => item.id))); - setReason(''); - setSuccess('Subconjunto de hallazgos actualizado para este objeto.'); - } catch (requestError) { setError(errorMessage(requestError)); } - finally { setSaving(false); } - }; - - if (loading) return
; - if (!selection) return {error || 'No se pudo cargar la configuración.'}; - - return
-
HALLAZGOS APLICABLES

{selection.asset.name}

Base: {selection.asset.assetTypeName}. Las excepciones de esta pantalla afectan sólo a este objeto del Inventario.

{enabled.size} habilitados
- {error && {error}}{success && {success}} - {!selection.typeConfigured &&

El tipo técnico todavía no tiene un catálogo restringido. Por compatibilidad, su base actual incluye todo el catálogo activo. Podés configurar primero el tipo general en “Catálogo de hallazgos”.

} - -
{visible.map((item) => )}
- {canManage && <>