The metrics JSON uses 'discos' (array) not 'disco' (single object),
so disk alerts were never firing. Also reports per-mountpoint label.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
La API devuelve HTTP 200 con code:"401" para credenciales inválidas.
Ahora el service retorna error cuando code != "0".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
El error "unmarshal: invalid character '<'" ocultaba qué devolvía
LabsMobile. Ahora el error incluye Content-Type y los primeros 200
bytes del cuerpo para diagnóstico.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Problema raíz:
1. El ping TCP usaba Servidor.IpServidor → fallaba si la BD solo escucha
en localhost del servidor remoto (comportamiento normal en producción)
2. La reactividad Alpine v3.13 no detectaba keys nuevas en objeto vacío {}
dentro de x-for loops, spinner nunca aparecía
Cambios:
- pkg/models/conx_db.go: nuevo campo Host (vacío = usa Servidor.IpServidor)
+ método HostEfectivo() como fuente única de verdad para host
- pkg/services/query_runner_service.go: todos los puntos (openDynamicDB,
openDynamicDBWithName, redisConnect, mongoURI) usan c.HostEfectivo()
- rest/controllers/servidor_controller.go: PingConexion reescrito —
primero prueba conexión real a la BD (no solo TCP), si falla prueba TCP,
devuelve host+puerto testeado y mensajes de error descriptivos
- servidor_dashboard.html: hacerPing usa spread-replace para forzar
reactividad + $nextTick, resultado muestra host:puerto testeado y
mensaje de error completo en múltiples líneas
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Backend:
- Agrega github.com/redis/go-redis/v9 como dependencia
- isRedisDriver() detecta 'redis' y 'valkey' en nombre del tipo de BD
- redisConnect(): abre cliente Redis con auth, host, port, db index
- redisTestConnection(): PING para probar conexión
- redisListDatabases(): lee CONFIG GET databases → devuelve db0..dbN
- redisListKeys(): SCAN iterativo, hasta 200 keys del db seleccionado
- redisExecuteCommand(): parsea comandos línea a línea, multi-comando
devuelve tabla command/result/error; comando único devuelve QueryResult
tipado (string, int64, []any para KEYS/SMEMBERS/LRANGE, HGETALL como
field/value table)
- redisParseArgs(): tokenizador respetando comillas simples y dobles
- Todos los comandos se guardan en query_history
Frontend:
- isRedis: false estado y reset en onConxChange()
- Detecta redis/valkey en tipo_db.nombre
- Editor cambia label 'Redis CLI', placeholder con ejemplos Redis
- Sidebar: 'Keys' en lugar de 'Tablas' para Redis
- insertTable(): TYPE + TTL + GET para inspeccionar una key de Redis
- Panel de chips rojos: KEYS *, DBSIZE, INFO, CONFIG GET, CLIENT LIST, SLOWLOG
- Generador Redis: select de 24 comandos + formulario contextual
(key, value, ttl, field según el comando elegido)
- generateRedisCmd(): genera el comando en el editor
- Badge MySQL no aparece cuando es Redis
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Agrega splitPostgresStatements() que parsea SQL respetando dollar-quoting, strings y comentarios
- En ExecuteSQL, si es PostgreSQL y hay múltiples sentencias, cada una se ejecuta con su propio db.Exec()
- Evita el error: 'CREATE DATABASE cannot run inside a transaction block'
- Error ocurría porque PostgreSQL envuelve multi-statement en transacción implícita al usar simple query protocol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Nuevo modelo PortalPasswordResetToken con token seguro (32 bytes, 1h vigencia)
- AutoMigrate del nuevo modelo en main.go
- SendPortalPasswordResetEmail con diseño consistente al app
- Handlers: PortalForgotPasswordPage/Post y PortalResetPasswordPost/Page
- Rutas públicas GET/POST /portal/forgot-password y /portal/reset-password
- Vistas forgot_password.html y reset_password.html con validación JS
- Enlace ¿Olvidaste tu contraseña? en login.html + soporte mensaje success
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>