La Consulta SQL Asistida Reinventada
Como vimos en el artículo sobre dashboards HTML con Chart.js, el control WebBrowser de PowerBuilder es una puerta abierta hacia el ecosistema web moderno. Allí lo usamos para embeber HTML estático con gráficos dinámicos. Hoy damos un paso más: vamos a integrar AG Grid Community (una de las librerías de grid más potentes del mercado) dentro de la ventana w_con_sql, la Consulta SQL Asistida. Y el grid será completamente dinámico: sus columnas cambian en runtime según la SQL que escriba el usuario.
Sí, seguimos usando PowerBuilder como motor, en este caso mi Cloud Framework, pero igualmente aplicable en PowerBuilder clásico. El DataWindow sigue ahí, trabajando en la sombra, pero el usuario ve algo que parece salido de una aplicación React moderna. Y sin servidor web. Sin licencias adicionales. Sin magia negra.
El Punto de Partida: w_con_sql
La ventana w_con_sql es la clásica consulta SQL asistida: el usuario elige tablas, columnas, filtros, y ejecuta la consulta. El resultado se muestra en un DataWindow. Funciona. Ha funcionado durante años. Pero tiene sus limitaciones visuales y de interacción.
La idea es simple: mantener todo el mecanismo de construcción de SQL intacto y sustituir únicamente la presentación de resultados por un grid React moderno. El DataWindow sigue existiendo pero el usuario no lo ve. Ve AG Grid.
La Clave: Grid Completamente Dinámico
Este es el salto cualitativo respecto al artículo de dashboards. Allí, el HTML se generaba desde PowerBuilder con datos conocidos de antemano. Aquí, ni las columnas ni los datos se conocen hasta el momento de ejecutar la consulta. El usuario puede pedir cualquier combinación de tablas y campos, y el grid debe adaptarse.
Para lograrlo, hay dos fases:
- Generar la definición de columnas a partir del DataWindow creado dinámicamente.
- Enviar los datos mediante
ExportJson().
Comunicación PowerBuilder → React
Una vez tenemos el DataWindow creado y recuperados los datos, toca enviarlos al grid. La comunicación se realiza íntegramente mediante EvaluateJavascriptSync() (o Async para operaciones que no necesitan respuesta inmediata), llamando a funciones window.* que la app React expone globalmente.
El diseño es el mismo que en el artículo de dashboards: PowerBuilder manda, React responde. La app React no sabe nada de PowerBuilder; simplemente expone funciones en window y PowerBuilder las invoca cuando quiere.
Integración con los Temas de PowerBuilder
Los temas Flat Design de PowerBuilder (Blue, Dark, Grey, Lime, Orange, Silver) tienen colores definidos que podemos leer y mapear a los temas de AG Grid.
Además, hay una función pública wf_cambiar_tema() que permite cambiar el tema en caliente desde otra ventana o desde el menú de la aplicación, sin recargar el grid ni perder los datos cargados.
Menú Contextual Enriquecido
Una de las ventajas de AG Grid Community es su menú contextual configurable. En la app React lo hemos definido con las opciones más útiles:
- Exportar a Excel → generado desde el lado React con ExcelJS
- Exportar a PDF → generado desde el lado React con jsPDF
- Copiar al portapapeles → copia las filas seleccionadas
- Ordenar Ascendente / Descendente
- Filtrar por esta columna
- Abrir Mantenimiento → opción opcional; se muestra u oculta según
window.setMaintenanceEnabled(bool)
Un apunte importante sobre la exportación a Excel: exportDataAsExcel es una función de AG Grid Enterprise. Nosotros usamos la versión Community, así que la exportación la implementamos directamente en React con ExcelJS, que nos da total control sobre el formato del archivo resultante sin necesidad de licencia adicional.
Arquitectura del Build: Un Solo Archivo HTML
Aquí está uno de los trucos más prácticos del proyecto. Una app React normal genera docenas de archivos en dist/. Navegar a eso desde PowerBuilder es un engorro. La solución: vite-plugin-singlefile.
// vite.config.ts
export default defineConfig({
base: './', // Rutas relativas (imprescindible para file://)
plugins: [react(), viteSingleFile()],
build: {
cssCodeSplit: false, // CSS en un solo bloque
assetsInlineLimit: 100000000, // Inlinear todos los assets
rollupOptions: {
output: {
inlineDynamicImports: true, // Sin chunks separados
},
},
},
})
El resultado es un único index.html de aproximadamente 3MB que incluye todo inlineado. Navegamos a él con:
wb_new.Navigate("dist\index.html")
Sin servidor web. Sin CORS. Sin rutas relativas que se rompan. La app React arranca en milisegundos directamente desde el sistema de archivos local.
El Flujo Completo de la Ventana
┌─────────────────────────────────────────────┐
│ w_con_sql - Consulta SQL Asistida │
│ │
│ [Selector de tablas / columnas / filtros] │
│ [DataWindow clásico - visible] │
│ │
│ [ Crear DataWindow ] │
└─────────────────────────────────────────────┘
│
▼ Al pulsar "Crear DW"
┌─────────────────────────────────────────────┐
│ w_con_sql - Vista de Resultados │
│ │
│ [DataWindow - oculto, sigue funcionando] │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ AG Grid React │ │
│ │ - Columnas generadas en runtime │ │
│ │ - Filtros avanzados por tipo │ │
│ │ - Ordenación, resize, menú │ │
│ │ - Tema sincronizado con PB │ │
│ └─────────────────────────────────────┘ │
│ │
│ [Redimensionar ventana → autoFitColumns()] │
└─────────────────────────────────────────────┘
Cuando el usuario redimensiona la ventana, el evento Resize de PowerBuilder reposiciona el WebBrowser y llama window.autoFitColumns() para que el grid se adapte al nuevo espacio disponible.
Beneficios de AG Grid
El usuario gana:
- Filtros avanzados en cada columna (texto, número, fecha), combinables
- Ordenación multicolumna con Shift+Click
- Redimensionado de columnas con drag
- Exportación a Excel y PDF desde el menú contextual
- Copiar al portapapeles en un clic
- Temas visuales coherentes con la aplicación PB
- Una experiencia que no parece "aplicación legacy"
El desarrollador gana:
- No ha tocado la lógica de negocio existente
- No hay servidor web que mantener
- El build React es un artefacto estático que se distribuye con la aplicación
- La comunicación PB↔React es limpia y bien definida
- Es extensible: añadir una nueva función
window.*es trivial en ambos lados
Código y Recursos
El ejemplo completo está disponible en los repositorios públicos del proyecto:
- PowerBuilder 2025 (FrontEnd): github.com/rasanfe/PersonDemo03
- API .NET 8 (BackEnd): github.com/rasanfe/MyPowerServer
Conclusión
El WebBrowser en PowerBuilder no es solo para mostrar páginas web externas. Es un puente hacia todo el ecosistema de librerías JavaScript modernas: Chart.js para visualización, AG Grid para datos tabulares, y lo que se nos ocurra después.
El patrón es siempre el mismo: PowerBuilder gestiona los datos y la lógica de negocio (que es donde tiene 30 años de ventaja), y delegamos la presentación a tecnologías web especializadas. La comunicación mediante EvaluateJavascriptSync/Async y funciones window.* es suficientemente potente para cubrir cualquier caso de uso.
¿Tiene sentido hacer esto? Depende del contexto. En una app de empresa con usuarios acostumbrados a Excel y grids avanzados, la diferencia es notable. Y el coste de implementación es sorprendentemente bajo.
Si experimentáis con esto en vuestros proyectos, me encantaría saber cómo os va. Los comentarios y las contribuciones al repo son siempre bienvenidos.
PowerBuilder sigue más vivo que nunca. 🚀
Artículo relacionado: Dashboard HTML PowerBuilder con Chart.js
Comentarios
Publicar un comentario