metis-desk/docs/inventario-responsive-v01-3.md
David f9384c9376 feat: Introduce contextual detail layout and budget management for assets and resources
- Added `INVENTORY_DETAIL_BUDGET` and `RESOURCE_DETAIL_BUDGET` to define layout parameters for inventory and resource detail views.
- Implemented `useContextualDetail` hook to manage visibility and focus transitions between inline and overlay modes.
- Created `contextual-detail-layout` module to handle budget calculations and state management for contextual details.
- Updated documentation to reflect changes in asset and resource handling, ensuring consistent UI behavior across different viewports.
- Conducted regression tests to validate functionality and ensure no existing features were broken during the implementation.
2026-10-22 01:24:37 +02:00

15 KiB
Raw Blame History

Inventario de activos por capacidad — V01.3

Arquitectura y alcance

Entrega sobre V01.1/V01.2, sin cambiar su shell. La selección sigue en useAssetInventoryPageController; useInventoryDetail coordina capacidad y visibilidad contextual. No se modifica la navegación a fichas completas, permisos, API, datos, vendor ni dependencias. Recursos queda expresamente fuera: su migración corresponde a V01.4 y V01 continúa parcialmente resuelto.

Una referencia al div[data-slot=inventory-layout] observa su content box mediante un único ResizeObserver. El observer se desconecta al desmontar, publica solamente cruces de modo y comienza en overlay hasta recibir una medida fiable. No observa la columna que encoge, no usa innerWidth ni guarda píxeles como estado React. El grid no cambia de anchura exterior al mostrar el panel: no hay realimentación. El reducer devuelve el mismo estado ante capacidad/visibilidad iguales.

inventory-detail-layout.ts es la fuente única del presupuesto, la decisión y las columnas. No se replica un umbral en CSS. SelectionPanel añade una opción explícita layout="inline"; su valor predeterminado responsive conserva exactamente el contrato CSS de recursos. useCompactDetail y el breakpoint inventory siguen disponibles para ese consumidor.

Presupuesto y presentación

Concepto Valor efectivo
Columna de tabla de referencia 800 px
Separación 24 px
Panel 320–400 px
Umbral content box exterior W 1144 px inclusive
Panel cuando cabe clamp(320 px, W − 824 px, 400 px)
Tabla interior en el límite 798 px útiles; 2 px de borde exterior de EntityTable

No se incrementa artificialmente el umbral por las columnas opcionales. Su desbordamiento horizontal permanece dentro de la tabla. Con W inferior al mínimo, el listado ocupa toda la columna y la selección explícita abre AssetDetailDialog, con FormDialog, título y detalle compacto existentes. No queda un panel oculto focusable ni una columna vacía.

El panel inline es un aside cuyo nombre accesible incluye el nombre del activo, con cierre y acciones existentes. No atrapa foco ni bloquea la tabla. Se conservan todos los campos, acordeones, relaciones y permisos del panel existente. El diálogo conserva su contenido e historial; esta entrega no homogeneiza ambos contenidos.

Selección, visibilidad y transiciones

Evento Selección Presentación y foco
Pulsar zona no interactiva de fila Activo pulsado Abre en el modo disponible
Enlace del nombre o Ficha e historial Contrato de ruta existente Ficha completa, sin nueva ruta
Cerrar detalle Se conserva Sin panel ni modal; botón «Mostrar detalle seleccionado»
Inline → overlay Se conserva Cierra detalle; nunca abre modal; foco del panel al botón de reapertura, foco de tabla permanece
Overlay abierto → inline Se conserva Desmonta modal, libera modalidad y muestra panel; foco al cierre del panel
Overlay cerrado → inline Se conserva Permanece cerrado
Cambios dentro del mismo modo Se conserva Sin cambio de visibilidad ni reconstrucción de tabla
Desaparición externa del activo Contrato anterior Aviso existente EntityNotFound, sin inventar una selección alternativa
Borrado confirmado Contrato anterior Limpia selección y detalle solo tras éxito de la mutación

No se ejecutan borrados en la auditoría. La desaparición externa se simula en la respuesta HTTP de la instalación sintética. Un filtro o cambio de página no elimina la selección si el activo sigue en el inventario cargado. Ante desaparición externa se conserva el nodo exterior observado y el aviso previo; si desaparece el elemento enfocado, el contenedor recibe foco para evitar BODY.

Base UI conserva Escape, modalidad y retorno ordinario mediante finalFocus. El destino alternativo local comprueba disparador conectado/habilitado, control de reapertura, búsqueda y contenedor. En el cambio de modal a panel se enfoca el cierre en el siguiente frame, una vez retiradas las guardas/modalidad; el frame se cancela al desmontar o cambiar de estado. No se añade un focus trap ni listeners globales. La edición conserva el contrato V06.

Estabilidad y geometrías

AssetList y su única EntityTable permanecen en la misma posición de React y DOM; no hay claves o ramas de layout que las reconstruyan. Cambiar capacidad no cambia URL, consultas, búsqueda, plantilla, filtros, orden, página ni preferencias de columnas. El scroll vertical se conserva cuando sigue existiendo contenido suficiente; no se promete conservar un desplazamiento superior al nuevo máximo físico tras retirar un panel largo.

Mediciones reales con usuario ordinario, compañía/portátil sintéticos, global predeterminada y compañía fija cuando cabe. Anchos en px; tabla = viewport horizontal interior. Las medidas previas permanecen en before/measurements.json, las nuevas en after/measurements.json.

Viewport W inventario Tabla con detalle antes Panel antes Tabla después Presentación después
1920×1080 1403 977 400 977 Inline, panel 400
1660×900 1143 719 398,39 1141 Overlay
1440×900 1079 707 345,59 1077 Overlay
1366×768 1005 651 327,83 1003 Overlay
1160×800 799 453 320 797 Overlay
1100×800 980 634 320 978 Overlay
1024×768 904 902 Oculto 902 Overlay
920×768 800 798 Oculto 798 Overlay
768×1024 720 718 Oculto 718 Overlay
390×844 358 356 Oculto 356 Overlay
320×640 288 286 Oculto 286 Overlay

En 1660 se evita específicamente confundir viewport amplio con capacidad suficiente: W=1143 queda 1 px por debajo. Compactar manualmente global aumenta W y habilita inline; expandirla lo cierra sin abrir modal. Ocultar/fijar compañía también recalcula la medida. El panel no controla las políticas del shell.

Pruebas, evidencias y límites

Las evidencias locales se guardan en .artifacts/playwright/v01-3/, ignorado por Git. Se utiliza una sola instalación de scripts/visual-audit.py, preparada por los endpoints reales, con login de usuario ordinario y 403 verificado en gestión de usuarios. Cada cliente de auditoría se conecta al servidor MCP Docker fijado en .codex/config.toml; Chromium headless no se instala en WSL. Se bloquean escrituras HTTP en las pruebas visuales.

  • before/ y after/: inventario cerrado y seleccionado en las once resoluciones, 22 estados por fase, geometrías y consola. Se abrieron e inspeccionaron capturas comparativas.
  • Prueba de capacidad: W=1143, 1144, 1145, 1200 y 1224, en el mismo viewport; se mide la caja real y se comprueban mínimos, ausencia de doble detalle y nodo de tabla.
  • Pruebas de foco: contracción con foco en panel y en acción de fila, ampliación con modal abierto, reapertura por teclado, Escape, edición/cancelación y selector anidado.
  • Prueba de estado: fixture HTTP de 41 activos derivada del portátil sintético, sin insertarlos en BD. Se comprueban búsqueda, plantilla, orden descendente, segunda página, columnas, scroll horizontal/vertical y nodo DOM al cruzar cuatro veces el límite.
  • Prueba de desaparición: fixture HTTP vacía y refetch por foco; no borra datos. El enlace nativo sigue abriendo la ficha completa.
  • Regresión: suite existente de navegación V01.1/V01.2, selección V02, asistentes V03, retorno V06 y cabeceras V09. El caso de contraste se ejecuta ahora a 1920 porque el panel inline ya no corresponde a 1440; conserva los mismos estados y colores.

Capturas representativas abiertas e inspeccionadas: 1100 antes, 1100 con diálogo, 1920 inline, 320 con diálogo, límite W=1144, reapertura explícita tras resize rápido. manifest.json registra dimensiones, tamaño y SHA-256 de los PNG, sin información de sesión.

Resultados ejecutados

Comprobación ejecutada Resultado
Playwright MCP, cobertura completa reejecutada en tres grupos 21/21: inventario/foco 6/6, navegación 8/8, componentes/formularios 7/7; sin casos duplicados ni omitidos
Resize durante apertura/animación Tres ciclos rápidos correctos, sin modal residual ni foco en BODY
Resize con edición y selector abiertos Borrador conservado, editor permanece, cancelación con foco alternativo V06; el desplegable de Base UI se cierra al recalcular geometría
Consola de los grupos finales y escenarios adicionales Cero errores y warnings registrados por MCP
Typecheck dirigido assets, rdx-ui y web Correcto
pnpm --filter @metis/assets test 27 ficheros correctos
Inventario ejecutado directamente con Node/tsx 24 pruebas correctas, incluidas capacidad y transiciones
Tests rdx-ui y resources 11 ficheros correctos en cada paquete; contrato predeterminado de recursos conservado
Biome dirigido a los archivos afectados Correcto, sin supresiones
pnpm typecheck Falla en vendor calendar.tsx:165, incompatibilidad locale/exactOptionalPropertyTypes ya documentada
pnpm lint Falla: 15 errores, 1 warning, 4 infos en archivos preexistentes ajenos al diff
pnpm check Falla: 168 errores, 1 warning, 4 infos preexistentes; no se reformatean archivos ajenos
pnpm test con MariaDB temporal independiente Falla: dos expectativas SSR antiguas de compañías («Personas (1)» y aviso de persona sin acceso); 7 tareas correctas de 8 ejecutadas; no se completa la suite global
pnpm build Correcto; aviso existente de chunks mayores de 500 kB
Enlaces locales de los seis documentos afectados 190 comprobados, ninguno ausente

Los fallos globales se contrastaron con los ya documentados en V01.2 y con los archivos sin modificar. Sus logs quedan en technical/. La base de pruebas global se retiró al terminar cada ejecución. Las pasadas intermedias de UI que detectaron foco incorrecto o selectores/eventos inadecuados se conservan como diagnóstico, no se cuentan como aprobadas. La pasada secuencial de 21 casos terminó 20/21 al buscar el panel inicial: el guion no restauraba las anchuras de sus fixtures. Se restituyeron y se espera la medida inicial mediante frames; se añadió una comprobación explícita del modo antes del caso de foco. Se reejecutaron los 21 métodos del runner en tres grupos, incluyendo en el mismo cliente la secuencia de seis casos antes implicada. La pasada anterior no se presenta como aprobada. verification.json enumera los métodos y technical/visual-*.log conserva los resultados finales.

Reproducción

Desde WSL con Node 24 y PNPM fijado en package.json:

python3 scripts/visual-audit.py

Conservar ese preparador abierto y utilizar la ruta privada que imprime, sin copiar el contenido de la sesión:

METIS_PLAYWRIGHT_STORAGE_STATE=.artifacts/playwright/authenticated-XXXX/session.json \
METIS_UI_AUDIT_DIRECTORY=.artifacts/playwright/v01-3/regression \
python3 scripts/visual-audit-ui.test.py
pnpm --filter @metis/assets typecheck
pnpm --filter @repo/rdx-ui typecheck
pnpm --filter @metis/assets test
pnpm --filter @repo/rdx-ui test

Al finalizar esta entrega se envió SIGINT únicamente al preparador identificado por sus logs; terminó correctamente, retiró su BD y eliminó session.json y database.env. Se conservaron los contenedores ajenos y las capturas; comprobación en cleanup.json. Ctrl+C reproduce esa retirada de servicios y sesión del preparador. La suite global pnpm test necesita su propia BD de pruebas desechable, separada de la instalación visual; no usar bases existentes ni sus fixtures para preparar auditorías.

No se afirma cumplimiento WCAG completo, prueba con lector de pantalla, zoom nativo validado ni validación de otros motores/dispositivos físicos. Se conserva el estado de los otros hallazgos. Falta V01.4 para migrar recursos y realizar su regresión; el contrato explícito de SelectionPanel permite hacerlo sin modificar vendor ni duplicar política CSS/React.

Archivos principales

  • modules/assets/src/web/assets/list/helpers/inventory-detail-layout.ts: presupuesto, política y reducer.
  • modules/assets/src/web/assets/list/hooks/use-inventory-detail.ts: único observer, visibilidad y coordinación de foco.
  • use-inventory-page-controller.ts e inventory-page.tsx: selección, composición y reapertura; tabla estable.
  • asset-selection-panel.tsx y asset-detail-dialog.tsx: semántica y finalFocus del detalle existente.
  • packages/rdx-ui/src/components/selection-panel.tsx: variante explícita, predeterminado compatible con recursos.
  • Locales es/en: etiqueta contextual independiente de presentación lateral/modal.
  • inventory.test.tsx y scripts/visual-audit-ui.test.py: pruebas de política y regresión visual.
  • DESIGN.md, patrón de listados, biblioteca de componentes, propuesta V01 y auditoría: contrato actual y seguimiento sin borrar mediciones históricas.

Skills y APIs consultadas

Se leyeron ux-tables (principal: proteger comparación y manipulación), ux-navigation (contexto y foco), shadcn y referencias de composición/Base UI (modalidad y APIs existentes), vercel-composition-patterns (datos frente a presentación) y vercel-react-best-practices, incluida rerender-derived-state (modo discreto, sin estado por píxel). No se impone estética nueva ni se aplica la recomendación genérica de ocultar acciones frente al patrón Metis.

La CLI de documentación shadcn falló por EAI_AGAIN. Se contrastaron la API instalada Base UI 1.8.0 y las documentaciones oficiales de Dialog shadcn/Base UI y Dialog Base UI, sin instalar ni regenerar componentes. No se requirieron frontend-design/ProMax para decisiones estéticas. No están instaladas las skills de auditoría ux-heuristics-audit, ux-accessibility-audit, ux-microcopy-audit, ux-aesthetics-audit, ux-mobile-responsiveness-audit ni ux-information-architecture-audit citadas por las guías. No se instalaron; se aplicaron los criterios disponibles y las verificaciones MCP.

Seguimiento V01.4

Este informe y sus mediciones se conservan como historia. V01.4 extrae el hook a @repo/rdx-ui/hooks/use-contextual-detail y la política a lib/contextual-detail-layout, con activos y recursos como consumidores reales. El fichero de activos conserva el presupuesto 800/24/320–400; su mínimo sigue en 1144. Las 22 geometrías de activos repetidas en V01.4 coinciden con esta entrega. No se conserva una copia del observer específico. El estado vigente y el cierre de V01 se consultan en V01.4.