diff --git a/AGENTS.md b/AGENTS.md index c33ee6e..6fa73ac 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -88,9 +88,7 @@ React, TanStack Query, Tailwind y shadcn/ui (Base UI, estilo Vega). Los componen Estado remoto en TanStack Query; claves centralizadas e invalidación explícita después de mutaciones. No duplicar estado remoto ni usar efectos para derivar valores calculables durante render. Mantener accesibilidad y estados de carga, error, vacío y acciones deshabilitadas. -Los títulos de grupos en todos los diálogos siguen el estilo de «Datos de la plantilla»: `text-xs font-medium uppercase tracking-wide text-muted-foreground`. Reutilizar `FormSectionTitle` de @repo/rdx-ui, también dentro de `FormSection`, conservando el nivel semántico del encabezado. La variante del contenedor no cambia este estilo. Los títulos principales del diálogo y los nombres editables de secciones conservan su tratamiento propio. -Todos los diálogos de selección de tipo `PickerList` utilizan `FormDialog layout="picker"`: altura estable adaptada a la ventana, independiente del número de resultados. La tabla ocupa el espacio disponible con `EntityTable layout="fill"`; búsqueda, filtros, paginación y acciones quedan estables, y los resultados tienen desplazamiento interno con espacio reservado para la barra. En ventanas pequeñas se permite desplazamiento adicional del cuerpo para mantener accesibles todos los controles. -En los diálogos de selección de tipo `PickerList`, la columna del checkbox o radio se sitúa siempre al principio, antes de las columnas de datos, con identificador `selection`, cabecera solo visible para lectores de pantalla y anchura ajustada al control, próxima a la columna del nombre, sin ordenación ni posibilidad de ocultarla. No se trata como columna `actions` ni se ancla a la derecha. Pulsar cualquier punto no interactivo de una fila disponible debe activar/desactivar su checkbox, o seleccionar su radio en modo único. Reutilizar `onRowClick` de la tabla común, respetar las filas deshabilitadas y conservar la navegación por teclado del control. Pulsar directamente el checkbox, radio u otro control debe ejecutar solo su interacción propia, sin duplicar el cambio por propagación. +Todos los diálogos nuevos o modificados siguen el [patrón de diseño de cuadros de diálogo](docs/patron-de-dialogos.md), fuente normativa para títulos uniformes, separación entre grupos, distribución responsive, alturas iguales por fila, secciones plegables, filas compactas, ordenación accesible y selección múltiple. Reutilizar los componentes de @repo/rdx-ui indicados en el patrón. En todos los `PickerList`, mantener altura estable, columna `selection` compacta al principio y selección al pulsar zonas no interactivas de la fila. Aplicar cada pauta según el tipo de contenido; conservar los campos y restricciones propios de cada entidad. Separar componentes por responsabilidades reales, sin fragmentar JSX trivial. Antes de crear o modificar pantallas, reconocer activamente patrones visuales y de interacción comunes entre ellas, así como componentes repetidos dentro de una misma pantalla. Aplicar soluciones coherentes a todos los casos equivalentes, conservando las necesidades propias de cada entidad. Reutilizar y extender la biblioteca visual existente antes de duplicar estructura, estilos o comportamiento. Extraer componentes compartidos cuando haya repetición real: cabeceras, listados, formularios modales, grupos de campos, selectores con alta, estados y ayuda contextual. @@ -224,6 +222,8 @@ Estas reglas complementan las convenciones y documentos de arquitectura existent #### Diálogos, modales y ventanas emergentes +El diseño visual y de interacción sigue [el patrón de diálogos](docs/patron-de-dialogos.md); las siguientes reglas definen la organización de sus componentes. + - Páginas y listados no deben implementar directamente el contenido de ventanas modales funcionales. Los diálogos de alta, edición, confirmación, selección o detalle son componentes independientes. - Toda ventana modal, cuadro de diálogo o formulario modal con contenido y responsabilidad propios debe extraerse a un componente React independiente y vivir en su propio fichero `.tsx`. - Esta regla se aplica especialmente a componentes construidos con primitivas de shadcn/ui como `Dialog`, `AlertDialog`, `Sheet`, `Drawer` o componentes propios como `FormDialog`, pero no depende del nombre concreto utilizado. diff --git a/docs/componentes-de-interfaz.md b/docs/componentes-de-interfaz.md index 220b4f3..006f35b 100644 --- a/docs/componentes-de-interfaz.md +++ b/docs/componentes-de-interfaz.md @@ -9,6 +9,10 @@ consumen mediante `@repo/rdx-ui`. Los componentes que conocen contratos, textos, reglas de Metis viven en el módulo o aplicación que los utiliza; nunca en ninguno de los dos paquetes genéricos. +El [patrón de diseño de cuadros de diálogo](patron-de-dialogos.md) es la fuente normativa +para componer grupos, columnas responsive, filas compactas y selectores. Esta guía describe +los componentes que lo implementan y sus contratos. + ## Componentes actuales - Button: volver a comprobar la conexión. @@ -495,7 +499,7 @@ URLs de vista previa se liberan al cambiar de archivo o desmontar el componente. El alta y la edición de plantillas de activos y recursos agrupan los datos generales con `FormSection` e incorporan campos desde las cabeceras de sus grupos. `TemplateSectionsEditor` permite secciones apiladas o una cuadrícula responsive mediante `sectionLayout="stack" | "responsive"`, con una cabecera numerada sobre fondo diferenciado que contiene el input del nombre, el asa de arrastre y las acciones de orden y eliminación. El cuerpo conserva la descripción y un área de campos separada por un borde. `TemplateSectionEditor` encapsula cada sección con `Collapsible`: todas empiezan abiertas y un botón de cabecera permite plegarlas con ratón o teclado. El nombre, el asa y las acciones siguen visibles al plegar. El contenido permanece montado para conservar los controles; si la validación nativa detecta un control inválido oculto, la sección se abre antes de que el navegador lo enfoque. La apertura se conserva por identidad al reordenar y no se guarda como parte de la plantilla. Los editores de activos y recursos usan la cuadrícula responsive: una columna hasta 1.000 px de ancho disponible y dos a partir de ese umbral, con separación de 16 px y tarjetas de igual altura en cada fila, determinada por la sección más alta. El orden recorre cada fila de izquierda a derecha y se conserva en el DOM, la numeración, el teclado y el arrastre; la altura de cada fila se recalcula al plegar o desplegar sus secciones, manteniendo ambas tarjetas con la misma altura. El bloque «Sin sección» permanece debajo, a ancho completo. -`TemplateSectionFields` muestra un título traducido y el número de campos. Cada campo tiene fondo propio y separa su nombre y acciones de la configuración de obligatoriedad y asignación, cuyo selector conserva una etiqueta visible. Los campos se distribuyen en dos columnas a partir de 700 px de su propio grupo y en una para anchos menores; cada grupo establece su contenedor para evitar columnas demasiado estrechas cuando las secciones se muestran en paralelo. El bloque «Sin sección» se diferencia con borde discontinuo; las secciones vacías conservan un mensaje explícito. Se reutilizan los colores semánticos del tema para mantener el contraste en modo claro y oscuro. +`TemplateSectionFields` muestra un título traducido y el número de campos. Cada campo tiene fondo propio. En la presentación `cards`, separa su nombre y acciones de la configuración de obligatoriedad y asignación, cuyo selector conserva una etiqueta visible; los editores de plantillas de activos y recursos utilizan la presentación `compact` descrita más abajo. Los campos se distribuyen en dos columnas a partir de 700 px de su propio grupo y en una para anchos menores; cada grupo establece su contenedor para evitar columnas demasiado estrechas cuando las secciones se muestran en paralelo. El bloque «Sin sección» se diferencia con borde discontinuo; las secciones vacías conservan un mensaje explícito. Se reutilizan los colores semánticos del tema para mantener el contraste en modo claro y oscuro. ### Orden mediante arrastre y teclado @@ -537,10 +541,28 @@ El alta y la edición de plantillas de activos y recursos reutilizan `TemplateMe ## Títulos de grupos en diálogos -Todos los diálogos con grupos utilizan el estilo de «Datos de la plantilla»: texto pequeño, peso medio, mayúsculas, espaciado entre letras y color atenuado (`text-xs font-medium uppercase tracking-wide text-muted-foreground`). `FormSectionTitle` centraliza esta presentación y recibe `children`, `id` opcional y `as="h3" | "h4" | "h5"` para conservar la jerarquía semántica. El consumidor aporta el texto traducido; las mayúsculas se aplican mediante CSS. +Todos los diálogos con grupos utilizan el estilo de «Datos de la plantilla»: texto pequeño, seminegrita, mayúsculas, espaciado entre letras y color atenuado (`text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-4`). `FormSectionTitle` centraliza esta presentación y recibe `children`, `id` opcional y `as="h3" | "h4" | "h5" | "legend" | "span"` para conservar la semántica del encabezado, leyenda o título dentro de un `summary`. El consumidor aporta el texto traducido; las mayúsculas se aplican mediante CSS. La variante `span` conserva la tipografía y deja el espaciado al `summary` que la contiene, sin margen inferior propio. `FormSection`, `TemplateSectionsEditor` y `TemplateSectionFields` comparten este título, con independencia de sus bordes, acciones o contenido. La regla también se aplica a grupos de consulta, como los puestos del historial de perfiles. Los títulos principales del diálogo y los nombres editables de secciones mantienen su presentación propia. ### Campos compactos en plantillas de activos y recursos `TemplateSectionsEditor fieldLayout="compact"` presenta cada campo en una fila: asa de arrastre, switch de obligatoriedad, nombre flexible, flechas arriba/abajo y papelera. El nombre puede ocupar varias líneas en pantallas estrechas. El switch conserva una etiqueta accesible con «Obligatorio» y el nombre del campo; su texto visual y el selector de sección se omiten. Las notas de campos inactivos siguen disponibles para lectores de pantalla. Se mantienen el arrastre, las flechas por teclado, los límites de orden y los estados deshabilitados. Ambos editores utilizan esta presentación compacta. + +## Ajustes comunes tras la revisión de diálogos + +`FormBody` establece su propio contenedor de consultas de tamaño: las cuadrículas de formularios +y subcontroles utilizan `@min-[560px]` para decidir sus dos columnas según el ancho real del +modal. `FieldSections` aplica la misma regla a los campos y estira los grupos de cada fila +a la altura de su vecino más alto. Los títulos de consulta, grupos de permisos y secciones +desplegables reutilizan `FormSectionTitle`, conservando el estilo vigente del componente. + +`FormActions` admite `cancelDisabled` para conservar el bloqueo de cancelación durante una +confirmación pendiente, además de `leadingActions` para acciones opcionales a la izquierda. +Las confirmaciones de marcas y definiciones de catálogo usan `FormBody` y `FormActions` para +mantener su pie fuera del área desplazable. La selección de compañía del dashboard también +sitúa Continuar en ese pie y lo deshabilita mientras falta una selección o una consulta correcta. + +`SoftwareInstallationEditorDialog`, `SoftwareResourceCreateDialog` y `EntityTableColumnsDialog` +encapsulan sus interacciones en ficheros independientes. Sus consumidores conservan apertura, +selección, datos y callbacks; los formularios y controles mantienen sus contratos anteriores. diff --git a/docs/inventario-de-modales.md b/docs/inventario-de-modales.md index 7073068..d5c3fd2 100644 --- a/docs/inventario-de-modales.md +++ b/docs/inventario-de-modales.md @@ -1,177 +1,171 @@ # Inventario de interacciones modales -Revisión de 2026-10-08. Se inspeccionaron las primitivas y wrappers importados, sus consumidores, -los bloques condicionales y las implementaciones manuales posibles: Dialog, AlertDialog, Sheet, -Drawer, FormDialog, portales, elementos dialog, aria-modal y roles dialog/alertdialog. -La búsqueda no dependió del nombre de los componentes. +Revisión de código de 2026-10-15 según el [patrón de diseño de diálogos](patron-de-dialogos.md). +Se buscaron constructores `FormDialog`, `ConfirmDeleteDialog` y `FieldPickerDialog`, además de +primitivas `Dialog`, `AlertDialog`, `Sheet`, `Drawer`, portales y diálogos manuales. Se revisaron +los formularios, controles compartidos y contenido de consulta que reciben estos constructores. -El código propio contiene **81 componentes que construyen una interacción modal**. Todos -usan FormDialog de @repo/rdx-ui y tienen un componente principal por fichero. Un componente -puede representar variantes de alta, edición o copia, y catálogos con distintos tipos; el número -no es un recuento de todos los estados posibles de las ventanas. No se encontraron otras -implementaciones propias con AlertDialog, Sheet, Drawer ni diálogos HTML/manuales. +El código propio contiene **81 componentes modales en módulos** y **3 constructores +compartidos en @repo/rdx-ui**. El recuento identifica componentes, no cada variante de alta, +edición, copia o estado. Las dos variantes de CatalogFieldPickerDialog son adaptadores del +mismo selector genérico. El código vendor de `packages/shadcn-ui` queda fuera de esta revisión +y no se modifica. -Actualización de 2026-10-09: se añade DeleteBrandDialog para confirmar la eliminación de -marcas personalizadas; el inventario pasa a 82 componentes. Se ha comprobado esta operación -en navegador con API simulada: Cancelar/Escape, errores, bloqueo durante el envío, éxito, -español/inglés y anchura móvil. Esta comprobación no amplía la revisión al resto de modales. +## Resultado de la revisión -La implementación vendor de packages/shadcn-ui queda fuera de la refactorización según AGENTS.md. -Sus primitivas y el diálogo de configuración de tablas se consultan y consumen, no se duplican -ni reorganizan. Los popovers de selectores y menús de acciones no se contabilizan como formularios -o ventanas modales funcionales. +- Los diálogos utilizan la estructura común de cabecera, cuerpo desplazable y pie. Las + confirmaciones de marcas y catálogo se han adaptado al mismo pie fijo, conservando el + bloqueo durante el envío y la presentación de errores. +- Los formularios y sus subcontroles calculan las columnas según su contenedor. Los títulos + de grupos de consulta, permisos y secciones comparten el estilo de Datos de la plantilla. +- Las secciones de plantillas conservan dos columnas cuando hay espacio, igual altura por + fila, plegado, campos compactos, ordenación accesible e incorporación de campos por grupo. +- AssetPickerDialog y los dos CatalogFieldPickerDialog mantienen altura estable, selección + compacta al principio, selección desde la fila y confirmación provisional. Los diálogos + de configuración de columnas son ajustes, no selectores de entidades PickerList. +- Se extrajeron los diálogos de edición de instalaciones de software, alta de su recurso y + configuración de columnas. Los padres mantienen apertura y datos, sin definir el modal. +- Las variantes de selección de compañía del dashboard colocan Continuar en el pie común. + Los formularios sencillos, historiales y ayudas mantienen su tamaño según contenido; las + fechas de revisión y nombres de registros conservan su tipografía de datos, no de grupos. +- Se conservan los pasos de alta de recursos ya existentes: no se ha añadido ningún asistente + para resolver únicamente espacio. Tampoco se añaden cuadrículas a formularios sencillos. -## Responsabilidades y consumidores +## Componentes revisados -Las páginas y listados conservan apertura, selección y callbacks. Los componentes enumerados -encapsulan título, disposición, anchura, contenido y cierre. Los formularios existentes mantienen -sus schemas, borradores, mutaciones, ayuda y errores. EndRelationshipDialog posee además la -mutación de confirmación y sus estados pendientes y de error. +Las rutas siguen la [estructura por entidades y operaciones](estructura-web-por-entidades-y-operaciones.md). +La columna Composición indica el constructor utilizado; las variantes heredan sus reglas comunes. -CompanyEditorDialog, PersonEditorDialog, DepartmentEditorDialog y SiteEditorDialog se reutilizan -el patrón entre catálogo y selector. Los callbacks de selección permanecen en el consumidor que -posee el borrador. Las altas anidadas conservan sus restricciones existentes. +### assets (23) -Se integró el contenido exclusivo de los antiguos SupportHistory, ApplicationHistory, -CertificateHistory y PrinterHistory en sus respectivos componentes de diálogo, tras comprobar -sus referencias. No se eliminaron historiales ni acciones. Los archivos anteriores se pueden -recuperar desde Git. +| Componente | Composición | +| --- | --- | +| [EndRelationshipDialog](../modules/assets/src/web/asset-relationships/end/ui/end-relationship-dialog.tsx) | `FormDialog` | +| [RelationshipEditorDialog](../modules/assets/src/web/asset-relationships/shared/ui/relationship-editor-dialog.tsx) | `FormDialog` | +| [WorkstationAssetCreateDialog](../modules/assets/src/web/assets/create/ui/workstation-asset-create-dialog.tsx) | `FormDialog` | +| [AssetDetailDialog](../modules/assets/src/web/assets/detail/ui/asset-detail-dialog.tsx) | `FormDialog` | +| [AssetPickerDialog](../modules/assets/src/web/assets/select/ui/asset-picker-dialog.tsx) | `FormDialog` · altura estable | +| [AssetEditorDialog](../modules/assets/src/web/assets/shared/ui/asset-editor-dialog.tsx) | `FormDialog` | +| [DeleteAssetDialog](../modules/assets/src/web/assets/shared/ui/delete-asset-dialog.tsx) | `ConfirmDeleteDialog` | +| [DeleteBrandDialog](../modules/assets/src/web/brands/delete/ui/delete-brand-dialog.tsx) | `FormDialog` | +| [BrandEditorDialog](../modules/assets/src/web/brands/shared/ui/brand-editor-dialog.tsx) | `FormDialog` | +| [DeleteCatalogDefinitionDialog](../modules/assets/src/web/catalog/delete/ui/delete-catalog-definition-dialog.tsx) | `FormDialog` | +| [CatalogDefinitionDialog](../modules/assets/src/web/catalog/detail/ui/catalog-definition-dialog.tsx) | `FormDialog` | +| [CatalogEditorDialog](../modules/assets/src/web/catalog/shared/ui/catalog-editor-dialog.tsx) | `FormDialog` | +| [CatalogFieldCreateDialog](../modules/assets/src/web/catalog-fields/create/ui/catalog-field-create-dialog.tsx) | `FormDialog` | +| [CatalogFieldPickerDialog](../modules/assets/src/web/catalog-fields/select/ui/catalog-field-picker-dialog.tsx) | `FieldPickerDialog` · altura estable | +| [CatalogRelationCreateDialog](../modules/assets/src/web/catalog-relations/create/ui/catalog-relation-create-dialog.tsx) | `FormDialog` | +| [CatalogTemplateCreateDialog](../modules/assets/src/web/catalog-templates/create/ui/catalog-template-create-dialog.tsx) | `FormDialog` | +| [DeleteRecordDialog](../modules/assets/src/web/shared/ui/delete-record-dialog.tsx) | `ConfirmDeleteDialog` | +| [SupportHistoryDialog](../modules/assets/src/web/support-connections/history/ui/support-history-dialog.tsx) | `FormDialog` | +| [SupportConnectionEditorDialog](../modules/assets/src/web/support-connections/shared/ui/support-connection-editor-dialog.tsx) | `FormDialog` | +| [SupportResourceCreateDialog](../modules/assets/src/web/support-connections/shared/ui/support-resource-create-dialog.tsx) | `FormDialog` | +| [WorkstationHistoryDialog](../modules/assets/src/web/workstations/history/ui/workstation-history-dialog.tsx) | `FormDialog` | +| [WorkstationEditorDialog](../modules/assets/src/web/workstations/shared/ui/workstation-editor-dialog.tsx) | `FormDialog` | +| [WorkstationLifecycleDialog](../modules/assets/src/web/workstations/shared/ui/workstation-lifecycle-dialog.tsx) | `ConfirmDeleteDialog` | -## Componentes por área +### companies (49) -Las rutas reflejan la [estructura por entidades y operaciones](estructura-web-por-entidades-y-operaciones.md). +| Componente | Composición | +| --- | --- | +| [AccessQuickEditor](../modules/companies/src/web/access/create/ui/access-quick-editor.tsx) | `FormDialog` | +| [QuickCreateDialog](../modules/companies/src/web/access/create/ui/quick-create-dialog.tsx) | `FormDialog` | +| [AccessHelpDialog](../modules/companies/src/web/access/help/ui/access-help-dialog.tsx) | `FormDialog` | +| [AccessHistory](../modules/companies/src/web/access/history/ui/access-history.tsx) | `FormDialog` | +| [AccessEditorDialog](../modules/companies/src/web/access/shared/ui/access-editor-dialog.tsx) | `FormDialog` | +| [ApplicationQuickEditor](../modules/companies/src/web/application-configurations/create/ui/application-quick-editor.tsx) | `FormDialog` | +| [ApplicationHistoryDialog](../modules/companies/src/web/application-configurations/history/ui/application-history-dialog.tsx) | `FormDialog` | +| [ApplicationConfigurationEditorDialog](../modules/companies/src/web/application-configurations/shared/ui/application-configuration-editor-dialog.tsx) | `FormDialog` | +| [AssignmentHistoryDialog](../modules/companies/src/web/assignments/history/ui/assignment-history-dialog.tsx) | `FormDialog` | +| [AssignmentEditorDialog](../modules/companies/src/web/assignments/shared/ui/assignment-editor-dialog.tsx) | `FormDialog` | +| [CertificateQuickEditor](../modules/companies/src/web/certificate-configurations/create/ui/certificate-quick-editor.tsx) | `FormDialog` | +| [CertificateHistoryDialog](../modules/companies/src/web/certificate-configurations/history/ui/certificate-history-dialog.tsx) | `FormDialog` | +| [CertificateConfigurationEditorDialog](../modules/companies/src/web/certificate-configurations/shared/ui/certificate-configuration-editor-dialog.tsx) | `FormDialog` | +| [InventoryQuickCreateDialog](../modules/companies/src/web/companies/detail/ui/inventory-quick-create-dialog.tsx) | `FormDialog` | +| [CompanyEditorDialog](../modules/companies/src/web/companies/shared/ui/company-editor-dialog.tsx) | `FormDialog` | +| [DashboardQuickCreate](../modules/companies/src/web/dashboard/create/ui/dashboard-quick-create.tsx) | `FormDialog` | +| [DashboardDetailsDialog](../modules/companies/src/web/dashboard/detail/ui/dashboard-details-dialog.tsx) | `FormDialog` | +| [DepartmentEditorDialog](../modules/companies/src/web/departments/shared/ui/department-editor-dialog.tsx) | `FormDialog` | +| [FolderQuickEditor](../modules/companies/src/web/folder-mappings/create/ui/folder-quick-editor.tsx) | `FormDialog` | +| [FolderMappingHistoryDialog](../modules/companies/src/web/folder-mappings/history/ui/folder-mapping-history-dialog.tsx) | `FormDialog` | +| [FolderMappingEditorDialog](../modules/companies/src/web/folder-mappings/shared/ui/folder-mapping-editor-dialog.tsx) | `FormDialog` | +| [MailQuickEditor](../modules/companies/src/web/mail-configurations/create/ui/mail-quick-editor.tsx) | `FormDialog` | +| [MailConfigurationHistoryDialog](../modules/companies/src/web/mail-configurations/history/ui/mail-configuration-history-dialog.tsx) | `FormDialog` | +| [MailConfigurationEditorDialog](../modules/companies/src/web/mail-configurations/shared/ui/mail-configuration-editor-dialog.tsx) | `FormDialog` | +| [MailboxUseEditorDialog](../modules/companies/src/web/mailbox-uses/shared/ui/mailbox-use-editor-dialog.tsx) | `FormDialog` | +| [MailboxCreateDialog](../modules/companies/src/web/mailboxes/create/ui/mailbox-create-dialog.tsx) | `FormDialog` | +| [PersonEditorDialog](../modules/companies/src/web/people/shared/ui/person-editor-dialog.tsx) | `FormDialog` | +| [PrinterProfileCreateDialog](../modules/companies/src/web/printer-configurations/create/ui/printer-profile-create-dialog.tsx) | `FormDialog` | +| [PrinterHistoryDialog](../modules/companies/src/web/printer-configurations/history/ui/printer-history-dialog.tsx) | `FormDialog` | +| [PrinterConfigurationEditorDialog](../modules/companies/src/web/printer-configurations/shared/ui/printer-configuration-editor-dialog.tsx) | `FormDialog` | +| [ProcessTemplateEditorDialog](../modules/companies/src/web/process-templates/shared/ui/process-template-editor-dialog.tsx) | `FormDialog` | +| [ProcessQuickCreateDialog](../modules/companies/src/web/processes/create/ui/process-quick-create-dialog.tsx) | `FormDialog` | +| [ProcessStartDialog](../modules/companies/src/web/processes/start/ui/process-start-dialog.tsx) | `FormDialog` | +| [ProcessEditDialog](../modules/companies/src/web/processes/update/ui/process-edit-dialog.tsx) | `FormDialog` | +| [RemoteQuickEditor](../modules/companies/src/web/remote-connections/create/ui/remote-quick-editor.tsx) | `FormDialog` | +| [RemoteConnectionHistoryDialog](../modules/companies/src/web/remote-connections/history/ui/remote-connection-history-dialog.tsx) | `FormDialog` | +| [RemoteConnectionEditorDialog](../modules/companies/src/web/remote-connections/shared/ui/remote-connection-editor-dialog.tsx) | `FormDialog` | +| [ConfigurationQuickEditor](../modules/companies/src/web/shared/ui/configuration-quick-editor.tsx) | `FormDialog` | +| [DeleteRecordDialog](../modules/companies/src/web/shared/ui/delete-record-dialog.tsx) | `ConfirmDeleteDialog` | +| [SiteEditorDialog](../modules/companies/src/web/sites/shared/ui/site-editor-dialog.tsx) | `FormDialog` | +| [SoftwareResourceCreateDialog](../modules/companies/src/web/software-installations/create/ui/software-resource-create-dialog.tsx) | `FormDialog` | +| [SoftwareHistoryDialog](../modules/companies/src/web/software-installations/history/ui/software-history-dialog.tsx) | `FormDialog` | +| [SoftwareInstallationEditorDialog](../modules/companies/src/web/software-installations/shared/ui/software-installation-editor-dialog.tsx) | `FormDialog` | +| [TeleworkAuthorizationHistoryDialog](../modules/companies/src/web/telework-authorizations/history/ui/telework-authorization-history-dialog.tsx) | `FormDialog` | +| [TeleworkAuthorizationEditorDialog](../modules/companies/src/web/telework-authorizations/shared/ui/telework-authorization-editor-dialog.tsx) | `FormDialog` | +| [WorkProfileHistoryDialog](../modules/companies/src/web/work-profiles/history/ui/work-profile-history-dialog.tsx) | `FormDialog` | +| [WorkProfileEditorDialog](../modules/companies/src/web/work-profiles/shared/ui/work-profile-editor-dialog.tsx) | `FormDialog` | +| [WorkProfileLifecycleDialog](../modules/companies/src/web/work-profiles/shared/ui/work-profile-lifecycle-dialog.tsx) | `ConfirmDeleteDialog` | +| [WorkspaceSettingsDialog](../modules/companies/src/web/workspace/settings/ui/workspace-settings-dialog.tsx) | `FormDialog` | -### modules/assets/src/web +### identity (2) -- [AssetDetailDialog](../modules/assets/src/web/assets/detail/ui/asset-detail-dialog.tsx) -- [AssetEditorDialog](../modules/assets/src/web/assets/shared/ui/asset-editor-dialog.tsx) -- [BrandEditorDialog](../modules/assets/src/web/brands/shared/ui/brand-editor-dialog.tsx) -- [DeleteBrandDialog](../modules/assets/src/web/brands/delete/ui/delete-brand-dialog.tsx) -- [CatalogDefinitionDialog](../modules/assets/src/web/catalog/detail/ui/catalog-definition-dialog.tsx) -- [CatalogEditorDialog](../modules/assets/src/web/catalog/shared/ui/catalog-editor-dialog.tsx) -- [CatalogFieldCreateDialog](../modules/assets/src/web/catalog-fields/create/ui/catalog-field-create-dialog.tsx) -- [CatalogFieldPickerDialog](../modules/assets/src/web/catalog-fields/select/ui/catalog-field-picker-dialog.tsx): selección múltiple provisional para añadir campos a una plantilla; reutiliza la tabla común y confirma el lote antes de cambiar el borrador. -- [CatalogRelationCreateDialog](../modules/assets/src/web/catalog-relations/create/ui/catalog-relation-create-dialog.tsx) -- [CatalogTemplateCreateDialog](../modules/assets/src/web/catalog-templates/create/ui/catalog-template-create-dialog.tsx) -- [EndRelationshipDialog](../modules/assets/src/web/asset-relationships/end/ui/end-relationship-dialog.tsx) -- [RelationshipEditorDialog](../modules/assets/src/web/asset-relationships/shared/ui/relationship-editor-dialog.tsx) -- [SupportConnectionEditorDialog](../modules/assets/src/web/support-connections/shared/ui/support-connection-editor-dialog.tsx) -- [SupportHistoryDialog](../modules/assets/src/web/support-connections/history/ui/support-history-dialog.tsx) -- [WorkstationAssetCreateDialog](../modules/assets/src/web/assets/create/ui/workstation-asset-create-dialog.tsx) -- [WorkstationEditorDialog](../modules/assets/src/web/workstations/shared/ui/workstation-editor-dialog.tsx) -- [WorkstationHistoryDialog](../modules/assets/src/web/workstations/history/ui/workstation-history-dialog.tsx) +| Componente | Composición | +| --- | --- | +| [AccountPasswordDialog](../modules/identity/src/web/passwords/change/ui/account-password-dialog.tsx) | `FormDialog` | +| [UserEditorDialog](../modules/identity/src/web/users/shared/ui/user-editor-dialog.tsx) | `FormDialog` | -### modules/companies/src/web/access +### resources (7) -- [AccessEditorDialog](../modules/companies/src/web/access/shared/ui/access-editor-dialog.tsx) -- [AccessHelpDialog](../modules/companies/src/web/access/help/ui/access-help-dialog.tsx) -- [AccessHistory](../modules/companies/src/web/access/history/ui/access-history.tsx) -- [AccessQuickEditor](../modules/companies/src/web/access/create/ui/access-quick-editor.tsx) -- [QuickCreateDialog](../modules/companies/src/web/access/create/ui/quick-create-dialog.tsx) +| Componente | Composición | +| --- | --- | +| [CatalogDefinitionDialog](../modules/resources/src/web/catalog/detail/ui/catalog-definition-dialog.tsx) | `FormDialog` | +| [CatalogEditorDialog](../modules/resources/src/web/catalog/shared/ui/catalog-editor-dialog.tsx) | `FormDialog` | +| [CatalogFieldCreateDialog](../modules/resources/src/web/catalog-fields/create/ui/catalog-field-create-dialog.tsx) | `FormDialog` | +| [CatalogFieldPickerDialog](../modules/resources/src/web/catalog-fields/select/ui/catalog-field-picker-dialog.tsx) | `FieldPickerDialog` · altura estable | +| [CatalogTemplateCreateDialog](../modules/resources/src/web/catalog-templates/create/ui/catalog-template-create-dialog.tsx) | `FormDialog` | +| [ResourceDetailDialog](../modules/resources/src/web/resources/detail/ui/resource-detail-dialog.tsx) | `FormDialog` | +| [ResourceEditorDialog](../modules/resources/src/web/resources/shared/ui/resource-editor-dialog.tsx) | `FormDialog` | -### modules/companies/src/web/application-configurations +### rdx-ui (3) -- [ApplicationConfigurationEditorDialog](../modules/companies/src/web/application-configurations/shared/ui/application-configuration-editor-dialog.tsx) -- [ApplicationHistoryDialog](../modules/companies/src/web/application-configurations/history/ui/application-history-dialog.tsx) -- [ApplicationQuickEditor](../modules/companies/src/web/application-configurations/create/ui/application-quick-editor.tsx) +| Componente | Composición | +| --- | --- | +| [ConfirmDeleteDialog](../packages/rdx-ui/src/components/confirm-delete-dialog.tsx) | `FormDialog` | +| [EntityTableColumnsDialog](../packages/rdx-ui/src/components/entity-table-columns-dialog.tsx) | `FormDialog` | +| [FieldPickerDialog](../packages/rdx-ui/src/components/field-picker-dialog.tsx) | `FormDialog` · altura estable | -### modules/companies/src/web/certificate-configurations +## Validación y límites -- [CertificateConfigurationEditorDialog](../modules/companies/src/web/certificate-configurations/shared/ui/certificate-configuration-editor-dialog.tsx) -- [CertificateHistoryDialog](../modules/companies/src/web/certificate-configurations/history/ui/certificate-history-dialog.tsx) -- [CertificateQuickEditor](../modules/companies/src/web/certificate-configurations/create/ui/certificate-quick-editor.tsx) +La revisión cubre código y render estático mediante las pruebas existentes. Las comprobaciones +interactivas de apertura, Escape, restauración de foco, arrastre, envío, errores y altura visual +en español/inglés y anchos estrecho/amplio quedan pendientes de una sesión de navegador. +No se dispone de una herramienta de navegador en esta sesión; los análisis de código, tipos, +formato y pruebas no sustituyen esa revisión visual. -### Compañías, organización, dashboard y workspace de companies +Resultados de los comandos ejecutados: -- [AssignmentEditorDialog](../modules/companies/src/web/assignments/shared/ui/assignment-editor-dialog.tsx) -- [AssignmentHistoryDialog](../modules/companies/src/web/assignments/history/ui/assignment-history-dialog.tsx) -- [CompanyEditorDialog](../modules/companies/src/web/companies/shared/ui/company-editor-dialog.tsx) -- [ConfigurationQuickEditor](../modules/companies/src/web/shared/ui/configuration-quick-editor.tsx) -- [DashboardDetailsDialog](../modules/companies/src/web/dashboard/detail/ui/dashboard-details-dialog.tsx) -- [DashboardQuickCreate](../modules/companies/src/web/dashboard/create/ui/dashboard-quick-create.tsx) -- [DepartmentEditorDialog](../modules/companies/src/web/departments/shared/ui/department-editor-dialog.tsx) -- [InventoryQuickCreateDialog](../modules/companies/src/web/companies/detail/ui/inventory-quick-create-dialog.tsx) -- [PersonEditorDialog](../modules/companies/src/web/people/shared/ui/person-editor-dialog.tsx) -- [SiteEditorDialog](../modules/companies/src/web/sites/shared/ui/site-editor-dialog.tsx) -- [WorkspaceSettingsDialog](../modules/companies/src/web/workspace/settings/ui/workspace-settings-dialog.tsx) +| Comprobación | Resultado | +| --- | --- | +| Typecheck dirigido a rdx-ui, assets, resources, companies e identity | Correcto | +| Biome y ESLint dirigidos a los archivos de código modificados | Correctos | +| `pnpm build` | Correcto; conserva el aviso de chunks grandes | +| `pnpm test` | UI, activos, recursos, identidad, core y DDD correctos; empresas mantiene el fallo previo de `companies-page.test.tsx` | +| `pnpm typecheck` | Mantiene TS2375 previo en `packages/shadcn-ui/src/components/calendar.tsx:165` | +| `pnpm lint` / `pnpm check` | Mantienen respectivamente 14 y 155 errores previos ajenos al cambio | +| `git diff --check` y enlaces locales de la documentación | Correctos | -### modules/companies/src/web/folder-mappings - -- [FolderMappingEditorDialog](../modules/companies/src/web/folder-mappings/shared/ui/folder-mapping-editor-dialog.tsx) -- [FolderMappingHistoryDialog](../modules/companies/src/web/folder-mappings/history/ui/folder-mapping-history-dialog.tsx) -- [FolderQuickEditor](../modules/companies/src/web/folder-mappings/create/ui/folder-quick-editor.tsx) - - - -### Buzones, usos y configuraciones de correo de companies - -- [MailboxCreateDialog](../modules/companies/src/web/mailboxes/create/ui/mailbox-create-dialog.tsx) -- [MailboxUseEditorDialog](../modules/companies/src/web/mailbox-uses/shared/ui/mailbox-use-editor-dialog.tsx) -- [MailConfigurationEditorDialog](../modules/companies/src/web/mail-configurations/shared/ui/mail-configuration-editor-dialog.tsx) -- [MailConfigurationHistoryDialog](../modules/companies/src/web/mail-configurations/history/ui/mail-configuration-history-dialog.tsx) -- [MailQuickEditor](../modules/companies/src/web/mail-configurations/create/ui/mail-quick-editor.tsx) - -### modules/companies/src/web/printer-configurations - -- [PrinterConfigurationEditorDialog](../modules/companies/src/web/printer-configurations/shared/ui/printer-configuration-editor-dialog.tsx) -- [PrinterHistoryDialog](../modules/companies/src/web/printer-configurations/history/ui/printer-history-dialog.tsx) -- [PrinterProfileCreateDialog](../modules/companies/src/web/printer-configurations/create/ui/printer-profile-create-dialog.tsx) - -### modules/companies/src/web/processes - -- [ProcessEditDialog](../modules/companies/src/web/processes/update/ui/process-edit-dialog.tsx) -- [ProcessQuickCreateDialog](../modules/companies/src/web/processes/create/ui/process-quick-create-dialog.tsx) -- [ProcessStartDialog](../modules/companies/src/web/processes/start/ui/process-start-dialog.tsx) - -### modules/companies/src/web/process-templates - -- [ProcessTemplateEditorDialog](../modules/companies/src/web/process-templates/shared/ui/process-template-editor-dialog.tsx) - -### modules/companies/src/web/work-profiles - -- [WorkProfileEditorDialog](../modules/companies/src/web/work-profiles/shared/ui/work-profile-editor-dialog.tsx) -- [WorkProfileHistoryDialog](../modules/companies/src/web/work-profiles/history/ui/work-profile-history-dialog.tsx) - -### modules/companies/src/web/remote-connections - -- [RemoteConnectionEditorDialog](../modules/companies/src/web/remote-connections/shared/ui/remote-connection-editor-dialog.tsx) -- [RemoteConnectionHistoryDialog](../modules/companies/src/web/remote-connections/history/ui/remote-connection-history-dialog.tsx) -- [RemoteQuickEditor](../modules/companies/src/web/remote-connections/create/ui/remote-quick-editor.tsx) - -### modules/companies/src/web/telework-authorizations - -- [TeleworkAuthorizationEditorDialog](../modules/companies/src/web/telework-authorizations/shared/ui/telework-authorization-editor-dialog.tsx) -- [TeleworkAuthorizationHistoryDialog](../modules/companies/src/web/telework-authorizations/history/ui/telework-authorization-history-dialog.tsx) - - -### modules/identity/src/web - -- [AccountPasswordDialog](../modules/identity/src/web/passwords/change/ui/account-password-dialog.tsx) -- [UserEditorDialog](../modules/identity/src/web/users/shared/ui/user-editor-dialog.tsx) -- [UserManagementDialog](../modules/identity/src/web/users/list/ui/user-management-dialog.tsx) - -### modules/resources/src/web - -- [CatalogDefinitionDialog](../modules/resources/src/web/catalog/detail/ui/catalog-definition-dialog.tsx) -- [CatalogEditorDialog](../modules/resources/src/web/catalog/shared/ui/catalog-editor-dialog.tsx) -- [CatalogFieldCreateDialog](../modules/resources/src/web/catalog-fields/create/ui/catalog-field-create-dialog.tsx) -- [CatalogFieldPickerDialog](../modules/resources/src/web/catalog-fields/select/ui/catalog-field-picker-dialog.tsx): adaptador del selector compartido para incorporar campos al destino y ofrecer alta rápida configurable. -- [CatalogTemplateCreateDialog](../modules/resources/src/web/catalog-templates/create/ui/catalog-template-create-dialog.tsx) -- [ResourceDetailDialog](../modules/resources/src/web/resources/detail/ui/resource-detail-dialog.tsx) -- [ResourceEditorDialog](../modules/resources/src/web/resources/shared/ui/resource-editor-dialog.tsx) - -## Comprobaciones y límites - -Typecheck, lint, pruebas de los módulos y validaciones globales correctos. Las pruebas existentes -comprueban traducciones es/en, listados sin formularios visibles, ayuda, restricciones de altas -anidadas, estados y contratos. Se amplió la prueba del dashboard con datos no vacíos de los -paneles extraídos. - -No se ejecutó una sesión interactiva de navegador. Queda por comprobar manualmente apertura, -Escape, restauración del foco, cancelación, envío y error en modales simples y anidados, en español, -inglés y anchura móvil. El render estático y el lint no sustituyen esa comprobación. - -Véase [revisión de buenas prácticas](revision-de-buenas-practicas.md) para el alcance y los resultados -globales, y [componentes de interfaz](componentes-de-interfaz.md) para los patrones compartidos. - -Los modales de tickets, intervenciones y sus plantillas están [archivados](funcionalidades-archivadas.md). +El fallo de empresas se reprodujo ejecutando directamente el fichero: una prueba de persona +espera el texto «Esta persona no tiene acceso a Metis Desk», ausente en el render actual. +No se ha modificado esa prueba ni el contenido de la ayuda para ocultar el fallo. +Los módulos de tickets, intervenciones y sus plantillas permanecen [archivados](funcionalidades-archivadas.md). diff --git a/docs/patron-de-dialogos.md b/docs/patron-de-dialogos.md new file mode 100644 index 0000000..bd768cd --- /dev/null +++ b/docs/patron-de-dialogos.md @@ -0,0 +1,118 @@ +# Patrón de diseño de cuadros de diálogo + +Fuente normativa para crear o modificar diálogos de Metis Desk. Recoge las decisiones +aplicadas a los editores de plantillas de activos y recursos y a los selectores `PickerList`. +La [guía de componentes](componentes-de-interfaz.md) describe sus APIs y consumidores; +el [inventario de modales](inventario-de-modales.md) recoge las implementaciones existentes. + +## Composición y reutilización + +- Cada interacción modal con responsabilidad propia vive en un componente y fichero `.tsx` + independientes. El padre decide su apertura y aporta datos y callbacks. +- Reutilizar `FormDialog`, `FormBody` y `FormActions` de `@repo/rdx-ui`, apoyados en las + primitivas de shadcn/ui y Base UI. Consultar los patrones existentes antes de crear otro. +- Mantener los bloques visuales genéricos independientes de entidades, DTO, consultas y + endpoints. El módulo aporta textos traducidos, controles, datos y acciones. +- Aplicar el mismo patrón a alta, edición y copia y a entidades equivalentes. Conservar los + campos y restricciones propios de cada entidad, como el uso de las plantillas de recursos. + +## Grupos, títulos y separación + +- Usar `FormSectionTitle` para los títulos de grupo: texto pequeño, seminegrita, mayúsculas, + espaciado entre letras y color atenuado (`text-xs font-semibold uppercase tracking-wide + text-muted-foreground mb-4`). Conservar el nivel semántico del encabezado; las mayúsculas + pertenecen a la presentación CSS y los textos pasan por i18n. +- El título principal del diálogo y los nombres editables de secciones tienen su propia + función. El nombre editable de una sección va en su cabecera, junto a sus acciones. +- Para los datos generales, preferir `FormSection variant="plain"`, sin borde ni relleno de + tarjeta. Los grupos repetidos que necesitan identidad visual usan borde y fondo semánticos + discretos. Evitar acumular marcos y rellenos en grupos anidados. +- Mantener más separación entre grupos principales que entre controles relacionados. En el + patrón de plantillas, `TemplateMetadataSection` deja 36 px antes del grupo de secciones + (20 px del cuerpo y 16 px adicionales); las columnas y tarjetas se separan 16 px. +- Situar las acciones locales en la cabecera del grupo al que afectan. Por ejemplo, + «Añadir campo» se ofrece en «Campos» y lleva implícita la sección de destino. + +## Distribución responsive y alturas + +- Decidir las columnas por el ancho disponible del contenedor, mediante container queries. + En espacios estrechos, apilar el contenido y permitir que nombres y acciones se adapten. +- En formularios con nombre, icono y descripción, reutilizar `TemplateMetadataSection`: + nombre e icono debajo a la izquierda, descripción a la derecha, en dos columnas iguales + desde 560 px. Ambas columnas tienen igual altura y el área de descripción ocupa el alto + restante. En una columna, el recorrido es nombre, icono y descripción. +- Para secciones repetidas equivalentes, usar una columna con poco espacio y dos cuando sus + controles quepan con comodidad. `TemplateSectionsEditor sectionLayout="responsive"` + cambia a dos columnas desde 1.000 px. Las secciones de cada fila tienen la misma altura, + determinada por la más alta, y se reajustan al plegar, desplegar o cambiar su contenido. +- Mantener el orden de izquierda a derecha y de arriba abajo en el DOM, la numeración, + el teclado y el arrastre. No introducir un orden visual diferente mediante CSS. +- Cada grupo de campos responde a su propio ancho, también cuando su sección ocupa media + fila. El bloque «Sin sección» permanece debajo de las secciones, a ancho completo. +- No convertir formularios sencillos en cuadrículas de secciones ni imponerles altura fija. + Los umbrales anteriores corresponden a los componentes citados; otros contenidos deben + elegir su disposición según el espacio que necesitan sus controles. + +## Secciones plegables y filas compactas + +- Las secciones extensas o repetidas utilizan la primitiva `Collapsible` mediante + `TemplateSectionEditor`. Empiezan abiertas y conservan el estado de apertura por identidad + al reordenarse. El nombre, el agarre y las acciones permanecen en la cabecera. +- Conservar los controles al plegar. Si la validación detecta un control inválido oculto, + abrir la sección antes de enfocarlo. Plegar no modifica los datos. +- En listas de configuración de campos, utilizar la presentación compacta + `TemplateSectionsEditor fieldLayout="compact"`: agarre, switch de obligatoriedad, nombre, + flechas de desplazamiento y papelera. Evitar una segunda fila de controles cuando esta + configuración sea suficiente. Esta pauta corresponde a referencias de campos dentro de + una plantilla; los formularios de edición de sus valores conservan sus controles propios. +- Dar nombre accesible a los switches y botones de icono, incluyendo el campo o la sección. + La obligatoriedad conserva su etiqueta accesible y ayuda al pasar el ratón. +- Reutilizar `IconPicker` como desplegable compacto con icono y texto, incluida la opción + sin icono. Evitar una fila permanente con todas las opciones de iconos. + +## Ordenación y selección de campos + +- Reutilizar `useDragReorder`, `ReorderHandle` y el indicador de destino. Mantener flechas + explícitas y ordenación por teclado; el arrastre no es la única forma de cambiar el orden. +- Las secciones se ordenan entre sí y los campos dentro de su sección. Conservar el foco + y bloquear los movimientos imposibles o las acciones durante el guardado. Cancelar un + arrastre no cambia los datos y guardar confirma el borrador del formulario. +- Cuando se incorporen varias referencias de un catálogo, utilizar un selector múltiple + en diálogo en lugar de un desplegable que obligue a añadirlas una a una. En plantillas, + reutilizar `CatalogFieldPickerDialog` desde la cabecera de cada grupo de campos, sin un + bloque independiente de incorporación tras los datos generales. +- Confirmar la selección como lote, conservarla al buscar o paginar y descartar la selección + provisional al cancelar. Respetar límites, disponibilidad y ausencia de duplicados. +- El alta rápida opcional se ofrece a la izquierda del pie mediante `leadingActions`. + Debe poder ocultarse o deshabilitarse desde el consumidor. Mantener el selector y su estado + durante el alta anidada; crear el elemento no confirma por sí solo el lote seleccionado. + +## Diálogos de selección PickerList + +- Todos utilizan `FormDialog layout="picker"` y `EntityTable layout="fill"`: altura estable + adaptada a la ventana, independiente de búsquedas, carga y número de resultados. La tabla + ocupa el espacio restante y mantiene desplazamiento interno con espacio reservado para + la barra; búsqueda, filtros, paginación y acciones permanecen estables. +- Mantener el área de resultados incluso vacía y las cabeceras visibles durante el scroll. + En ventanas pequeñas, permitir el desplazamiento adicional del cuerpo para acceder a + todos los controles. +- La columna `selection` es la primera, antes del nombre: anchura ajustada al checkbox o + radio, poco espacio hasta el nombre y cabecera visualmente oculta con nombre accesible. + No se ordena, no se oculta y no se ancla a la derecha como las acciones. +- Pulsar una zona no interactiva de una fila disponible alterna su checkbox o selecciona + su radio. Reutilizar `onRowClick` de la tabla; los controles internos ejecutan solo su + propia acción, sin duplicar cambios. Respetar filas deshabilitadas y navegación por teclado. + +## Cuerpo, pie y accesibilidad + +- Elegir la anchura del diálogo según su contenido y respetar los márgenes de la ventana. + Mantener cabecera y pie visibles y el cuerpo desplazable cuando el contenido lo requiera. +- Los formularios conservan altura según contenido; la altura estable por resultados es + la regla de los `PickerList`. No introducir pestañas ni pasos para resolver solo espacio. +- Situar ayuda contextual general al final del cuerpo, inmediatamente antes de `FormActions`. + Mantener errores junto al contexto que los origina y las acciones dentro del formulario. +- Conservar foco, cancelación, cierre por teclado, estados de carga, error, vacío y envío. + No cerrar ni limpiar el formulario antes de confirmar una operación correcta. +- Validar los cambios de interacción con pruebas dirigidas y revisar visualmente los anchos + estrecho y amplio, nombres largos, secciones de distinta altura, plegado y resultados vacíos + cuando correspondan. Informar de las comprobaciones que no se hayan podido ejecutar. diff --git a/modules/assets/src/web/asset-relationships/list/ui/asset-relationships.tsx b/modules/assets/src/web/asset-relationships/list/ui/asset-relationships.tsx index e3c97bd..574e54f 100644 --- a/modules/assets/src/web/asset-relationships/list/ui/asset-relationships.tsx +++ b/modules/assets/src/web/asset-relationships/list/ui/asset-relationships.tsx @@ -1,4 +1,5 @@ import { BrowserLink } from "@metis/core/client"; +import { FormSectionTitle } from "@repo/rdx-ui/components/form-section-title"; import { Button } from "@repo/shadcn-ui/components/button"; import { useState } from "react"; import { useTranslation } from "react-i18next"; @@ -65,7 +66,7 @@ export function AssetRelationships(props: AssetRelationshipsProps) { return (
- {!compact &&

{t("relations")}

} + {!compact && {t("relations")}} diff --git a/modules/assets/src/web/assets/detail/ui/asset-detail.tsx b/modules/assets/src/web/assets/detail/ui/asset-detail.tsx index 5d4cdc4..f9dba2c 100644 --- a/modules/assets/src/web/assets/detail/ui/asset-detail.tsx +++ b/modules/assets/src/web/assets/detail/ui/asset-detail.tsx @@ -2,6 +2,7 @@ import { BrowserLink } from "@metis/core/client"; import { DetailField } from "@repo/rdx-ui/components/detail-field"; import { DetailSection } from "@repo/rdx-ui/components/detail-section"; import { FieldSections } from "@repo/rdx-ui/components/field-sections"; +import { FormSectionTitle } from "@repo/rdx-ui/components/form-section-title"; import { useTranslation } from "react-i18next"; import { useAssetDetailController } from "../controllers"; @@ -28,7 +29,7 @@ export function AssetDetail(props: AssetDetailProps) { : String(value); return ( -
+
{!compact &&

{t("snapshotNotice")}

} {!compact && ( @@ -72,9 +73,7 @@ export function AssetDetail(props: AssetDetailProps) {
{!asset.specification.sections?.length && ( -

- {t("characteristics")} -

+ {t("characteristics")} )} -

+ {t("history")} ({asset.history.length}) -

+
    {[...asset.history].reverse().map((revision) => (
  1. @@ -125,7 +124,9 @@ export function AssetDetail(props: AssetDetailProps) { {t("site")}: {nameOf(revision.values.siteId, lookups.sites)}

    - {t("characteristics")} + + {t("characteristics")} + -

    {t("brands.deleteConfirm", { name: brand.name })}

    -

    {t("brands.deleteGuidance")}

    - {mutation.isError && ( -

    - {t(`brands.errors.${errorCode}`, { defaultValue: t("brands.deleteError") })} -

    - )} - - + +

    {t("brands.deleteConfirm", { name: brand.name })}

    +

    {t("brands.deleteGuidance")}

    + {mutation.isError && ( +

    + {t(`brands.errors.${errorCode}`, { defaultValue: t("brands.deleteError") })} +

    + )} +
    + -
    + ); } diff --git a/modules/assets/src/web/catalog/delete/ui/delete-catalog-definition-dialog.tsx b/modules/assets/src/web/catalog/delete/ui/delete-catalog-definition-dialog.tsx index e5ce12a..c2caeca 100644 --- a/modules/assets/src/web/catalog/delete/ui/delete-catalog-definition-dialog.tsx +++ b/modules/assets/src/web/catalog/delete/ui/delete-catalog-definition-dialog.tsx @@ -1,6 +1,5 @@ -import { FormDialog } from "@repo/rdx-ui/components/form-dialog"; +import { FormActions, FormBody, FormDialog } from "@repo/rdx-ui/components/form-dialog"; import { Button } from "@repo/shadcn-ui/components/button"; -import { DialogFooter } from "@repo/shadcn-ui/components/dialog"; import { useTranslation } from "react-i18next"; import type { CatalogItemDTO } from "../../../../common"; @@ -34,17 +33,16 @@ export function DeleteCatalogDefinitionDialog({ open title={t("delete")} > -

    {t("deleteDefinitionConfirm", { name: item.values.name })}

    -

    {t("deleteDefinitionGuidance")}

    - {error &&

    {t(`errors.${code}`, { defaultValue: t("deleteError") })}

    } - - + +

    {t("deleteDefinitionConfirm", { name: item.values.name })}

    +

    {t("deleteDefinitionGuidance")}

    + {error &&

    {t(`errors.${code}`, { defaultValue: t("deleteError") })}

    } +
    + -
    + ); } diff --git a/modules/assets/src/web/support-connections/list/ui/asset-support.tsx b/modules/assets/src/web/support-connections/list/ui/asset-support.tsx index e1a58c4..507939d 100644 --- a/modules/assets/src/web/support-connections/list/ui/asset-support.tsx +++ b/modules/assets/src/web/support-connections/list/ui/asset-support.tsx @@ -1,3 +1,4 @@ +import { FormSectionTitle } from "@repo/rdx-ui/components/form-section-title"; import { Button } from "@repo/shadcn-ui/components/button"; import { useState } from "react"; import { useTranslation } from "react-i18next"; @@ -30,7 +31,7 @@ export function AssetSupport(props: AssetSupportProps) { return (
    - {!compact &&

    {t("support.title")}

    } + {!compact && {t("support.title")}}
    - + <> + + + setAddingCompany(true) }} + id="dashboard-create-company" + label={t("companyLabel")} + onValueChange={setSelectedCompany} + options={ + companies.data?.companies + .filter((item) => item.active) + .map((item) => ({ value: item.id, label: item.name })) ?? [] + } + placeholder={t("dashboard.chooseCompany")} + value={selectedCompany} + /> +

    {t("dashboard.chooseCompany")}

    +
    +
    + + + + )} {addingCompany && ( diff --git a/modules/companies/src/web/folder-mappings/shared/ui/folder-mapping-form.tsx b/modules/companies/src/web/folder-mappings/shared/ui/folder-mapping-form.tsx index 1e56768..2742af4 100644 --- a/modules/companies/src/web/folder-mappings/shared/ui/folder-mapping-form.tsx +++ b/modules/companies/src/web/folder-mappings/shared/ui/folder-mapping-form.tsx @@ -76,7 +76,7 @@ export function FolderMappingForm(props: FolderMappingFormProps) {
    )} -
    +
    -
    +
    -

    {t("people")}

    + {t("people")} diff --git a/modules/companies/src/web/people/shared/ui/person-form.tsx b/modules/companies/src/web/people/shared/ui/person-form.tsx index 90aa11d..469fc2a 100644 --- a/modules/companies/src/web/people/shared/ui/person-form.tsx +++ b/modules/companies/src/web/people/shared/ui/person-form.tsx @@ -53,7 +53,7 @@ export function PersonForm(props: PersonFormProps) { onChange={setPhotoFile} person={person} /> -
    +
    @@ -65,7 +65,7 @@ export function PersonForm(props: PersonFormProps) {
    -
    +
    diff --git a/modules/companies/src/web/printer-configurations/shared/ui/printer-configuration-form.tsx b/modules/companies/src/web/printer-configurations/shared/ui/printer-configuration-form.tsx index bb1bade..c2fc03e 100644 --- a/modules/companies/src/web/printer-configurations/shared/ui/printer-configuration-form.tsx +++ b/modules/companies/src/web/printer-configurations/shared/ui/printer-configuration-form.tsx @@ -52,7 +52,7 @@ export function PrinterConfigurationForm(props: PrinterConfigurationFormProps) {
    -
    +
    -
    +
    void; + onSaved: (id: string) => void; +}) { + const { t } = useTranslation("companies"); + + return ( + { + if (!open) { + onClose(); + } + }} + open + title={t(kind === "os" ? "software.newOs" : "applications.newResource")} + wide + > + + + ); +} diff --git a/modules/companies/src/web/software-installations/list/ui/software-installations-panel.tsx b/modules/companies/src/web/software-installations/list/ui/software-installations-panel.tsx index ebd1ab4..4449fe8 100644 --- a/modules/companies/src/web/software-installations/list/ui/software-installations-panel.tsx +++ b/modules/companies/src/web/software-installations/list/ui/software-installations-panel.tsx @@ -12,7 +12,6 @@ import { EntityStatus, EntityTable, } from "@repo/rdx-ui/components/entity-list"; -import { FormDialog } from "@repo/rdx-ui/components/form-dialog"; import { Button } from "@repo/shadcn-ui/components/button"; import { Checkbox } from "@repo/shadcn-ui/components/checkbox"; import { useId, useState } from "react"; @@ -21,7 +20,7 @@ import { useTranslation } from "react-i18next"; import { DeleteRecordDialog } from "../../../shared/ui/delete-record-dialog"; import { SoftwareHistoryDialog } from "../../history/ui/software-history-dialog"; import { softwareApi, softwareKeys } from "../../shared/api/software-api"; -import { SoftwareInstallationForm } from "../../shared/ui/software-installation-form"; +import { SoftwareInstallationEditorDialog } from "../../shared/ui/software-installation-editor-dialog"; export function SoftwareInstallationsPanel({ companyId, @@ -255,26 +254,15 @@ export function SoftwareInstallationsPanel({ /> )} {editor && assetId && ( - { - if (!open) { - setEditor(undefined); - } - }} - open - title={t(edited ? "software.edit" : "software.new")} - > - setEditor(undefined)} - options={options} - /> - + setEditor(undefined)} + onSaved={() => setEditor(undefined)} + options={options} + /> )} {viewed && ( & { onClose: () => void }) { + const { t } = useTranslation("companies"); + + return ( + { + if (!open) { + onClose(); + } + }} + open + title={t(formProps.installation ? "software.edit" : "software.new")} + > + + + ); +} diff --git a/modules/companies/src/web/software-installations/shared/ui/software-installation-form.tsx b/modules/companies/src/web/software-installations/shared/ui/software-installation-form.tsx index 85ea603..ed8265b 100644 --- a/modules/companies/src/web/software-installations/shared/ui/software-installation-form.tsx +++ b/modules/companies/src/web/software-installations/shared/ui/software-installation-form.tsx @@ -1,7 +1,6 @@ import { zodResolver } from "@hookform/resolvers/zod"; -import { ResourceEditor } from "@metis/resources/client"; import { ContextHelp } from "@repo/rdx-ui/components/context-help"; -import { FormActions, FormBody, FormDialog } from "@repo/rdx-ui/components/form-dialog"; +import { FormActions, FormBody } from "@repo/rdx-ui/components/form-dialog"; import { SelectWithAction } from "@repo/rdx-ui/components/select-with-action"; import { Button } from "@repo/shadcn-ui/components/button"; import { Input } from "@repo/shadcn-ui/components/input"; @@ -14,6 +13,7 @@ import { useTranslation } from "react-i18next"; import type { SoftwareInstallationDTO, SoftwareInstallationInput } from "../../../../common"; import { SOFTWARE_STATE_TRANSITIONS, SoftwareInstallationInputSchema } from "../../../../common"; +import { SoftwareResourceCreateDialog } from "../../create/ui/software-resource-create-dialog"; import { SoftwareApiError, softwareApi, softwareKeys } from "../api/software-api"; export function SoftwareInstallationForm({ @@ -90,7 +90,7 @@ export function SoftwareInstallationForm({ {t("applications.newResource")} )} -
    +
    @@ -160,28 +160,15 @@ export function SoftwareInstallationForm({ {quick && ( - { - if (!open) { - setQuick(undefined); - } + setQuick(undefined)} + onSaved={(id) => { + form.setValue("resourceId", id); + setQuick(undefined); }} - open - title={t(quick === "os" ? "software.newOs" : "applications.newResource")} - wide - > - { - form.setValue("resourceId", id); - setQuick(undefined); - }} - /> - + /> )} ); diff --git a/modules/companies/src/web/telework-authorizations/shared/ui/telework-authorization-form.tsx b/modules/companies/src/web/telework-authorizations/shared/ui/telework-authorization-form.tsx index e1af063..7c05ffe 100644 --- a/modules/companies/src/web/telework-authorizations/shared/ui/telework-authorization-form.tsx +++ b/modules/companies/src/web/telework-authorizations/shared/ui/telework-authorization-form.tsx @@ -54,7 +54,7 @@ export function TeleworkAuthorizationForm(props: TeleworkAuthorizationFormProps) label={t("telework.active")} onCheckedChange={(active) => form.setValue("active", active)} /> -
    +
    )} -
    +
    {selectors.map((selector) => { const fixed = !!profile && selector.field !== "accountId"; diff --git a/modules/resources/src/web/resources/detail/ui/integration-summary.tsx b/modules/resources/src/web/resources/detail/ui/integration-summary.tsx index b60f191..d403e99 100644 --- a/modules/resources/src/web/resources/detail/ui/integration-summary.tsx +++ b/modules/resources/src/web/resources/detail/ui/integration-summary.tsx @@ -30,7 +30,7 @@ export function IntegrationSummary({ })); return ( -
    +
    {entries.map((entry) => (
    {entry.label}
    diff --git a/modules/resources/src/web/resources/detail/ui/resource-detail.tsx b/modules/resources/src/web/resources/detail/ui/resource-detail.tsx index e975267..18d98e0 100644 --- a/modules/resources/src/web/resources/detail/ui/resource-detail.tsx +++ b/modules/resources/src/web/resources/detail/ui/resource-detail.tsx @@ -1,5 +1,6 @@ import { DetailField } from "@repo/rdx-ui/components/detail-field"; import { FieldSections } from "@repo/rdx-ui/components/field-sections"; +import { FormSectionTitle } from "@repo/rdx-ui/components/form-section-title"; import { useTranslation } from "react-i18next"; import type { ResourceDTO, ResourceReferenceDTO } from "../../../../common/inventory"; @@ -25,10 +26,10 @@ export function ResourceDetail({ : String(value); return ( -
    +
    {!compact &&

    {t("snapshotNotice")}

    } {!compact && ( -
    +
    {t("template")}
    {resource.specification.templateName}
    @@ -65,9 +66,9 @@ export function ResourceDetail({ )} {!compact && ( <> -

    + {t("history")} ({resource.history.length}) -

    +
      {[...resource.history].reverse().map((revision) => (
    1. diff --git a/modules/resources/src/web/resources/shared/ui/resource-integration-fields.tsx b/modules/resources/src/web/resources/shared/ui/resource-integration-fields.tsx index ca1c8e5..8e8cf98 100644 --- a/modules/resources/src/web/resources/shared/ui/resource-integration-fields.tsx +++ b/modules/resources/src/web/resources/shared/ui/resource-integration-fields.tsx @@ -32,7 +32,7 @@ export function ResourceIntegrationFields({ if (mailbox) { return ( -
      +
      +
      {(["resourceTypeId", "systemId", "environmentId"] as const).map((key) => { const kind = key === "resourceTypeId" diff --git a/packages/rdx-ui/src/components/confirm-delete-dialog.tsx b/packages/rdx-ui/src/components/confirm-delete-dialog.tsx index e6fd2ae..0ed523c 100644 --- a/packages/rdx-ui/src/components/confirm-delete-dialog.tsx +++ b/packages/rdx-ui/src/components/confirm-delete-dialog.tsx @@ -48,7 +48,7 @@ export function ConfirmDeleteDialog({

      )} - +