148 lines
16 KiB
Markdown
148 lines
16 KiB
Markdown
|
|
# V01.2 — Navegación responsive en portátil y tablet
|
|||
|
|
|
|||
|
|
21 de octubre de 2026. Segunda entrega de la [arquitectura B híbrida](propuesta-navegacion-responsive-v01.md). Completa la adaptación de las navegaciones; V01 sigue parcialmente resuelto y quedan pendientes V01.3/V01.4.
|
|||
|
|
|
|||
|
|
## Arquitectura y alcance
|
|||
|
|
|
|||
|
|
La navegación global presenta tres modos: expandida de 228 px, raíl de 72 px y Sheet sin reserva lateral. La navegación de compañía presenta una columna de 240 px o el Sheet existente. Los destinos se comparten entre presentaciones: no se copian los 21 enlaces, contadores, permisos ni consultas. Rutas, filtros y paginación mantienen sus contratos.
|
|||
|
|
|
|||
|
|
`WorkspaceMobileNavigationProvider` amplía el coordinador de V01.1: conserva una sola raíz Sheet y añade la preferencia manual global, intención contextual temporal y modos efectivos. `useWorkspaceCapacity` observa únicamente el contenedor del shell con un ResizeObserver, publica bandas discretas y se desconecta al desmontar. No almacena anchuras en React ni observa tablas o paneles. Las clases/CSS responden al modo publicado; no hay otra colección de umbrales por componente.
|
|||
|
|
|
|||
|
|
Los nombres Mobile de los componentes de V01.1 se mantienen para evitar una migración de rutas/imports ajena a la entrega; sus presentaciones superpuestas ahora se reutilizan también en tablet y portátil.
|
|||
|
|
|
|||
|
|
La columna contextual agrupa identidad, edición, ocultación y destinos en `CompanyFixedNavigation`. `CompanyDetailBody` mantiene el landmark y la identidad de contenido separados de la presentación de menús, con key estable por sección. Su navegación tiene scroll independiente; el contenido conserva una zona principal de scroll. La cabecera es sticky también en escritorio. La franja contextual solo aparece cuando la columna está superpuesta: mantiene compañía, sección y activador sin duplicar una segunda cabecera cuando ya existe columna fija.
|
|||
|
|
|
|||
|
|
El raíl conserva nombres accesibles y tooltips al foco/hover, incluidos compañías y catálogos. Ofrece Menú global y expansión temporal con etiquetas en Sheet. En los tamaños sin raíl el activador está en la cabecera. Búsqueda y cuenta conservan su comportamiento y traducciones es/en.
|
|||
|
|
|
|||
|
|
No se modifica vendor, backend, autenticación, permisos, dependencias, inventario ni selección/detalle de activos y recursos. Los breakpoints `inventory=1100`, `dashboard=1200` y `useCompactDetail` siguen iguales.
|
|||
|
|
|
|||
|
|
## Presupuestos y modos
|
|||
|
|
|
|||
|
|
La fuente única de la política es `workspace-navigation-capacity.ts`. Se contrasta con el ancho **del shell**, sin asumir que coincide siempre con el viewport:
|
|||
|
|
|
|||
|
|
| Capacidad del shell | Global efectiva | Compañía efectiva por defecto |
|
|||
|
|
| --- | --- | --- |
|
|||
|
|
| <920 px | Sheet | Sheet |
|
|||
|
|
| ≥920 y <1160 px | Raíl 72 | Sheet |
|
|||
|
|
| ≥1160 y <1660 px | Raíl 72 | Columna 240 |
|
|||
|
|
| ≥1660 px | 228 o 72 según preferencia | Columna 240 |
|
|||
|
|
|
|||
|
|
Se conserva además la composición de cabecera de 768 px de V01.1: nominal 56 px por debajo y 88 px desde esa anchura. No es otro presupuesto horizontal de navegación.
|
|||
|
|
|
|||
|
|
Las sumas de referencia son 72+48+800=920, 72+240+48+800=1160 y 228+240+48+800+24+320=1660. Los 800 px son una referencia operativa, no un mínimo absoluto para dispositivos físicos ni una nueva política de panel. Bordes y distribución real se registran en la matriz; no se presenta la suma teórica como medición.
|
|||
|
|
|
|||
|
|
La misma política se aplica en dashboard/directorio y compañía, evitando que cambiar de sección expanda/contraiga el raíl automáticamente. Ocultar la secundaria libera 240 px; no fuerza expansión de la global. Abrir el detalle de inventario tampoco altera los modos del shell.
|
|||
|
|
|
|||
|
|
## Preferencias e intención
|
|||
|
|
|
|||
|
|
- Solo se conserva la clave existente `metis-desk:sidebar-collapsed`. `true` solicita raíl; `false`, ausencia o valor inválido conserva la expansión predeterminada cuando cabe.
|
|||
|
|
- La adaptación automática no escribe localStorage. Al recuperar capacidad vuelve a aplicarse la preferencia manual. La acción de contraer/expandir en ancho amplio sigue siendo la única que guarda esa elección.
|
|||
|
|
- Cuando no cabe la global expandida, Expandir menú abre un Sheet temporal: no sustituye la preferencia guardada ni resta ancho al contenido.
|
|||
|
|
- Ocultar secciones conserva una intención temporal en el workspace. Sobrevive a cambios de anchura y de compañía dentro de ese montaje; no se persiste y se reinicia al recargar. Fijar secciones vuelve a la columna cuando cabe.
|
|||
|
|
- Si no cabe la columna, Fijar secciones permanece deshabilitado con explicación. Ganar espacio no sobrescribe una ocultación manual.
|
|||
|
|
- Apertura de Sheet, compañía activa y mediciones no se incorporan a las preferencias. Los errores de acceso/escritura de localStorage mantienen navegación en memoria.
|
|||
|
|
|
|||
|
|
## Foco, modalidad y estabilidad
|
|||
|
|
|
|||
|
|
Base UI mantiene trap, inert y bloqueo del fondo. Los destinos siguen siendo BrowserLink reales: Enter, clic modificado, clic central, URL directa e historial conservan su semántica. Escape/cerrar restaura el origen; navegar de manera ordinaria enfoca el contenido.
|
|||
|
|
|
|||
|
|
Al ensanchar, un menú cuya presentación pasa a fija se cierra y busca el enlace equivalente, o su destino activo. Si continúa necesitando Sheet, permanece abierto. Al estrechar nunca se abre por sí solo: los enlaces o activadores que desaparecen trasladan foco a un control visible equivalente. Si el foco continúa en el contenido o un formulario, se conserva.
|
|||
|
|
|
|||
|
|
La resolución de foco se realiza después del commit, sobre la presentación realmente visible. Los elementos de navegaciones ocultas no forman parte del recorrido de teclado. El cambio contextual → global usa la misma raíz modal, sin dos menús simultáneos ni retorno intermedio al fondo.
|
|||
|
|
|
|||
|
|
Cabecera/franja y foco emplean el offset del shell, scroll-padding y scroll-margin. Los cambios de modo no cambian el key del contenido ni sus filtros, búsqueda, selección o formularios.
|
|||
|
|
|
|||
|
|
## Mediciones antes/después
|
|||
|
|
|
|||
|
|
Línea base: V01.1 cargada por URL directa, una compañía y un activo sintéticos, sin preferencias. Cinco pantallas —dashboard, directorio, resumen, listado y ficha de activo— en once resoluciones: 55 mediciones y capturas por fase. Se esperan fuentes, frames y transiciones antes de medir.
|
|||
|
|
|
|||
|
|
| Resolución | Global / compañía | Ancho main antes → después | Tabla útil después | Y de main después |
|
|||
|
|
| --- | --- | --- | --- | --- |
|
|||
|
|
| 1920×1080 | 228 / 240 | 1452 → 1452 | 1401 | 88 |
|
|||
|
|
| 1660×900 | 228 / 240 | 1192 → 1192 | 1141 | 88 |
|
|||
|
|
| 1440×900 | 72 / 240 | 972 → 1128 | 1077 | 88 |
|
|||
|
|
| 1366×768 | 72 / 240 | 898 → 1054 | 1003 | 88 |
|
|||
|
|
| 1160×800 | 72 / 240 | 692 → 848 | 797 | 88 |
|
|||
|
|
| 1100×800 | 72 / Sheet | 632 → 1028 | 978 | 137 |
|
|||
|
|
| 1024×768 | 72 / Sheet | 556 → 952 | 902 | 137 |
|
|||
|
|
| 920×768 | 72 / Sheet | 452 → 848 | 798 | 137 |
|
|||
|
|
| 768×1024 | Sheet / Sheet | 300 → 768 | 718 | 137 |
|
|||
|
|
| 390×844 | Sheet / Sheet | 390 → 390 | 356 | 106 |
|
|||
|
|
| 320×640 | Sheet / Sheet | 320 → 320 | 286 | 106 |
|
|||
|
|
|
|||
|
|
No se registra overflow horizontal del documento en ninguna de las 55 mediciones posteriores. En los límites nominales la tabla útil mide 797–798 px, 2–3 px menos que la referencia de 800 por bordes/distribución; se mantienen los presupuestos redondos como prioridades, no mínimos absolutos. No se introducen umbrales adicionales para compensar esa diferencia.
|
|||
|
|
|
|||
|
|
El móvil conserva la geometría de V01.1. Los controles intermedios dejan de reservar ambas columnas; no se confunde esta recuperación con la resolución del panel de inventario.
|
|||
|
|
|
|||
|
|
## Pruebas y resultados
|
|||
|
|
|
|||
|
|
Se reutiliza el procedimiento `scripts/visual-audit.py` y el cliente Playwright MCP mediante Docker/Chromium. Se prepara una única instancia sintética de auditoría; la BD de tests globales se aísla en otro contenedor. No se usa la BD local real ni se crean usuarios adicionales para ampliar la cobertura.
|
|||
|
|
|
|||
|
|
`sidebar-preference.test.ts` conserva las pruebas de valores inválidos/almacenamiento inaccesible y añade límites, preferencia frente a modo efectivo e intención contextual. `scripts/visual-audit-ui.test.py` amplía las pruebas ya existentes, sin framework paralelo.
|
|||
|
|
|
|||
|
|
La validación cubre límites a ambos lados, los 21 destinos, teclado, foco, tooltip, preferencias y recarga, ocultación/fijación, resize, conservación de tabla/formulario, scroll independiente, traducciones y nombres largos. Se repiten las regresiones V02/V03/V06/V09 con datos sintéticos. Los intentos fallidos de desarrollo no se cuentan como pasadas aprobadas.
|
|||
|
|
|
|||
|
|
**Suite final completa: 16 pruebas Playwright MCP aprobadas en 453,516 s.** Incluye las regresiones V01.1, V02, V03, V06 y V09. La consola final registra cero errores y cero avisos. La comprobación semántica de orientación confirma compañía y sección visibles en once resoluciones; sus anchos/Y finales coinciden con la matriz posterior tras los últimos ajustes de composición.
|
|||
|
|
|
|||
|
|
Pasan las cinco pruebas ejecutadas directamente de preferencia/capacidad y las doce pruebas de `app.test.tsx`, además del caso dirigido de navegación de compañía es/en. La suite global de Node mantiene dos expectativas antiguas fallidas de `companies-page.test.tsx`; no se confunde el éxito de los casos dirigidos con el éxito de toda la suite.
|
|||
|
|
|
|||
|
|
| Comando / comprobación | Resultado real |
|
|||
|
|
| --- | --- |
|
|||
|
|
| `pnpm --filter @metis/companies typecheck` | Pasa |
|
|||
|
|
| `pnpm --filter @metis/web typecheck` | Pasa |
|
|||
|
|
| Biome dirigido, 20 archivos propios TS/TSX/JSON | Pasa sin errores ni avisos |
|
|||
|
|
| ESLint de espaciado, 18 archivos TS/TSX | Pasa |
|
|||
|
|
| `pnpm build` | Pasa; conserva aviso de chunk grande |
|
|||
|
|
| `pnpm typecheck` | Falla en vendor `calendar.tsx:165`, incompatibilidad locale/exactOptionalPropertyTypes ya documentada; vendor intacto |
|
|||
|
|
| `pnpm lint` | Falla: 15 errores, un aviso y cuatro informaciones en archivos ajenos, como fotos/procesos/migraciones/skills |
|
|||
|
|
| `pnpm check` | Falla: 168 errores, un aviso y cuatro informaciones de formato/reglas globales ajenas; propios comprobados separadamente |
|
|||
|
|
| `pnpm test` con MariaDB aislada | Falla en las expectativas previas «Personas (1)» y «Esta persona no tiene acceso a Metis Desk». Turbo termina con 7 tareas correctas de 8 y no acredita las suites que el fallo interrumpe |
|
|||
|
|
|
|||
|
|
Estos fallos globales ya figuran en el seguimiento del sprint 1 y V01.1; se contrastan los diagnósticos, no se atribuye automáticamente cualquier fallo a deuda previa. Los contenedores de tests se retiraron al finalizar. El preparador visual cerró sus servicios, retiró su BD y borró sesión/credenciales al terminar la auditoría; se conservaron los contenedores previos ajenos. No se corrigen archivos ajenos para conseguir checks globales verdes.
|
|||
|
|
|
|||
|
|
Se reprodujo con una prueba adicional el foco en BODY al desaparecer el activador entre 390→768; después de corregir el reconocimiento de los activadores, pasan los cuatro escenarios de cambio de cabecera/contexto. Se mantienen la prueba fallida previa y la posterior como evidencia de la corrección. También se corrigieron errores del propio guion MCP —ejecución DOM fuera de page.evaluate, nombres de botones y esperas de frames—; no se contabilizan como defectos de Metis ni como pruebas aprobadas.
|
|||
|
|
|
|||
|
|
Para verificar cambio de compañía se creó una segunda compañía exclusivamente en la BD sintética, mediante el formulario real. La excepción HTTP del guion permite solo ese POST de fixture; los demás formularios se cancelan y no se realizan borrados. La matriz antes/después se tomó antes de añadir esa segunda compañía. No se crean usuarios adicionales.
|
|||
|
|
|
|||
|
|
Para repetir, mantener abierto el preparador y usar la ruta privada que imprima:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
METIS_PLAYWRIGHT_STORAGE_STATE=.artifacts/playwright/authenticated-ID/session.json \
|
|||
|
|
METIS_UI_AUDIT_DIRECTORY=.artifacts/playwright/v01-2/after \
|
|||
|
|
python3 scripts/visual-audit-ui.test.py -v
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Sustituir ID por la sesión real. No versionar ni compartir esa sesión.
|
|||
|
|
|
|||
|
|
## Evidencias y límites
|
|||
|
|
|
|||
|
|
Evidencias locales excluidas de Git, bajo `.artifacts/playwright/v01-2/`. Las capturas se abren y examinan: geometría, snapshot y comportamiento no son pruebas intercambiables. Los logs identifican fallos previos y regresiones corregidas de esta entrega.
|
|||
|
|
|
|||
|
|
- [Mediciones antes](../.artifacts/playwright/v01-2/before/measurements.json) y [después](../.artifacts/playwright/v01-2/after-layout/measurements.json), cinco pantallas por once resoluciones.
|
|||
|
|
- [Orientación y geometría finales](../.artifacts/playwright/v01-2/orientation-final.json), identidad y sección visibles en los once tamaños. Los campos auxiliares heredados `identity*` del primer muestreador no se usan para concluir visibilidad: no resuelven la identidad de la nueva composición. Esta comprobación usa franja o encabezado fijo según el modo real.
|
|||
|
|
- [Activos 768 antes](../.artifacts/playwright/v01-2/before/assets-768.png), [después](../.artifacts/playwright/v01-2/after-layout/assets-768.png), [raíl y secundaria en 1440](../.artifacts/playwright/v01-2/after-layout/assets-1440.png), [franja y Sheet contextual en 1024](../.artifacts/playwright/v01-2/final/responsive-context-overlay-1024.png).
|
|||
|
|
- [Tooltip con teclado](../.artifacts/playwright/v01-2/final/responsive-tooltip-focus-1366.png), [último destino y scroll propio](../.artifacts/playwright/v01-2/final/responsive-last-destination-1366.png), [nombre largo](../.artifacts/playwright/v01-2/final/navigation-long-name-1366.png), [segunda compañía](../.artifacts/playwright/v01-2/final/responsive-second-company-768.png).
|
|||
|
|
- [Últimas mediciones interactivas por escenario](../.artifacts/playwright/v01-2/final/summary-latest.json), [consola final](../.artifacts/playwright/v01-2/final/console.json), [índice de capturas](../.artifacts/playwright/v01-2/evidence-index.json) y [log de las 16 pruebas](../.artifacts/playwright/v01-2/technical/visual-ui-final.log). Los subdirectorios de sondeo/desarrollo no sustituyen la suite final.
|
|||
|
|
|
|||
|
|
A 1100 px se conserva el panel de 320 y la tabla queda en 634; a 1024 se conserva el diálogo, de aproximadamente 922 px. [Captura del límite pendiente](../.artifacts/playwright/v01-2/panel-limitation/inventory-selection-1100.png). No se presenta esta tabla todavía estrecha como un problema resuelto por V01.2.
|
|||
|
|
|
|||
|
|
Para compartir evidencia, entregar únicamente el directorio `v01-2/`; excluir `authenticated-*`, sesiones y credenciales. Se revisan las cabeceras PNG y dimensiones al generar el índice. La configuración MCP permanece sin cambios.
|
|||
|
|
|
|||
|
|
No se declara cumplimiento WCAG ni verificación con lector de pantalla. El zoom real de Chromium headless no se considera probado por ampliar la fuente raíz; se conserva esa distinción de V01.1. Tampoco se prueba Cmd+clic en macOS, Docker Desktop/arm64 o todas las combinaciones de roles/compañías/tema oscuro.
|
|||
|
|
|
|||
|
|
V01.3 sigue pendiente: la política actual de panel/diálogo depende del viewport, no de la capacidad del inventario tras las navegaciones. V01.4 —migración de recursos y regresión final global de V01— tampoco se implementa. No se abordan V04–V12.
|
|||
|
|
|
|||
|
|
## Archivos principales y documentación
|
|||
|
|
|
|||
|
|
- Shell: `companies-workspace`, `workspace-sidebar`, `workspace-header`, `workspace-navigation-content`, `workspace-search`, `workspace-navigation-button` y el provider/context de V01.1.
|
|||
|
|
- Política/DOM: `workspace-navigation-capacity.ts`, `use-workspace-capacity.ts` y `workspace-navigation-focus.ts`. El helper de preferencia se mueve, sin cambiar su contrato, de view a shared para que el coordinador no dependa de una operación superior.
|
|||
|
|
- Compañía: `company-detail`, `company-detail-body`, `company-fixed-navigation`, `company-context-bar` y `company-navigation-sheet`.
|
|||
|
|
- Estilos locales de composición en `apps/web/src/global.css`, textos en `common/locales/es.json` y `en.json`, pruebas de preferencias y el guion MCP existente.
|
|||
|
|
- Documentación actualizada: DESIGN, componentes, propuesta V01, seguimiento de auditoría y descripción responsive de rutas. No cambia ningún destino.
|
|||
|
|
|
|||
|
|
## Skills y APIs consultadas
|
|||
|
|
|
|||
|
|
`ux-navigation` dirige orientación, ámbitos, etiquetas y descubribilidad; `frontend-design` conserva jerarquía e identidad existentes; `shadcn` guía Sheet y Tooltip sobre sus APIs instaladas. Las reglas de composición y React sustentan el coordinador compartido, estado mínimo y una suscripción discreta con cleanup. No se consulta Pro Max sin una duda específica ni se genera otra paleta/sistema visual.
|
|||
|
|
|
|||
|
|
La CLI informativa `pnpm dlx shadcn@latest docs sheet tooltip` falla por DNS. Se consultan las [docs de Sheet](https://ui.shadcn.com/docs/components/base/sheet), [Tooltip](https://ui.shadcn.com/docs/components/base/tooltip) y [Dialog/Base UI](https://base-ui.com/react/components/dialog), contrastadas con vendor instalado, sin modificarlo. Los auditores especializados no instalados no se presentan como ejecutados; la comprobación interactiva se realiza con MCP.
|