# Patrón de listados de entidades Estándar de Metis Desk. Fuente funcional: patrón acordado con el usuario en esta conversación. La referencia de Activos conserva el estilo Vega, los tokens semánticos y la ficha lateral real de la aplicación. Los listados nuevos y sus operaciones deben aplicar la [estructura web por entidades y operaciones](estructura-web-por-entidades-y-operaciones.md). El listado pertenece a `/list/ui`; sus altas, detalles e historiales a sus operaciones respectivas. Los formularios y diálogos comunes de alta y edición pertenecen a `/shared/ui`, no al fichero del listado ni a un directorio global de componentes. ## Estructura obligatoria La pantalla se divide en cabecera, contenido y pie opcional. La cabecera muestra título y subtítulo breve a la izquierda y acciones globales a la derecha. El alta es la acción primaria, normalmente «+ Añadir [entidad]», y abre un modal; se conservan las etiquetas actuales cuando ya describen una operación concreta. Nunca mostrar el formulario junto al listado. El título y el botón de alta muestran el mismo icono de entidad antes del texto, tomado del catálogo `@repo/rdx-ui/lib/icons` y coherente con la navegación. Activos utiliza `BoxIcon`, Recursos `LayersIcon`, Personas `PersonIcon`, Perfiles de usuario `WorkProfileIcon` y Puestos `MonitorIcon`. `EntityListHeader.icon` presenta el icono del título a 24 px, sin encogerse; el botón reutiliza el tamaño de icono de `Button`. Ambos son decorativos (`aria-hidden`), conservando el texto y el nombre accesible. No sustituir el icono de entidad por un signo «+» ni añadir ambos. Esta pauta se aplica también a catálogos, configuraciones y sublistados con alta propia; las demás acciones conservan su representación. El contenido contiene una tabla y cuatro bandas, en este orden: 1. Búsqueda rápida a la izquierda y filtros propios de la entidad a la derecha. El texto indica los campos buscables. Cuando hay criterios aplicados, Limpiar filtros restaura los valores iniciales de la pantalla; no cambia el ámbito de compañía ni el perfil desde el que se ha navegado. 2. Información «Mostrando X-Y de N [entidades]» a la izquierda; Columnas y Ordenar por a la derecha. Estos controles cambian la representación, no los filtros ni los datos. 3. Cabeceras y filas de la tabla, con densidad uniforme. Los estados vacíos siguen dentro de esta banda. 4. Información del mismo rango repetida a la izquierda; anterior, páginas, siguiente y elementos por página a la derecha. El pie opcional está fuera de la tabla y solo aparece cuando existe contenido complementario útil. No añadir estadísticas ni decoración sin una necesidad funcional. ## Reglas de interacción - Búsqueda y filtros se combinan; filtrar o cambiar tamaño de página vuelve a la primera página. Si una actualización reduce resultados, se ajusta la página para no mostrar un rango inexistente. - Contar los resultados filtrados antes de paginar. Cero resultados se expresa como 0-0 de 0. La ordenación actúa sobre todos los resultados filtrados antes de paginar y mantiene un orden estable para empates. - Columnas configurables mediante controles con etiquetas; identificación y acciones no se ocultan. No se pierde acceso a una acción por ocultar otra columna. La configuración es local a la vista y no se guarda en datos de negocio. - Solo ofrecer ordenación para valores con significado comparable. Todo listado ordenable comienza con una columna ordenada e indicada mediante `aria-sort` y el selector de ordenación. El criterio común es la primera columna ordenable en ascendente: Nombre en usuarios, activos y catálogos; Persona en teletrabajo y accesos remotos; Departamento en asignaciones. Cada listado puede declarar un criterio propio mediante `defaultSort`. Las cabeceras alternan ascendente/descendente y «Orden inicial» restaura el criterio del listado. - El identificador principal abre la ficha existente si hay una. Usar enlace si existe una ruta real; botón si abre diálogo, detalle en memoria o panel. No inventar rutas. - Representar estados mediante indicador visual y texto, nunca solo color. Mantener los avisos de revisión e información contextual. - Las relaciones son navegables cuando el destino ya ofrece navegación adecuada; no introducir enlaces ficticios ni nuevas rutas. - Acciones de fila siempre al final, con cabecera y celdas alineadas a la derecha y columna anclada al borde derecho durante el desplazamiento horizontal. La columna actions no se oculta ni se ordena. La acción principal se presenta como botón de icono con tooltip y nombre accesible, antes del menú de tres puntos. Usar el lápiz para Editar y el ojo para Abrir o Ver; elegir la operación según la finalidad de cada listado. La principal no se repite en el menú. Las acciones secundarias, incluidas las destructivas, permanecen en el desplegable, cuyo disparador muestra únicamente los tres puntos y conserva etiqueta accesible y título. Si no hay secundarias, no mostrar el desplegable. Conservar las restricciones y los estados deshabilitados existentes. Reutilizar `EntityRowActions.primaryAction`; el consumidor aporta el icono, el texto traducido y el callback. No convertir acciones de negocio en acciones masivas. - Selección múltiple solo cuando una operación real la necesita. No añadir casillas sin consumidor. Mantener separada la selección del activo para su panel lateral. - Los diálogos `PickerList` mantienen una altura estable mediante `FormDialog layout="picker"` y llenan el área de resultados con `EntityTable layout="fill"`. Buscar, paginar, cargar o quedarse sin resultados no cambia la altura del diálogo. Búsqueda, filtros, paginación y acciones permanecen fuera del desplazamiento de resultados; el cuerpo permite desplazamiento adicional si la ventana es demasiado pequeña. - En diálogos `PickerList`, la selección ocupa siempre la primera columna, con identificador `selection`, sin ordenación ni ocultación y sin anclaje a la derecha. Toda fila disponible permite activar/desactivar su checkbox o seleccionar su radio mediante `onRowClick`. Las filas deshabilitadas no cambian la selección; los controles internos conservan su interacción y el teclado, sin un segundo cambio por propagación del clic. - Cancelar un modal conserva búsqueda, filtros, página y selección de la lista. Las actualizaciones continúan invalidando las consultas actuales. - Las consultas que alimentan un listado usan `useListQuery`: se vuelven a consultar cada 60 segundos mientras la pestaña está visible y también al recuperar foco o conexión. No se consulta en segundo plano ni se aplica este intervalo a formularios, sesión u otras consultas que no presenten un listado. Cuando un listado filtra familias mediante pestañas, utilizar `ScrollableTabsList` de `@repo/rdx-ui` dentro de `Tabs`. La barra mantiene una sola fila limitada al ancho del listado, con desplazamiento horizontal, controles laterales solo cuando sean necesarios y la pestaña activa visible. Mantener `min-w-0` en la raíz y el contenido para que ni las etiquetas ni la tabla ensanchen la página. La selección conserva las reglas de URL, filtros y paginación del listado. Véase [pestañas horizontales desplazables](componentes-de-interfaz.md#pestañas-horizontales-desplazables). ## Celdas sin valor En cualquier listado, tabla, sublistado o PickerList, una celda sin valor muestra exclusivamente un guion largo (`—`, U+2014), cualquiera que sea la causa de la ausencia. No mostrar «Sin indicar», «Sin valor», «Sin especificar», «Sin asignación», «Sin fecha», «Sin logotipo» ni equivalentes en otros idiomas. El signo es común a es/en y no requiere traducción. `EntityTable` aplica este criterio cuando `render` devuelve `null`, `undefined`, un booleano sin representación visual, una cadena vacía o formada solo por espacios, un array vacío o un fragmento sin contenido. Los consumidores deben devolver ausencia directamente en lugar de envolverla en componentes vacíos o convertirla en textos sustitutorios. Los renderizadores de contenido compuesto son responsables de aplicar el mismo criterio a sus valores opcionales. El cero y los valores reales permanecen visibles; los booleanos de negocio se presentan con sus etiquetas o estados correspondientes. Se mantienen los estados de negocio explícitos, por ejemplo «Inactivo» o «Abierto». Esta pauta se refiere a celdas de datos y no sustituye los mensajes de carga, error, ausencia de registros o búsqueda sin resultados, ni los placeholders de formularios. ## Común y específico Común: distribución, cabecera, cuatro bandas, márgenes, altura base de filas, búsqueda, limpieza, contador, columnas, ordenación, paginación, accesibilidad y estados. Específico: título, subtítulo, ámbito, alta y acciones globales, campos buscables, filtros, columnas, formatos, acciones de fila, avisos y destino de ficha. Las columnas conservan la información funcional de cada pantalla. Licencias y aplicaciones continúan dentro del listado Recursos; no crear pantallas para entidades que no existen. ## Responsive, accesibilidad y estados Cabecera y bandas se apilan en anchuras pequeñas. Los filtros ajustan sus controles, la tabla permite desplazamiento horizontal dentro de su contenedor y las celdas largas pueden partir texto. Mantener la navegación del espacio de compañía y el panel de activos en escritorio, con la ficha modal móvil existente. Usar tabla semántica con nombre accesible, th con scope, controles etiquetados, foco visible, acciones por teclado y página actual con aria-current. Los elementos decorativos se ocultan al lector. Los menús y modales conservan manejo de foco de Base UI. No depender del color para comunicar información. Carga inicial y errores se presentan dentro del contenido sin afirmar que no hay registros. El vacío distingue ausencia de datos y búsqueda sin resultados. Mantener el mensaje y la recuperación de errores de cada consulta; no inventar resultados ni endpoints. Las recargas conservan datos y controles cuando la integración existente lo permite. ## Inventario de listados y ubicaciones actuales La aplicación navega por espacios y secciones mediante rutas URL independientes, según [Rutas del cliente](rutas-del-cliente.md). Los componentes siguientes se componen desde CompaniesWorkspace, CompanyDetail o IdentityWorkspace; altas, ediciones e historiales conservan sus modales. | Listado / ámbito | Componente y ubicación actual | Aplicación | | --- | --- | --- | | Compañías | [CompaniesPage](../modules/companies/src/web/companies/list/ui/companies-page.tsx) | Sí | | Personas/contactos | [PeopleSection](../modules/companies/src/web/people/list/ui/people-section.tsx) | Sí | | Departamentos | [DepartmentSection](../modules/companies/src/web/departments/list/ui/department-section.tsx) | Sí | | Sedes | [SiteSection](../modules/companies/src/web/sites/list/ui/site-section.tsx) | Sí | | Usuarios internos | [UserManagement](../modules/identity/src/web/users/list/ui/user-management.tsx) | Sí | | Activos | [AssetInventoryPage](../modules/assets/src/web/assets/list/ui/inventory-page.tsx) | Sí; conserva panel lateral | | Puestos de trabajo | [WorkstationsPage](../modules/assets/src/web/workstations/list/ui/workstations-page.tsx) | Sí | | Recursos, incluidas aplicaciones y licencias | [ResourcesPage](../modules/resources/src/web/resources/list/ui/resources-page.tsx) | Sí; pestañas por plantilla y «Todo», panel lateral y ficha modal móvil | | Campos y plantillas de recursos, global/compañía | [ResourceCatalogPage](../modules/resources/src/web/catalog/list/ui/catalog-page.tsx) | Sí; dos secciones | | Campos, plantillas y relaciones de activos, global/compañía | [AssetCatalogPage](../modules/assets/src/web/catalog/list/ui/catalog-page.tsx) | Sí; tres secciones | | Cuentas y accesos / catálogos informáticos | [AccessWorkspacePage](../modules/companies/src/web/access/list/ui/access-workspace.tsx) | Sí; cuenta, titularidad, grupo, pertenencia, autorización, necesidad, cobertura, entorno, sistema, tipo, permiso y plantilla | | Perfiles de usuario | [WorkProfilesPage](../modules/companies/src/web/work-profiles/list/ui/work-profiles-page.tsx) | Sí | | Correo por perfil | [MailConfigurationsPage](../modules/companies/src/web/mail-configurations/list/ui/mail-configurations-page.tsx) | Sí, también entrada desde perfil | | Carpetas por perfil | [FolderMappingsPage](../modules/companies/src/web/folder-mappings/list/ui/folder-mappings-page.tsx) | Sí, también entrada desde perfil | | Impresoras por perfil | [PrinterConfigurationsPage](../modules/companies/src/web/printer-configurations/list/ui/printer-configurations-page.tsx) | Sí, también entrada desde perfil | | Aplicaciones por perfil | [ApplicationConfigurationsPage](../modules/companies/src/web/application-configurations/list/ui/application-configurations-page.tsx) | Sí, también entrada desde perfil | | Certificados por perfil | [CertificateConfigurationsPage](../modules/companies/src/web/certificate-configurations/list/ui/certificate-configurations-page.tsx) | Sí, también entrada desde perfil | | Teletrabajo | [TeleworkAuthorizationsPage](../modules/companies/src/web/telework-authorizations/list/ui/telework-authorizations-page.tsx) | Sí, conserva ámbito de persona | | Accesos remotos | [RemoteConnectionsPage](../modules/companies/src/web/remote-connections/list/ui/remote-connections-page.tsx) | Sí, conserva ámbito de persona | | Procesos de personas | [ProcessesPage](../modules/companies/src/web/processes/list/ui/processes-page.tsx) | Sí; su detalle es excepción | | Plantillas de procesos | [ProcessTemplatesPage](../modules/companies/src/web/process-templates/list/ui/process-templates-page.tsx) | Sí | | Marcas globales | [BrandCatalogPage](../modules/assets/src/web/brands/list/ui/brands-page.tsx) | Sí; EntityListHeader y EntityTable, filtro de estado y modales | | Asignaciones departamentales | PeopleSection → PersonDetails | Sublistado de ficha; conserva sus operaciones y adopta tabla común | Los enlaces apuntan a las ubicaciones actuales bajo `modules//src/web//`. No hay listados separados de equipos, software, incidencias o ubicaciones adicionales: corresponden a Activos, Recursos o Sedes. ## Excepciones justificadas No son pantallas de listado sencillo: HomePage (estado técnico), WorkEnvironmentPage (resumen de preparación), fichas CompanyDetail/PersonDetails/AssetDetail/ResourceDetail, historiales y revisiones, pasos/instrucciones de plantillas, tareas de ProcessDetail y selectores de formularios. AssetRelationships, AssetSupport, MailboxRelations son bloques contextuales de ficha, sin gestión independiente de un conjunto; mantienen su presentación contextual. CompanyInventory es un adaptador de consultas, no un listado adicional. Las barras laterales, navegación, formulario de acceso y cambio de contraseña tampoco adoptan el patrón. Las instrucciones/historiales que antes estaban expandidos dentro de catálogos se mantienen accesibles desde cada fila; no desaparecen por pasar a tabla. ## Implementación y verificación Se reutilizan los componentes propios de @repo/rdx-ui, incluidos SelectWithAction y EntityTable, sobre Table, Button, Input, Dialog y los tokens existentes de @repo/shadcn-ui. Las consultas, DTO, endpoints, permisos y mutaciones permanecen en sus módulos. Los componentes comunes no conocen entidades ni invocan API. La validación debe incluir tipos, estilo, pruebas y compilación, además de interacción real para búsqueda/limpieza, columnas, ordenación, cambios de página/tamaño, apertura/cancelación de fichas y panel de activos. Verificar español e inglés y una anchura móvil. ### Migración realizada Se han adaptado las 25 familias de listados del inventario y el sublistado de asignaciones departamentales. Los catálogos y accesos reutilizan sus componentes para las distintas secciones y ámbitos; las rutas distinguen el ámbito sin crear nuevas entidades. El inventario conserva la ficha lateral y su modal móvil. Las fichas, historiales y bloques contextuales de las excepciones mantienen su función. Componentes compartidos: EntityListHeader y EntityTable; EntityTableConfiguration para columnas y orden; EntityTableContent para tabla semántica; EntityListPagination, EntityRowActions, EntityAction y EntityStatus para controles. useEntityTable concentra filtros locales, ordenación estable, columnas visibles y paginación. entity-list.ts contiene textos es/en y cálculo de rangos. No se añade selección masiva sin una operación que la consuma. La primera columna tiene anchura mínima para evitar nombres ilegibles. El desplazamiento horizontal permanece dentro de la tabla. El panel de activos ajusta su contenido y sus botones a la anchura disponible. ### Verificación de la entrega (7 de octubre de 2026) - pnpm typecheck: correcto, 10 tareas. - pnpm test: correcto, 195 pruebas, incluidas HTTP/MariaDB en la base de pruebas; 9 tareas. Las nuevas pruebas cubren límites de paginación, rangos repetidos, búsqueda local/controlada, traducción y distinción de carga/error/vacío. - pnpm build: correcto, 2 tareas. Se mantiene el aviso de tamaño del paquete web. - pnpm lint y pnpm check: ejecutados; siguen fallando por problemas previos ajenos a la migración. La comprobación específica de todos los archivos de código modificados y nuevos es correcta. No se han añadido supresiones. - Navegador: revisadas todas las familias de pantallas y las secciones de cuentas/accesos; búsqueda, filtros específicos y limpieza, columnas bloqueadas/configurables, ordenación y recuperación del orden inicial, segunda página, tamaño de página y opción vacía. - Navegación comprobada a persona y activo; edición/copia en modal y cancelación sin guardar. Las definiciones de serie no ofrecen edición y las plantillas globales no ofrecen edición desde una compañía. - Español/inglés y anchura móvil de 390 px comprobados; el activo abre la ficha modal en móvil. En escritorio la página no presenta desbordamiento horizontal; la tabla conserva su propio desplazamiento. - No se han creado ni alterado registros de negocio durante la revisión del navegador. ### Ajuste inicial de acciones de fila (7 de octubre de 2026) La regla vigente de acción principal visible figura en Reglas de interacción; este apartado registra la verificación del ajuste inicial. Disparador solo con icono de tres puntos, etiqueta accesible y título conservados. Columna actions siempre al final, compacta, alineada y anclada a la derecha; no admite ocultación, búsqueda u ordenación. El fondo opaco respeta hover, menú abierto y selección del inventario. Verificación: 204 pruebas correctas, tipos y compilación correctos; los cinco archivos de código/estilos de este ajuste pasan Biome. Las comprobaciones globales conservan los errores anteriores. En navegador se han comprobado apertura/cancelación de edición, botón sin texto, posición de cabecera y celdas antes y después del desplazamiento horizontal a anchura móvil, y color del activo seleccionado. No se modificaron registros de negocio durante la revisión. ### Selector de activos Los formularios que seleccionan activos usan un diálogo con el mismo `AssetList` del inventario. Reutiliza `EntityTable`, búsqueda, pestañas por plantilla, columnas y paginación. La selección provisional no cambia el formulario hasta confirmar, ni altera la URL o filtros del listado padre. Cada consumidor restringe los candidatos y declara selección única o múltiple con límite. Véase [componentes de interfaz](componentes-de-interfaz.md#selección-de-activos-en-diálogo). Tickets, intervenciones y sus plantillas se conservan en [el archivo de funcionalidades](funcionalidades-archivadas.md), fuera del inventario activo. ### Columna visual del tipo de activo En `AssetList`, el icono de plantilla ocupa una columna `icon` compacta antes de Nombre, con cabecera accesible y tooltip con el nombre de plantilla, disponible con puntero y teclado. La columna Plantilla conserva solo el nombre. La columna visual no se ordena ni se oculta y no sustituye la ordenación inicial por Nombre. En `PickerList`, la selección permanece siempre por delante del icono.