diff --git a/AGENTS.md b/AGENTS.md index 6fa73ac..5adb972 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,6 +11,8 @@ No imprimir, copiar ni versionar .env locales o secretos. `packages/shadcn-ui` contiene código de terceros/vendor. No refactorizar, reformatear, reorganizar ni modificar su implementación salvo instrucción explícita del usuario. Puede consultarse su API pública para integrarlo desde código propio. +`archive/` conserva funcionalidades retiradas y sus archivos de integración. No modificar ni aplicarles las convenciones del código activo. Su recuperación se documenta en [funcionalidades archivadas](docs/funcionalidades-archivadas.md). + ## Convenciones El espaciado vertical se define en `.lintrc`, cargado por `eslint.config.mjs`. Separar funciones, clases y métodos con una línea vacía; mantener agrupadas propiedades y firmas de sobrecarga. `pnpm format` combina Biome con estas reglas. Véase [formato y espaciado](docs/formato-y-espaciado-del-codigo.md). @@ -84,7 +86,7 @@ Las fuentes normativas se consultan, no se duplican: Todo código web nuevo de módulos, entidades y operaciones debe seguir [la estructura web por entidades y operaciones](docs/estructura-web-por-entidades-y-operaciones.md): `modules//src/web///`, con ámbitos `shared` según sus consumidores e índices únicamente donde haya contenido exportable para otras unidades. Esta guía es la fuente normativa de la organización interna del frontend; no cambia las capas del servidor ni la implementación vendor. -React, TanStack Query, Tailwind y shadcn/ui (Base UI, estilo Vega). Los componentes compartidos viven en @repo/shadcn-ui. Incorporar TanStack Table y React Hook Form cuando haya consumidores. +React, TanStack Query, Tailwind y shadcn/ui (Base UI, estilo Vega). Los componentes propios compartidos viven en @repo/rdx-ui y reutilizan las primitivas vendor de @repo/shadcn-ui. TanStack Table y React Hook Form ya tienen consumidores; seguir los patrones existentes. 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. @@ -94,7 +96,7 @@ Antes de crear o modificar pantallas, reconocer activamente patrones visuales y 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. Construir progresivamente una biblioteca visual básica con contratos claros, accesibilidad, textos traducibles y composición sencilla. Mantener los componentes genéricos independientes de entidades, DTO, consultas y endpoints de Metis Desk; el módulo consumidor aporta datos, textos y acciones. Documentar patrones y componentes en docs/componentes-de-interfaz.md y en el estándar correspondiente. Preparar esa independencia para poder agrupar o extraer posteriormente componentes en un paquete reutilizable en otras aplicaciones. Aprovechar @repo/shadcn-ui y crear abstracciones conforme aparezcan consumidores reales. -Las pantallas de listado de entidades siguen [el patrón de listados](docs/patron-de-listados-de-entidades.md), reutilizando los componentes comunes de @repo/shadcn-ui. +Las pantallas de listado de entidades siguen [el patrón de listados](docs/patron-de-listados-de-entidades.md), reutilizando los componentes comunes de @repo/rdx-ui y las primitivas de @repo/shadcn-ui. Los listados no muestran formularios de alta ni edición junto a los datos. El alta se inicia con un botón en la cabecera, a la derecha; formularios en modal shadcn/ui como norma general, con anchura y desplazamiento adaptados a su contenido. La edición se abre mediante una acción explícita, siguiendo el mismo criterio. Mantener foco, cierre por teclado, cancelación y errores dentro del formulario. Incluir ayuda contextual con finalidad, ámbito y ejemplos, sin rellenar los campos automáticamente. En formularios, colocar la ayuda en la parte inferior, inmediatamente antes del pie del modal con Guardar y Cancelar. ## Validación y entrega diff --git a/README.md b/README.md index df50524..d065ebd 100644 --- a/README.md +++ b/README.md @@ -21,4 +21,4 @@ Aplicación interna para soporte técnico a pequeñas empresas. - [Traducciones de la interfaz](docs/traducciones.md) - [Alcance y siguientes entregas](docs/plan-de-desarrollo.md) -Incluye acceso, sesiones persistentes, gestión de usuarios y compañías clientes con personas, departamentos, asignaciones con historial y sedes, junto con catálogos informáticos, cuentas, grupos, recursos, permisos y necesidades con cobertura calculada. También incluye inventario configurable, puestos con activos exclusivos y compartidos, perfiles de trabajo por persona y dispositivo, buzones independientes y correo POP/IMAP por perfil con periodos de uso e historial. Las configuraciones del entorno y los tickets se incorporarán progresivamente. +Incluye acceso, sesiones persistentes, gestión de usuarios y compañías clientes con personas, departamentos, asignaciones con historial y sedes, junto con catálogos informáticos, cuentas, grupos, recursos, permisos y necesidades con cobertura calculada. También incluye inventario configurable, puestos con activos exclusivos, perfiles de trabajo por persona y dispositivo, buzones independientes y correo POP/IMAP por perfil con periodos de uso e historial. Incluye configuraciones del entorno, teletrabajo, accesos remotos y procesos de personas. Consultar las [funcionalidades archivadas](docs/funcionalidades-archivadas.md) para el código retirado de la aplicación. diff --git a/docs/arquitectura/pruebas.md b/docs/arquitectura/pruebas.md index 81bc943..3af7259 100644 --- a/docs/arquitectura/pruebas.md +++ b/docs/arquitectura/pruebas.md @@ -8,9 +8,10 @@ Las pruebas verifican comportamiento observable, no detalles internos. - HTTP: middleware, entrada, contratos de salida, estados y autorización. - Frontend: textos traducidos, estados y acciones observables. -Usar el runner nativo de Node.js con tsx. La primera prueba HTTP abre Express en un puerto efímero y usa fetch real. No necesita una base de datos ni espera tiempos arbitrarios. -La prueba web inicial usa renderizado React en servidor para verificar es/en y el estado pendiente. -No sustituye una prueba de interacción en navegador. +Usar el runner nativo de Node.js con tsx. Las pruebas HTTP técnicas abren Express en un puerto efímero y usan fetch real, sin necesitar base de datos. Las pruebas de persistencia utilizan MariaDB y exclusivamente la base de pruebas. No utilizar esperas arbitrarias. +Las pruebas web usan renderizado React en servidor para verificar es/en, estados y contratos observables. No sustituyen una prueba de interacción en navegador. + +`archive/` queda fuera de la suite activa. Las pruebas de retirada comprueban la ausencia de las funciones archivadas y la conservación de los datos de las entidades activas. Comprobaciones transversales: pnpm typecheck, pnpm lint, pnpm test, pnpm check y pnpm build. Si una no se ejecuta o falla, documentar exactamente cuál y por qué. diff --git a/docs/componentes-de-interfaz.md b/docs/componentes-de-interfaz.md index a2c6e38..abb02cf 100644 --- a/docs/componentes-de-interfaz.md +++ b/docs/componentes-de-interfaz.md @@ -582,3 +582,9 @@ un valor esté vacío, de su estado deshabilitado ni de que un booleano sea `fal Los grupos de campos, como permisos, reutilizan `RequiredIndicator` en su leyenda, sin marcar cada checkbox como obligatorio. La configuración de obligatoriedad de las plantillas conserva sus switches y su significado. + +`TemplateFieldSummary` aplica el mismo criterio en la consulta de plantillas: recibe +`requiredLabel` con el texto traducido de obligatoriedad solo si el campo es obligatorio. +Muestra el asterisco junto al nombre y conserva ese texto para lectores de pantalla. +Los campos optativos no muestran indicación de opcionalidad; tipo, unidad y avisos se +mantienen como metadatos de consulta. diff --git a/docs/funcionalidades-archivadas.md b/docs/funcionalidades-archivadas.md index c4bdc27..a516ba8 100644 --- a/docs/funcionalidades-archivadas.md +++ b/docs/funcionalidades-archivadas.md @@ -15,6 +15,13 @@ El código está en [archive/tickets-and-interventions](../archive/tickets-and-i Son referencias para reintegrar, no archivos que deban sobrescribirse. - `manifest.json`: ruta original y SHA-256 de cada archivo conservado. +La comprobación documental del 15 de octubre de 2026 detecta dos entradas cuyo SHA-256 +no coincide con el fichero conservado: `integration/modules/companies/src/common/locales/es.json` +y `integration/modules/companies/src/common/locales/en.json`. Ambos ficheros coinciden con +su versión en Git; la discrepancia del manifiesto ya existía y esta revisión no modifica +el archivo. Las otras 253 entradas coinciden. Revisar esas dos entradas antes de utilizar +el manifiesto como comprobación íntegra de una recuperación. + El archivo queda fuera de los workspaces de PNPM, del ámbito TypeScript y de Biome y ESLint. Ningún archivo activo lo importa. No es un paquete ejecutable ni un flag. diff --git a/docs/prompts/prompt-refactorizacion-general.md b/docs/prompts/prompt-refactorizacion-general.md index c18cb3a..9ec738d 100644 --- a/docs/prompts/prompt-refactorizacion-general.md +++ b/docs/prompts/prompt-refactorizacion-general.md @@ -29,7 +29,7 @@ Debes: - evitar cambios puramente cosméticos sin beneficio real; - evitar introducir nuevas abstracciones innecesarias. -La tarea consiste en revisar TODO el código propio relevante del repositorio, no únicamente los archivos modificados recientemente. +La tarea consiste en revisar TODO el código propio relevante de la aplicación activa, no únicamente los archivos modificados recientemente. Excluye `archive/`: conserva código retirado y referencias de integración, no implementaciones que deban refactorizarse ni instrucciones vigentes. Consulta [funcionalidades archivadas](../funcionalidades-archivadas.md) para su alcance. No te limites a generar un informe de problemas: corrige los problemas que puedan resolverse de forma segura. @@ -716,4 +716,4 @@ No afirmes: - haber corregido un problema que siga presente; - haber ejecutado una comprobación que no hayas ejecutado. -El resultado debe dejar el código propio del repositorio progresivamente alineado con `AGENTS.md`, manteniendo el comportamiento existente y evitando refactorizaciones especulativas. \ No newline at end of file +El resultado debe dejar el código propio del repositorio progresivamente alineado con `AGENTS.md`, manteniendo el comportamiento existente y evitando refactorizaciones especulativas. diff --git a/modules/assets/src/common/locales/en.json b/modules/assets/src/common/locales/en.json index b6f726c..210e2b2 100644 --- a/modules/assets/src/common/locales/en.json +++ b/modules/assets/src/common/locales/en.json @@ -51,14 +51,14 @@ "choose": "Choose a tool", "chooseState": "Choose a status", "newTool": "New tool", - "destination": "Identifier or destination (optional)", + "destination": "Identifier or destination", "requiresVpn": "Requires VPN", "preferred": "Preferred method", "state": "Status", "pending": "Pending configuration", "available": "Available", "retired": "Retired", - "notes": "Notes (optional)", + "notes": "Notes", "empty": "No assistance methods recorded for this asset.", "showRetired": "Include retired methods", "history": "History", @@ -203,9 +203,9 @@ "newTemplate": "New template", "editTemplate": "Edit template", "name": "Name", - "description": "Description (optional)", + "description": "Description", "type": "Data type", - "unit": "Unit (optional)", + "unit": "Unit", "choices": "List values", "choicesHelp": "Enter one value per line. Existing values are retained; you can add others.", "text": "Text", @@ -251,10 +251,9 @@ "view": "View", "close": "Close", "viewDefinition": "{{name}}", - "optional": "Optional", "remove": "Remove field: {{name}}", "noFields": "Add at least one field. All fields are initially optional.", - "fieldHelpText": "Help text (optional)", + "fieldHelpText": "Help text", "fieldHelpHint": "Shown next to the field when creating or editing an asset.", "protected": "Built-in templates and fields can be edited in the global catalog. A field's data type remains fixed. You can change availability or create a template copy for a company.", "helpTitle": "What is it for?", @@ -311,7 +310,7 @@ "title": "Template sections", "add": "Add section", "name": "Section name", - "description": "Description (optional)", + "description": "Description", "ungrouped": "Unsectioned", "moveUp": "Move up", "moveDown": "Move down", @@ -339,7 +338,7 @@ "error": "The record could not be deleted. Please try again." }, "templateIcon": { - "label": "Icon (optional)", + "label": "Icon", "none": "No icon", "help": "Visually identifies the template and its assets. You can change or remove it on custom templates.", "options": { @@ -402,7 +401,7 @@ "broken": "Broken", "technicalStatus": "Technical state", "technicalStatusHelp": "Available and In use are calculated from active workstations. Breakdowns and maintenance retain existing assignments.", - "workstationPersonOptional": "Workstation owner (optional)", + "workstationPersonOptional": "Workstation owner", "workstationNameBySite": "Workstation at {{site}}", "workstationSteps": { "label": "New workstation steps", diff --git a/modules/assets/src/common/locales/es.json b/modules/assets/src/common/locales/es.json index fc82594..c048477 100644 --- a/modules/assets/src/common/locales/es.json +++ b/modules/assets/src/common/locales/es.json @@ -51,14 +51,14 @@ "choose": "Selecciona una herramienta", "chooseState": "Selecciona un estado", "newTool": "Nueva herramienta", - "destination": "Identificador o destino (opcional)", + "destination": "Identificador o destino", "requiresVpn": "Requiere VPN", "preferred": "Método preferido", "state": "Estado", "pending": "Pendiente de configurar", "available": "Disponible", "retired": "Retirado", - "notes": "Notas (opcional)", + "notes": "Notas", "empty": "No hay métodos de asistencia registrados para este activo.", "showRetired": "Mostrar métodos retirados", "history": "Historial", @@ -203,9 +203,9 @@ "newTemplate": "Nueva plantilla", "editTemplate": "Editar plantilla", "name": "Nombre", - "description": "Descripción (opcional)", + "description": "Descripción", "type": "Tipo de dato", - "unit": "Unidad (opcional)", + "unit": "Unidad", "choices": "Valores de la lista", "choicesHelp": "Escribe un valor por línea. Los valores existentes se conservan; puedes añadir otros.", "text": "Texto", @@ -251,10 +251,9 @@ "view": "Ver", "close": "Cerrar", "viewDefinition": "{{name}}", - "optional": "Opcional", "remove": "Retirar campo: {{name}}", "noFields": "Añade al menos un campo. Todos son opcionales inicialmente.", - "fieldHelpText": "Texto de ayuda (opcional)", + "fieldHelpText": "Texto de ayuda", "fieldHelpHint": "Se muestra junto al campo al crear o editar un activo.", "protected": "Las plantillas y campos de serie se pueden editar desde el catálogo global. El tipo de dato de un campo se mantiene fijo. Puedes cambiar la disponibilidad o crear una copia de una plantilla para una compañía.", "helpTitle": "¿Qué es y para qué sirve?", @@ -311,7 +310,7 @@ "title": "Secciones de la plantilla", "add": "Añadir sección", "name": "Nombre de la sección", - "description": "Descripción (opcional)", + "description": "Descripción", "ungrouped": "Sin sección", "moveUp": "Mover hacia arriba", "moveDown": "Mover hacia abajo", @@ -339,7 +338,7 @@ "error": "No se ha podido eliminar el registro. Inténtalo de nuevo." }, "templateIcon": { - "label": "Icono (opcional)", + "label": "Icono", "none": "Sin icono", "help": "Identifica visualmente la plantilla y sus activos. Puedes cambiarlo o quitarlo en las plantillas personalizadas.", "options": { @@ -402,7 +401,7 @@ "broken": "Averiado", "technicalStatus": "Estado técnico", "technicalStatusHelp": "Disponible y En uso se calculan según los puestos activos. Una avería o mantenimiento conserva las asignaciones existentes.", - "workstationPersonOptional": "Responsable del puesto (opcional)", + "workstationPersonOptional": "Responsable del puesto", "workstationNameBySite": "Puesto en {{site}}", "workstationSteps": { "label": "Pasos del nuevo puesto", diff --git a/modules/assets/src/web/asset-relationships/shared/ui/relationship-form.tsx b/modules/assets/src/web/asset-relationships/shared/ui/relationship-form.tsx index a446502..4316821 100644 --- a/modules/assets/src/web/asset-relationships/shared/ui/relationship-form.tsx +++ b/modules/assets/src/web/asset-relationships/shared/ui/relationship-form.tsx @@ -1,8 +1,8 @@ import { ContextHelp } from "@repo/rdx-ui/components/context-help"; import { FormActions, FormBody } from "@repo/rdx-ui/components/form-dialog"; +import { FormLabel } from "@repo/rdx-ui/components/form-label"; import { SelectWithAction } from "@repo/rdx-ui/components/select-with-action"; import { Button } from "@repo/shadcn-ui/components/button"; -import { Label } from "@repo/shadcn-ui/components/label"; import { Textarea } from "@repo/shadcn-ui/components/textarea"; import { useId } from "react"; import { useTranslation } from "react-i18next"; @@ -39,7 +39,9 @@ export function RelationshipForm(props: RelationshipFormProps) {
- + + {t("relationshipType")} + setQuick(true) }} disabled={mutation.isPending || catalog.isPending} @@ -56,7 +58,9 @@ export function RelationshipForm(props: RelationshipFormProps) { />
- + + {t("targetAsset")} +
- + {t("notes")}