Mismo formato que ya existia en Proyectos. Ordenable por columna; no cambia el orden por
defecto (sigue siendo el orden manual arrastrado con el mouse).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Hook reutilizable useDragReorder (drag & drop nativo HTML5, sin
libreria nueva) usado en dos lugares: ListView (opt-in via onReorder,
deshabilitado mientras haya un ordenamiento por columna activo) para
el listado de actividades de un proyecto, y el listado de tareas de
una actividad. Orden persistido en sort_order (activities y tasks,
migracion 012, posiciones siempre 1..N).
Fix real encontrado durante las pruebas: sincronizar el estado interno
del hook por la REFERENCIA del arreglo de entrada entraba en loop
infinito de renders cuando el llamador pasa "algo || []" (un arreglo
nuevo en cada render mientras los datos cargan). Corregido para
sincronizar por el contenido (ids), no por referencia.
Probado en dev con curl (persistencia del orden) y Playwright
(arrastrar filas en el navegador, orden visible y guardado
correctamente, sin errores de consola tras el fix).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
No existia forma de borrar una actividad. Agregado DELETE
/api/activities/:id con boton "Eliminar" en el listado (popup de
confirmacion). Si tiene tareas, se bloquea con 400 y mensaje claro en
vez de arrastrar todo en cascada sin avisar.
De paso: la logica de borrar adjunto (fila + archivo en disco) se
extrajo a un attachments/service.js reutilizable, usado tanto por el
borrado individual como por el borrado en cascada de una actividad
(evita archivos huerfanos). Comentarios de la actividad tambien se
limpian (sin FK fisica cruzada, entity_type/entity_id es polimorfico).
Probado en dev con curl (bloquea con tarea, permite sin tareas, 404
tras borrar) y Playwright (mensaje de advertencia visible).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Auditoria completa del frontend: quedaban 2 lugares con el mismo antipatron que
ya se habia corregido en Proyectos/Departamentos/Usuarios/Catalogos.
- ProjectActivitiesTab: "Nueva actividad" se apilaba debajo del listado de
actividades. Ahora abre en su propio DetailPopup, igual que el resto.
- ProjectInfoTab (pestaña Info de un proyecto): el combo "agregar miembro" se
apilaba debajo de la lista de miembros. Ahora hay un boton "Agregar miembro"
en el encabezado de esa tarjeta que abre un DetailPopup chico.
Con esto no queda ningun listado del sistema con un formulario apilado debajo:
todos usan DetailPopup (ver regla en project-md-templates/UI-UX-WINDOWS.md).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Las 11 pantallas con listado/detalle bloqueaban TODO su render con
"if (loading || !data) return <Cargando/>". Como useAsync pone loading=true en
cada reload (no solo en la carga inicial), cualquier accion dentro de un
DetailPopup abierto que dispara un reload del padre (agregar subtarea, agregar
dependencia, guardar comentario, etc.) desmontaba momentaneamente TODA la
pantalla -y con ella el popup y su estado interno (pestaña activa)-, que volvia
a montarse desde cero con sus valores iniciales.
Sintoma reportado: al agregar una subtarea (Enter o boton "Nuevo"), el popup de
la actividad volvia a la pestaña Info en vez de quedarse en Subtareas.
Fix: la guarda ahora es solo "if (!data)" -bloquea unicamente la carga
inicial, cuando todavia no hay nada que mostrar-. Las recargas subsiguientes
actualizan el contenido en el sitio sin desmontar nada.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
El detalle de un item de listado (actividad, departamento, usuario, proyecto nuevo,
catalogo) ya no se apila debajo ni al costado del listado: ahora abre en un popup que
cubre la ventana, deja el listado inactivo detras, nunca se cierra con clic afuera (solo
con el boton Cerrar o una accion explicita del formulario) y mantiene un alto FIJO por
instancia para que cambiar de pestaña interna (Info/Subtareas/Dependencias/Comentarios/
Documentos) no reajuste su tamaño.
De paso corrige un bug real de stacking: ContentDialog no usaba portal a document.body,
así que un dialogo de confirmacion abierto desde dentro de un DetailPopup quedaba oculto
detras de este. Ahora ambos son portales con una jerarquia de z-index explicita
(Flyout 100 < DetailPopup 200 < ContentDialog 250 < Toast 300).
En el detalle de actividad, Subtareas y Dependencias pasan de estar apiladas dentro de la
pestaña Info a ser cada una su propia pestaña.
Regla documentada en project-md-templates/UI-UX-WINDOWS.md (componente DetailPopup) para
que aplique a futuros proyectos de escritorio Windows del grupo.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>