570 lines
15 KiB
Markdown
570 lines
15 KiB
Markdown
# Rapid Dashboards — Guia de uso
|
|
|
|
Dashboard builder declarativo: defines un YAML, obtienes un dashboard desktop con datos en vivo.
|
|
|
|
## Inicio rapido
|
|
|
|
```bash
|
|
cd apps/rapid_dashboards
|
|
|
|
# Desarrollo — usa symlink dashboard.yaml (ver "Cambiar entre dashboards")
|
|
wails dev
|
|
|
|
# Desarrollo — build produccion
|
|
CGO_ENABLED=1 wails build -tags fts5
|
|
./build/bin/rapid-dashboards --dashboard examples/fn_registry_overview.yaml
|
|
```
|
|
|
|
## Compilar un dashboard especifico
|
|
|
|
### Desarrollo (wails dev)
|
|
|
|
`wails dev` no pasa argumentos CLI al binario. El binario busca el dashboard en este orden:
|
|
|
|
1. Flag `--dashboard <path>` (solo funciona con `wails build`, no con `wails dev`)
|
|
2. Variable de entorno `DASHBOARD` (no se propaga al binario en `wails dev`)
|
|
3. Archivo `dashboard.yaml` en el cwd (metodo recomendado para desarrollo)
|
|
|
|
**Para desarrollo, usar un symlink:**
|
|
|
|
```bash
|
|
# Apuntar al dashboard deseado
|
|
ln -sf examples/fn_registry_overview.yaml dashboard.yaml
|
|
|
|
# Lanzar — el binario encuentra dashboard.yaml automaticamente
|
|
wails dev
|
|
```
|
|
|
|
### Produccion (wails build)
|
|
|
|
```bash
|
|
# Compilar
|
|
CGO_ENABLED=1 wails build -tags fts5
|
|
|
|
# Ejecutar con un YAML especifico
|
|
./build/bin/rapid-dashboards --dashboard examples/fn_registry_overview.yaml
|
|
./build/bin/rapid-dashboards --dashboard /ruta/absoluta/mi_dashboard.yaml
|
|
```
|
|
|
|
El binario compilado acepta el flag `--dashboard` directamente.
|
|
|
|
---
|
|
|
|
## Cambiar entre dashboards
|
|
|
|
### En vivo (dropdown en la app)
|
|
|
|
Si hay mas de un archivo `.yaml` en el directorio del dashboard actual, aparece un dropdown junto al titulo. Al seleccionar otro dashboard:
|
|
|
|
- Se cargan las nuevas conexiones, queries y widgets
|
|
- Se cierran las conexiones anteriores
|
|
- El tema se aplica automaticamente
|
|
|
|
Los dashboards disponibles se escanean del directorio donde esta el YAML actual (por defecto `examples/`).
|
|
|
|
### Cambiando el symlink (para desarrollo)
|
|
|
|
```bash
|
|
# Ver dashboards disponibles
|
|
ls examples/*.yaml
|
|
|
|
# Cambiar al dashboard de apps
|
|
ln -sf examples/fn_registry_apps.yaml dashboard.yaml
|
|
|
|
# Cambiar al overview de funciones
|
|
ln -sf examples/fn_registry_overview.yaml dashboard.yaml
|
|
|
|
# Reiniciar wails dev para que tome el cambio
|
|
```
|
|
|
|
### Por CLI (produccion)
|
|
|
|
```bash
|
|
# Dashboard de funciones
|
|
./build/bin/rapid-dashboards --dashboard examples/fn_registry_overview.yaml
|
|
|
|
# Dashboard de apps
|
|
./build/bin/rapid-dashboards --dashboard examples/fn_registry_apps.yaml
|
|
```
|
|
|
|
---
|
|
|
|
## Temas
|
|
|
|
El campo `theme` del YAML controla toda la estetica del dashboard. Cada tema cambia colores de fondo, texto, cards, bordes, acentos y la paleta de colores de los graficos.
|
|
|
|
### Temas disponibles
|
|
|
|
| Tema | Descripcion | Uso recomendado |
|
|
|------|-------------|-----------------|
|
|
| `dark` | Azul-gris profundo, acentos azules | Default, dashboards tecnicos |
|
|
| `emerald` | Verde esmeralda oscuro, acentos dorados | Dashboards financieros, naturaleza |
|
|
| `amber` | Calido ambar/naranja sobre fondo oscuro | Dashboards de alertas, operaciones |
|
|
| `rose` | Rosa/magenta sobre fondo oscuro | Dashboards de marketing, analytics |
|
|
| `light` | Fondo claro con sombras sutiles | Presentaciones, pantallas con luz |
|
|
|
|
### Ejemplo de uso
|
|
|
|
```yaml
|
|
# Dashboard con tema esmeralda
|
|
theme: "emerald"
|
|
|
|
# Dashboard con tema claro
|
|
theme: "light"
|
|
```
|
|
|
|
### Que cambia cada tema
|
|
|
|
- **Background y foreground**: tonos base del fondo y texto
|
|
- **Card**: color de fondo de widgets, sin bordes en temas oscuros, con sombra en light
|
|
- **Primary/accent**: color de acento para interacciones y highlights
|
|
- **Border**: tonos de separadores y bordes
|
|
- **Chart palette**: cada tema tiene su propia secuencia de colores para graficos (`--chart-1` a `--chart-5`)
|
|
|
|
### Anadir un tema nuevo
|
|
|
|
Anadir un bloque `[data-theme="nombre"]` en `frontend/src/app.css` con todas las variables CSS. El tema se activa automaticamente al usar `theme: "nombre"` en el YAML.
|
|
|
|
---
|
|
|
|
## Estructura del YAML
|
|
|
|
Un dashboard se define con 5 bloques:
|
|
|
|
```yaml
|
|
settings: # titulo, dimensiones, refresh global, columnas
|
|
theme: # tema visual
|
|
connections: # bases de datos
|
|
queries: # SQL + refresh + params
|
|
filters: # controles de filtro
|
|
sections: # secciones con widgets
|
|
```
|
|
|
|
---
|
|
|
|
## 1. settings
|
|
|
|
```yaml
|
|
settings:
|
|
title: "Mi Dashboard" # titulo de la ventana
|
|
refresh: 30s # refresh global por defecto
|
|
width: 1280 # ancho ventana (px)
|
|
height: 800 # alto ventana (px)
|
|
columns: 12 # columnas del grid CSS
|
|
```
|
|
|
|
- `refresh` acepta duraciones Go: `200ms`, `1s`, `5s`, `1m`, `30m`
|
|
- `columns` define el grid base. Cada widget usa `span` para ocupar N columnas.
|
|
|
|
---
|
|
|
|
## 2. connections
|
|
|
|
Cada conexion tiene un nombre y un driver. Secrets via variables de entorno `${VAR}`.
|
|
|
|
### SQLite
|
|
```yaml
|
|
connections:
|
|
local:
|
|
driver: sqlite
|
|
path: ./data.db
|
|
```
|
|
|
|
### PostgreSQL
|
|
```yaml
|
|
connections:
|
|
main_db:
|
|
driver: postgres
|
|
host: localhost
|
|
port: 5432
|
|
user: analytics
|
|
password: "${PG_PASSWORD}"
|
|
database: myapp
|
|
sslmode: disable
|
|
```
|
|
|
|
### DuckDB
|
|
```yaml
|
|
connections:
|
|
warehouse:
|
|
driver: duckdb
|
|
path: ./warehouse.duckdb
|
|
```
|
|
|
|
### ClickHouse
|
|
```yaml
|
|
connections:
|
|
events:
|
|
driver: clickhouse
|
|
host: localhost
|
|
port: 9000
|
|
user: default
|
|
password: ""
|
|
database: events
|
|
```
|
|
|
|
**Paths relativos**: se resuelven desde el cwd del binario, NO desde la ubicacion del YAML. En desarrollo el cwd es `apps/rapid_dashboards/`, asi que `../../registry.db` apunta a la raiz del repo.
|
|
|
|
---
|
|
|
|
## 3. queries
|
|
|
|
```yaml
|
|
queries:
|
|
revenue_total:
|
|
connection: main_db
|
|
sql: "SELECT SUM(amount) as value FROM orders"
|
|
refresh: 10s
|
|
stale_time: 5s
|
|
|
|
revenue_by_date:
|
|
connection: main_db
|
|
sql: |
|
|
SELECT date, SUM(amount) as revenue
|
|
FROM orders
|
|
WHERE date >= :date_from AND date <= :date_to
|
|
ORDER BY date
|
|
params:
|
|
date_from: "$filter.date_range.from"
|
|
date_to: "$filter.date_range.to"
|
|
```
|
|
|
|
### Parametros
|
|
|
|
- `:nombre` en el SQL se reemplaza por el valor del param.
|
|
- `$filter.xxx` referencia el valor actual de un filtro.
|
|
- `$filter.date_range.from` accede al subcampo `from`.
|
|
- Placeholders se convierten al formato del driver (`$1` para Postgres, `?` para SQLite/DuckDB/ClickHouse).
|
|
|
|
### Fechas relativas
|
|
|
|
| Valor | Resultado |
|
|
|-------|-----------|
|
|
| `now` | timestamp actual |
|
|
| `now-7d` | hace 7 dias |
|
|
| `now-24h` | hace 24 horas |
|
|
| `now-30m` | hace 30 minutos |
|
|
|
|
---
|
|
|
|
## 4. filters
|
|
|
|
### Select
|
|
```yaml
|
|
filters:
|
|
category:
|
|
type: select
|
|
label: "Categoria"
|
|
default: "all"
|
|
options:
|
|
- { label: "Todas", value: "all" }
|
|
- { label: "Electronics", value: "electronics" }
|
|
```
|
|
|
|
### Date Range
|
|
```yaml
|
|
filters:
|
|
date_range:
|
|
type: date_range
|
|
label: "Periodo"
|
|
default: { from: "now-7d", to: "now" }
|
|
presets:
|
|
- { label: "7 dias", from: "now-7d", to: "now" }
|
|
- { label: "30 dias", from: "now-30d", to: "now" }
|
|
```
|
|
|
|
### Text
|
|
```yaml
|
|
filters:
|
|
search:
|
|
type: text
|
|
label: "Buscar"
|
|
placeholder: "Buscar por nombre..."
|
|
debounce: 300
|
|
```
|
|
|
|
---
|
|
|
|
## 5. sections y widgets
|
|
|
|
```yaml
|
|
sections:
|
|
- id: kpis
|
|
title: "Metricas"
|
|
columns: 4 # override de columnas
|
|
widgets:
|
|
- id: total_users
|
|
type: kpi
|
|
title: "Usuarios"
|
|
query: count_users
|
|
mapping: { value: "value" }
|
|
span: 1
|
|
|
|
- id: charts
|
|
title: "Graficos"
|
|
collapsible: true
|
|
columns: 2
|
|
widgets:
|
|
- id: revenue_line
|
|
type: line_chart
|
|
title: "Revenue"
|
|
query: revenue_by_date
|
|
mapping:
|
|
x: "date"
|
|
series:
|
|
- { key: "revenue", name: "Revenue", color: "#3b82f6" }
|
|
options:
|
|
zoomable: true
|
|
span: 1
|
|
```
|
|
|
|
---
|
|
|
|
## Tipos de widget
|
|
|
|
### kpi
|
|
|
|
```yaml
|
|
- type: kpi
|
|
mapping:
|
|
value: "campo_sql"
|
|
format: "$,.2f" # opcional
|
|
```
|
|
|
|
### line_chart
|
|
|
|
```yaml
|
|
- type: line_chart
|
|
mapping:
|
|
x: "date"
|
|
series:
|
|
- { key: "revenue", name: "Revenue", color: "#3b82f6" }
|
|
options:
|
|
curve: monotone # linear | monotone | step
|
|
show_grid: true
|
|
show_legend: true
|
|
zoomable: true
|
|
height: 400
|
|
```
|
|
|
|
### bar_chart
|
|
|
|
```yaml
|
|
- type: bar_chart
|
|
mapping:
|
|
x: "category"
|
|
y: "count"
|
|
# O multi-series con series: [...]
|
|
options:
|
|
horizontal: true # barras horizontales
|
|
show_grid: true
|
|
show_legend: true
|
|
height: 300
|
|
```
|
|
|
|
### pie_chart
|
|
|
|
```yaml
|
|
- type: pie_chart
|
|
mapping:
|
|
name: "domain" # campo para nombres de segmentos
|
|
value: "cantidad" # campo numerico
|
|
options:
|
|
donut: true # hueco central
|
|
show_legend: true # default: true
|
|
height: 300
|
|
```
|
|
|
|
### area_chart
|
|
|
|
```yaml
|
|
- type: area_chart
|
|
mapping:
|
|
x: "date"
|
|
series:
|
|
- { key: "users", name: "Usuarios" }
|
|
options:
|
|
stacked: true
|
|
height: 300
|
|
```
|
|
|
|
### sparkline
|
|
|
|
```yaml
|
|
- type: sparkline
|
|
mapping:
|
|
value: "metric"
|
|
options:
|
|
variant: area # line | area | bar
|
|
width: 200
|
|
height: 40
|
|
```
|
|
|
|
### table
|
|
|
|
```yaml
|
|
- type: table
|
|
mapping:
|
|
columns:
|
|
- { key: "name", label: "Nombre" }
|
|
- { key: "amount", label: "Monto", format: "$,.2f" }
|
|
- { key: "created_at", label: "Fecha", format: "datetime" }
|
|
options:
|
|
heatmap_columns: ["go", "python", "bash"] # colorea celdas por intensidad
|
|
```
|
|
|
|
Si no defines `columns`, se auto-detectan del resultado SQL.
|
|
|
|
**Heatmap**: `options.heatmap_columns` acepta un array de nombres de columna. Las celdas se colorean de azul oscuro (valor minimo) a azul brillante (valor maximo), calculado por columna.
|
|
|
|
---
|
|
|
|
## Formatos de valor
|
|
|
|
| Formato | Ejemplo | Resultado |
|
|
|---------|---------|-----------|
|
|
| `$,.2f` | 1234.5 | $1,234.50 |
|
|
| `,.2f` | 1234.5 | 1,234.50 |
|
|
| `.2f` | 1234.5 | 1234.50 |
|
|
| `,` | 1234 | 1,234 |
|
|
| `datetime` | ISO string | locale datetime |
|
|
|
|
---
|
|
|
|
## Variables de entorno
|
|
|
|
Cualquier campo del YAML soporta `${VARIABLE}`:
|
|
|
|
```bash
|
|
DB_HOST=prod.example.com DB_PASSWORD=secret \
|
|
./rapid-dashboards --dashboard prod.yaml
|
|
```
|
|
|
|
---
|
|
|
|
## Puntos clave (aprendizajes)
|
|
|
|
### Wails dev no pasa CLI args al binario
|
|
|
|
`wails dev -- --flag value` no funciona: Wails compila y ejecuta el binario como proceso hijo sin pasar los args despues de `--`. Tampoco propaga variables de entorno al binario. La solucion es usar un archivo `dashboard.yaml` en el cwd que el binario detecta automaticamente.
|
|
|
|
### Wails genera bindings ejecutando el binario sin args
|
|
|
|
Durante `wails dev`, el primer paso es generar bindings TypeScript. Para esto Wails ejecuta el binario sin argumentos. Si el binario requiere flags obligatorios y hace `os.Exit(1)`, la generacion falla. Solucion: detectar cuando no hay args y usar un config dummy con slices vacios (no nil) para que los tipos se generen correctamente.
|
|
|
|
### Slices nil de Go se serializan como null en JSON
|
|
|
|
`[]SectionDef(nil)` se serializa como `null`, no como `[]`. Si el frontend hace `.map()` sobre null, crash. Inicializar siempre con `[]SectionDef{}` para el config dummy, y usar `(config.sections ?? [])` en el frontend.
|
|
|
|
### Tipos de Wails vs tipos manuales de TypeScript
|
|
|
|
Wails genera `models.ts` con tipos `string` genericos. Si el frontend tiene tipos mas estrictos (union types como `"select" | "date_range"`), hay incompatibilidad. Solucion: castear los imports con `as unknown as typeof X`.
|
|
|
|
### Paths relativos se resuelven desde el cwd, no desde el YAML
|
|
|
|
`SQLiteOpen(path)` resuelve paths relativos al cwd del proceso. Si el YAML esta en `examples/` y el binario corre desde `apps/rapid_dashboards/`, un path `../../registry.db` es correcto pero `../../../registry.db` (relativo al YAML) no. Siempre pensar los paths desde el cwd del binario.
|
|
|
|
### Recharts Pie necesita valores numericos
|
|
|
|
SQLite puede devolver numeros como strings en algunos contextos. Recharts Pie no renderiza nada si `dataKey` apunta a un string. Solucion: coercer a `Number()` antes de pasar a Pie.
|
|
|
|
### Recharts PieLabelRenderProps es estricto
|
|
|
|
El tipo `label` de `<Pie>` no acepta callbacks con tipos genericos como `Record<string, unknown>`. Hay que importar `PieLabelRenderProps` de `recharts` y usar una funcion con nombre tipada, no un lambda inline.
|
|
|
|
### Animaciones de Recharts
|
|
|
|
Las animaciones por defecto de Recharts Pie son lentas en dashboards que refrescan frecuentemente. Usar `isAnimationActive={false}` para render instantaneo.
|
|
|
|
---
|
|
|
|
## Scripts de lanzamiento
|
|
|
|
Cada dashboard YAML debe tener forma de lanzarse rapido desde `scripts/`. La carpeta `scripts/` contiene dos scripts genericos que reciben el nombre del dashboard como argumento:
|
|
|
|
```bash
|
|
# Listar dashboards disponibles
|
|
./scripts/dev.sh
|
|
|
|
# Desarrollo — crea symlink + wails dev
|
|
./scripts/dev.sh fn_registry_overview
|
|
|
|
# Produccion — compila si es necesario + ejecuta
|
|
./scripts/prod.sh fn_registry_apps
|
|
|
|
# Produccion con variables de entorno
|
|
DB_PASSWORD=secret ./scripts/prod.sh mi_dashboard
|
|
```
|
|
|
|
### Convencion
|
|
|
|
Al crear un nuevo YAML en `examples/`, no hace falta crear scripts adicionales — `dev.sh` y `prod.sh` descubren automaticamente los `.yaml` de `examples/`. Solo ejecutar con el nombre (sin extension):
|
|
|
|
```bash
|
|
# Nuevo dashboard
|
|
vim examples/mi_nuevo_dashboard.yaml
|
|
|
|
# Lanzar inmediatamente
|
|
./scripts/dev.sh mi_nuevo_dashboard
|
|
```
|
|
|
|
`dev.sh` crea el symlink `dashboard.yaml` y lanza `wails dev`. `prod.sh` compila con `CGO_ENABLED=1 wails build -tags fts5` si el binario no existe o el YAML es mas reciente, y ejecuta con `--dashboard`.
|
|
|
|
---
|
|
|
|
## Compilacion multiplataforma
|
|
|
|
### Linux (default)
|
|
|
|
```bash
|
|
CGO_ENABLED=1 wails build -tags fts5
|
|
```
|
|
|
|
Genera `build/bin/rapid-dashboards` con soporte para SQLite, PostgreSQL, DuckDB y ClickHouse.
|
|
|
|
### Windows (cross-compile desde Linux)
|
|
|
|
```bash
|
|
CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc GOOS=windows GOARCH=amd64 \
|
|
wails build -tags "fts5 noduckdb noclickhouse" -platform windows/amd64 -skipbindings
|
|
```
|
|
|
|
Genera `build/bin/rapid-dashboards.exe`. Requiere `mingw-w64` instalado (`apt install gcc-mingw-w64-x86-64`).
|
|
|
|
**Limitacion:** DuckDB y ClickHouse se excluyen con los tags `noduckdb` y `noclickhouse` porque `go-duckdb` depende de libstdc++ y no cross-compila bien desde Linux. El `.exe` solo soporta SQLite y PostgreSQL. Si un YAML usa esos drivers, dara error: `"duckdb support not compiled"`.
|
|
|
|
### Windows nativo (con DuckDB y ClickHouse)
|
|
|
|
Para compilar con todos los drivers, compilar directamente en Windows con Go y MinGW/MSYS2 instalados:
|
|
|
|
```powershell
|
|
# En Windows con Go + MinGW (MSYS2)
|
|
$env:CGO_ENABLED=1
|
|
wails build -tags fts5
|
|
```
|
|
|
|
Esto genera un `.exe` con soporte completo: SQLite, PostgreSQL, DuckDB y ClickHouse.
|
|
|
|
### Resumen de soporte por plataforma
|
|
|
|
| Driver | Linux | Windows (cross-compile) | Windows (nativo) |
|
|
|---|---|---|---|
|
|
| SQLite | si | si | si |
|
|
| PostgreSQL | si | si | si |
|
|
| DuckDB | si | no | si |
|
|
| ClickHouse | si | no | si |
|
|
|
|
### Rutas en Windows
|
|
|
|
Las rutas no se rompen entre plataformas. El codigo usa `filepath.Join` y `filepath.IsAbs` de Go, que adaptan los separadores automaticamente (`/` en Linux, `\` en Windows). Los paths relativos en el YAML (ej: `../../registry.db`) funcionan igual en ambos OS.
|
|
|
|
---
|
|
|
|
## Extensibilidad
|
|
|
|
Para anadir un tipo de widget nuevo:
|
|
|
|
1. Crear `frontend/src/components/widgets/MiWidget.tsx` implementando `WidgetProps`
|
|
2. Registrar en `frontend/src/components/widgets/register.ts`: `registerWidget('mi_tipo', MiWidget)`
|
|
3. Usar en YAML: `type: mi_tipo`
|