metis-desk/docs/componentes-de-interfaz.md

14 KiB

Componentes de interfaz

Metis Desk usa shadcn/ui, con Base UI y el estilo base-vega, siguiendo la organización de factuges-erp. Los componentes viven en packages/shadcn-ui y se consumen mediante el paquete @repo/shadcn-ui. El código se genera desde el registro oficial y queda versionado en este repositorio, sin depender del ERP.

Componentes actuales

  • Button: volver a comprobar la conexión.
  • Card: bloques de información y estado.
  • Select: idioma y selección de sistemas, entornos, cuentas, personas y demás relaciones, con navegación por teclado.
  • Input y Label: credenciales y datos de usuario.
  • Checkbox: estado activo de usuarios, compañías, personas y departamentos.
  • Table: listados de usuarios, compañías, personas y departamentos.
  • Textarea: dirección opcional de las sedes, con varias líneas.
  • Dialog: formularios de alta y edición, con foco y cierre por teclado. FormDialog comparte el título y la cancelación traducidos.

Convención de navegación

Los listados presentan datos, búsqueda y acciones. El botón de alta se coloca en la cabecera, a la derecha. Los formularios se abren en modal como norma general, con anchura adaptable y desplazamiento si el contenido lo requiere. No mostrar formularios junto al listado. Las ediciones se abren mediante una acción explícita. Compañías, personas, departamentos, asignaciones, sedes y usuarios siguen este criterio. Las personas, los departamentos y las asignaciones se crean y editan en modales. El historial se consulta en un diálogo. Catálogos, cuentas, grupos, recursos, permisos y necesidades siguen la misma convención. Los permisos de una necesidad se eligen mediante casillas shadcn/ui.

TanStack Table filtra el listado de compañías por nombre; React Hook Form gestiona los formularios con los contratos Zod compartidos.

El paquete exporta componentes individuales. Importar solo el componente necesario:

import { Button } from "@repo/shadcn-ui/components/button";

El tema se define una sola vez en packages/shadcn-ui/src/styles/globals.css. La aplicación importa ese CSS y declara las fuentes de Tailwind de los módulos y del paquete compartido. Usar tokens semánticos como bg-background, text-foreground y border-border en vez de repetir colores por pantalla.

Añadir componentes

Desde la raíz del proyecto, dentro de WSL:

pnpm --filter @repo/shadcn-ui ui:add input

El CLI está fijado en package.json. Revisar los archivos y dependencias añadidos antes de validar. No usar --overwrite sin revisar las adaptaciones locales. apps/web/components.json también permite al CLI localizar el paquete compartido desde la aplicación.

Después de generar código, separar los imports de tipos con import type y ejecutar las comprobaciones del proyecto. No añadir todo el catálogo ni crear envoltorios sin una necesidad concreta.

Dependencias

Base UI proporciona interacción accesible y gestión del foco. class-variance-authority define variantes del botón; cn combina clases de Tailwind. lucide-react aporta los iconos del selector y tw-animate-css sus transiciones. shadcn es una herramienta de desarrollo; su hoja de estilos común se incorpora al compilar.

Guías oficiales: monorepos e instalación manual.

Ayuda contextual

ContextHelp muestra una explicación breve y permite desplegar ejemplos y recomendaciones mediante teclado. EntityHelp aporta contenido específico en español e inglés para compañías, personas, departamentos, sedes, asignaciones y todas las secciones de cuentas y accesos. Los catálogos explican si la definición es global o exclusiva de la compañía. Los ejemplos son orientativos: nunca se convierten en valores del formulario.

El botón Ayuda de Cuentas y accesos y Catálogos informáticos permite consultar la explicación de la sección sin abrir un alta. La misma ayuda aparece dentro de los modales de alta y edición. FormDialog utiliza una variante amplia para personas y formularios con más campos; el número de campos no cambia la navegación a una página propia.

La ayuda de los formularios se coloca en su parte inferior, inmediatamente antes de FormActions. Este pie compartido reúne Guardar y Cancelar dentro del formulario, conservando el envío y el cierre accesible del diálogo. Los diálogos de consulta mantienen únicamente Cerrar.

SelectWithAction: desplegable con acción integrada

El componente compartido vive en @repo/shadcn-ui/components/select-with-action. Compone Select, Button y ButtonGroup de shadcn/ui (Base UI, Vega). Presenta selección y botón «+» como un único grupo visual, manteniendo controles separados para teclado y lectores de pantalla. ButtonGroup utiliza fieldset para expresar semánticamente la agrupación.

Su contrato recibe id, etiqueta, opciones, placeholder, valor controlado y callback de selección. La acción es opcional y contiene etiqueta accesible, callback y estado deshabilitado. Admite opciones deshabilitadas, estado inválido, descripción accesible y obligatoriedad. Deshabilitar el selector también deshabilita la acción. El botón usa type=button y no envía el formulario.

No conoce compañías, HTTP, formularios ni modales: esas responsabilidades pertenecen al consumidor. No contiene textos propios que deban traducirse.

Formularios que permiten alta rápida

Sistema permite crear un sistema propio de la compañía mediante un modal adicional. Entorno permite crear un entorno para el sistema activo seleccionado; su acción no aparece antes de elegir un sistema. Los campos fijos en edición no ofrecen alta rápida. Uso y otros valores cerrados tampoco ofrecen altas.

QuickCreateDialog conserva los valores del formulario principal, actualiza el catálogo y selecciona el nuevo UUID después de guardar. Usa las rutas, protección CSRF y reglas de negocio existentes. Un nombre activo ya existente permite usar ese registro sin duplicarlo. Cancelar el modal adicional conserva la cuenta sin cambios. El elemento creado permanece en el catálogo aunque se cancele después la cuenta.

La ayuda aparece antes del pie con Guardar y seleccionar / Cancelar. Solo hay un nivel de alta adicional; el nuevo formulario no vuelve a ofrecer altas rápidas.

La revisión de los formularios extiende este patrón a personas, departamentos, cuentas, grupos, recursos, tipos de recurso, permisos y plantillas. Las asignaciones de departamento permiten añadir el primero sin abandonar el formulario. Se reutilizan los formularios y rutas existentes, manteniendo su validación y ayuda inferior.

Los entornos necesitan un sistema activo seleccionado. Los permisos nuevos heredan el tipo del recurso elegido. Al crear un grupo desde una pertenencia, sistema y entorno quedan fijados a los de la cuenta. Las plantillas siguen siendo globales; el modal lo explica y carga únicamente sus opciones globales. Los elementos creados desde un selector están activos para poder seleccionarlos.

Uso de cuenta, estado de configuración e idioma son listas cerradas. Las referencias históricas de cobertura (necesidad, autorización, titularidad y pertenencia) conservan sus operaciones propias. Los campos inmutables en edición no ofrecen altas. Los permisos múltiples de una necesidad continúan como casillas.

El catálogo de activos utiliza SelectWithAction para añadir campos a una plantilla y crearlos mediante un modal adicional. Los tipos de dato constituyen una lista cerrada. Las definiciones de serie se consultan en modales de lectura; su personalización se realiza mediante copias.

El inventario añade altas rápidas de plantilla, sede y persona en los activos. La plantilla creada desde un activo solo ofrece campos existentes para mantener un único nivel adicional de modal. Las características utilizan controles según su tipo; los valores sí/no conservan un estado vacío distinto de No.

Listados de entidades

El estándar se define en Patrón de listados de entidades, con inventario de pantallas y excepciones. EntityListHeader, EntityTable, EntityRowActions, EntityAction y EntityStatus viven en @repo/shadcn-ui/components/entity-list.

EntityTable recibe datos y columnas tipadas; utiliza TanStack Table para búsqueda, ordenación, visibilidad y paginación local. Admite búsqueda y filtros controlados por el módulo, conservando su semántica y ámbito. Las columnas de identificación y acciones quedan visibles. Los menús utilizan Base UI y conservan los callbacks de las acciones originales. No realiza peticiones ni conoce DTO de negocio.

La paginación es local sobre los conjuntos que las API actuales ya devuelven. No simula paginación de servidor. La selección del activo para el panel sigue perteneciendo a Inventario, fuera de la tabla compartida.

EntityTable separa internamente la configuración de columnas/ordenación, el contenido semántico y la paginación; useEntityTable concentra el estado de representación. entityLabel permite contar «plantillas», «campos» o «tickets» aunque el título del espacio sea más amplio. Los tamaños disponibles son 10, 25, 50 y 100; una opción vacía nunca cambia el tamaño a cero.

Se declara @tanstack/react-table en el paquete compartido porque es quien consume ahora la librería; se reutiliza la versión 8.21.3 que ya utilizaba Compañías. No se introduce un segundo sistema de tablas.

Catálogo de marcas y selector funcional

BrandCatalogPage reutiliza EntityListHeader/EntityTable con búsqueda, filtro de estado, columnas, ordenación y paginación. BrandEditorDialog compone FormDialog y BrandForm tanto para la gestión global como para las altas relacionadas; el formulario conserva ContextHelp y FormActions.

BrandSelect, dentro del módulo assets, adapta SelectWithAction al catálogo remoto: filtra marcas activas, conserva la selección inactiva actual y textos anteriores, ofrece alta rápida y respeta una sola anidación. El borrador padre se conserva y la nueva marca se selecciona por UUID. El componente genérico no conoce BrandDTO, consultas ni endpoints. Véase Catálogo global de marcas.

Componentes modales de los módulos

El inventario de modales localiza las interacciones de alta, edición, copia, confirmación, detalle, historial, selección, ayuda y configuración, incluyendo las altas rápidas dentro de otros formularios. La regla normativa de organización reside en AGENTS.md.

Las páginas coordinan apertura, selección y callbacks. El componente modal posee su estructura y la lógica que le pertenece; el formulario mantiene validación, borrador, errores y guardado. Se reutilizan FormDialog y FormActions sin modificar su implementación vendor. Los diálogos específicos de entidades viven junto a sus consumidores, no en la biblioteca visual genérica.

CompanyEditorDialog, PersonEditorDialog, DepartmentEditorDialog, SiteEditorDialog, BrandEditorDialog y SupportToolEditorDialog se reutilizan donde ya existen operaciones equivalentes. Los callbacks de guardado actualizan la selección del consumidor; no se cierra un formulario por el mero inicio de una mutación. Los historiales de consulta se derivan de los datos remotos actuales, mientras que los borradores de edición permanecen locales.

Acciones de fila ancladas

EntityRowActions muestra un botón icon-sm con EllipsisIcon, etiqueta accesible y título traducidos, sin texto visible repetido. EntityTable reserva la identidad de columna actions para operaciones: siempre visible, sin búsqueda/ordenación y fijada a la derecha mediante columnPinning de TanStack Table. EntityTableContent renderiza primero las columnas de datos y después la columna anclada, con cabecera/celdas sticky right-0, alineación derecha, anchura compacta y fondo opaco para evitar solapamientos al desplazar la tabla. Todos los listados consumidores heredan este comportamiento.

Tarjetas de indicadores

StatisticCard (@repo/shadcn-ui/components/statistic-card) representa un indicador con etiqueta, valor, icono y tinte discreto. Admite carga/error, evita sustituir datos desconocidos por cero y utiliza un botón con foco visible cuando hay navegación. No depende de DTO ni endpoints. Inicio la reutiliza para sus cinco KPI; la organización de bloques y sus estados permanece local al dashboard.

Shell global

App conserva el acceso y el selector de idioma. CompaniesWorkspace compone sidebar, header global y contenido con los destinos y estado de navegación existentes. El header solo aparece en sesiones autenticadas. Los catálogos se seleccionan en la sidebar; la navegación interna de cada compañía permanece en CompanyDetail.

Los tokens --desk-* de apps/web/src/global.css aíslan la paleta del shell de los colores semánticos del resto del producto: superficie negra exterior, contenido #F7F9FB, sidebar #0E282C, acento turquesa, texto y borde azul, radios 8/10/20px, sidebar 228px, header 88px, búsqueda 41px, fila de navegación 48px y avatar 35px. En móvil se conserva la navegación horizontal y envuelta, sin introducir drawer.

El buscador usa Input de shadcn/ui y filtra compañías cargadas y destinos globales; Escape limpia y los resultados se recorren mediante Tab. No existe un servicio de búsqueda transversal de entidades. La campana no muestra avisos ficticios: no existe servicio de notificaciones. El perfil usa disclosure nativo con foco visible y conserva las acciones de identidad y selección de idioma. No hay primitives Avatar ni DropdownMenu instalados; el avatar muestra iniciales del usuario real, sin inventar foto ni cargo. Configuración abre un FormDialog con las acciones existentes.

La sidebar global permite contraerse en escritorio de 228px a 72px mediante «Contraer menú» / «Expandir menú». Conserva iconos, nombres accesibles y títulos de ayuda también para compañías y subcatálogos. La navegación se desplaza por separado, manteniendo Configuración y el control de anchura en el pie visible. En móvil se conserva la navegación horizontal existente.

El menú expandido y su pie comparten márgenes horizontales de 20px mediante --desk-sidebar-inset. El header global usa --desk-header-background (#FFFFFF), con un borde inferior de 1px en --desk-border, sobre el contenido #F7F9FB.