Provides patterns and best practices for Sankhya BI dashboards using HTML, JSP, Java, and SQL, including code generation, visual consistency, database queries, and BI parameterization.
From antigravity-awesome-skillsnpx claudepluginhub sickn33/antigravity-awesome-skills --plugin antigravity-awesome-skillsThis skill uses the workspace's default tool permissions.
README.mdDesigns and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Enables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
To provide a consolidated guide of patterns and best practices for creating and maintaining dashboards, SQL queries, BI parameterization, and UI/UX within the Sankhya ecosystem (JSP/HTML/Java).
This skill should be used when:
Aplicar padrões de JSP/JSTL e organização server-side para reduzir erros de compilação, falhas de renderização e regressões em dashboards/telas.
Diretrizes de implementação
isELIgnored="false" para habilitar ${...} em tempo de renderização.core_rt para JSTL core no ecossistema Sankhya.c:if, c:choose, c:forEach).localStorage (ordem de colunas e ordenação).c:set para evitar Erro 500 no servidor Java do Sankhya.<script>. Utilizar containers HTML ocultos para passar dados ao JavaScript, mantendo a saúde do editor de código (IDE Linting).Os nomes de tabelas e campos abaixo são representativos e podem variar conforme a implementação da instância.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<%@ taglib prefix="snk" uri="/WEB-INF/tld/sankhyaUtil.tld" %>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<snk:load />
Carregamento de assets em dashboard/gadget
contextPath + BASE_FOLDER.openLevel), manter caminho absoluto para evitar quebra de resolução.<script src="${pageContext.request.contextPath}/${BASE_FOLDER}/js/app.js"></script>
<link rel="stylesheet" href="${pageContext.request.contextPath}/${BASE_FOLDER}/css/style.css" />
Consumo seguro de snk:query
query.rows (não no objeto raiz).empty query.rows.<snk:query var="qDados">
SELECT CAB.NUNOTA, CAB.CODPARC
FROM TGFCAB CAB
</snk:query>
<c:choose>
<c:when test="${empty qDados.rows}">
<span>Sem resultados</span>
</c:when>
<c:otherwise>
<c:forEach var="linha" items="${qDados.rows}">
${linha.NUNOTA}
</c:forEach>
</c:otherwise>
</c:choose>
Sanitização de parâmetros antes da SQL
" e ") antes de injetar em query.<c:set var="raw_codusu" value="${empty param.P_CODUSU ? '0' : param.P_CODUSU}" />
<c:set var="codusu_limpo" value="${fn:replace(raw_codusu, '\"', '')}" />
<c:set var="codusu_limpo" value="${fn:replace(codusu_limpo, '"', '')}" />
<c:set var="codusu_seguro" value="${empty codusu_limpo ? '0' : codusu_limpo}" />
<snk:query var="qAcessos">
SELECT CODUSU, NOMEUSU
FROM TSIUSU
WHERE CODUSU = :codusu_seguro
</snk:query>
Estado de tela e lazy-load em dashboard único
var dadosGlobais = [];
var produtoAtual = null;
var abaCarregada = {};
function abrirDetalhe(dado) {
produtoAtual = dado;
abaCarregada = {};
trocarAba("estoque");
}
function trocarAba(aba) {
if (aba === "estoque" && !abaCarregada.estoque) carregarAbaEstoque(produtoAtual.CODPROD);
if (aba === "pedidos" && !abaCarregada.pedidos) carregarAbaPedidos(produtoAtual.CODPROD);
if (aba === "parceiros" && !abaCarregada.parceiros) carregarAbaParceiros(produtoAtual.CODPROD);
}
Exemplo de Blindagem e Separação de Camadas
<%-- 1. Blindagem no topo do arquivo --%>
<c:set var="v_salesagent" value="${empty param.SALESAGENT ? '0' : param.SALESAGENT}" />
<%-- 2. Container oculto para dados (Separação JSP vs JS) --%>
<div id="data-container" style="display:none;">
[
<c:forEach var="row" items="${qDados.rows}" varStatus="loop">
{ "id": ${row.ID}, "nome": "${fn:replace(row.NOME, '"', '\\"')}" }${!loop.last ? ',' : ''}
</c:forEach>
]
</div>
<script>
// 3. JS apenas lê os dados do container
const rawData = document.getElementById('data-container').textContent.trim();
const myData = rawData ? JSON.parse(rawData) : [];
</script>
Padronizar identidade visual em componentes BI para consistência entre gadgets HTML5, tabelas e indicadores.
Diretrizes de UI/UX
--color-*) para evitar valores espalhados.BKCOLOR, FGCOLOR) quando necessário.Os nomes de tabelas e campos abaixo são representativos e podem variar conforme a implementação da instância.
<style>
:root {
--color-bg: #F5F7FA;
--color-surface: #FFFFFF;
--color-text: #1F2937;
--color-success: #1A7F37;
--color-warning: #B26A00;
--color-danger: #B42318;
--color-accent: #0E5A8A;
}
.card {
background: var(--color-surface);
color: var(--color-text);
border-radius: 8px;
padding: 12px;
}
</style>
SELECT
V.CODMETA,
V.VALOR_ATUAL,
V.VALOR_META,
CASE WHEN V.VALOR_ATUAL >= V.VALOR_META THEN '#1A7F37' ELSE '#B42318' END AS BKCOLOR,
'#FFFFFF' AS FGCOLOR
FROM AD_DADOS_VENDA V
<style>
#tblDados thead th { position: sticky; top: 0; z-index: 4; }
#tblDados .col-fixa-1 { position: sticky; left: 0; z-index: 3; }
#tblDados .col-fixa-2 { position: sticky; left: var(--fix-col-1-width); z-index: 2; }
.row-aprovacao td { background: #ffe8cc; color: #7a3a00; }
.row-parcial td { background: #fff4c4; color: #5e4c00; }
</style>
Estruturar exploração de dados com foco em performance, legibilidade e mapeamento correto de entidades Sankhya.
Boas práticas de exploração (DBExplorer)
DBEXPMAXROW) para evitar carga excessiva.SELECT * em tabelas com campos volumosos (BLOB/CLOB).Mapas essenciais do ecossistema
TDDTAB, TDDCAM, TDDOPC, TDDINS, TDDLIG.TGFCAB, TGFITE, TGFTOP, TGFPAR, TGFPRO, TGFEST, TGFVAR.TSIUSU, TSIGRU, TSIACI, TSIIMP.Padrões de SQL recomendados
CODTIPOPER + data de alteração (DHTIPOPER/DHALTER).(... = :P_PARAM OR :P_PARAM IS NULL).Os nomes de tabelas e campos abaixo são representativos e podem variar conforme a implementação da instância.
SELECT
CAB.NUNOTA,
CAB.CODPARC,
CAB.DTNEG,
ITE.SEQUENCIA,
ITE.CODPROD,
(ITE.VLRTOT - ITE.VLRDESC) AS VLR_LIQUIDO
FROM TGFCAB CAB
JOIN TGFITE ITE
ON ITE.NUNOTA = CAB.NUNOTA
JOIN TGFTOP TOP
ON TOP.CODTIPOPER = CAB.CODTIPOPER
AND TOP.DHALTER = CAB.DHTIPOPER
WHERE (CAB.CODPARC = :P_CODPARC OR :P_CODPARC IS NULL)
AND (CAB.CODVEND = :P_CODVEND OR :P_CODVEND IS NULL)
SELECT
U.CODUSU,
U.NOMEUSU,
G.NOMEGRUPO,
A.CODREL,
I.NOME AS DESCRICAO_RECURSO,
A.CONS,
A.ALTERA
FROM TSIUSU U
JOIN TSIGRU G ON G.CODGRUPO = U.CODGRUPO
JOIN TSIACI A ON A.CODGRUPO = U.CODGRUPO
JOIN TSIIMP I ON I.CODREL = A.CODREL
WHERE U.CODUSU = :P_CODUSU
ORDER BY I.NOME
Aplicar fluxo de desenvolvimento de componentes HTML5 no BI para garantir renderização, reatividade e navegação entre níveis.
Estrutura e publicação
.zip com index.html como entrada principal.assets/ (CSS, JS, libs, imagens).Fluxo de dados e parâmetros
: para bind padrão.:# para substituição literal (avaliar com cautela e validação).:@ para literal textual em cenários como LIKE./*inCollection*/.Os nomes de tabelas e campos abaixo são representativos e podem variar conforme a implementação da instância.
SELECT
C.CODCID,
C.NOMECID,
C.UF
FROM AD_TABELA_EXEMPLO C
WHERE /*inCollection*/ C.CODCID IN :P_CODCID /*inCollection*/
Reatividade e ciclo de vida
DOMContentLoaded em conteúdo injetado.<script>
function renderizarComponente(dados) {
// Atualizar DOM, gráficos e KPIs com os dados recebidos
}
function iniciar() {
const dadosIniciais = window.snkBIData || [];
renderizarComponente(dadosIniciais);
}
setTimeout(iniciar, 300);
</script>
Drill-down e eventos
Navegação multi-nível (openLevel e contrato de contexto)
NIVEL_RESUMO, NIVEL_DETALHE, NIVEL_ITEM) para evitar acoplamento em string solta.openLevel em funções dedicadas por rota de navegação (ex.: abrir detalhe por vendedor, abrir itens por parceiro).ARG_* para chaves e P_* para filtros/período).openLevel e parâmetros obrigatórios antes de navegar.var cfg = window.DASH_CONFIG || {};
var NIVEL_DETALHE = cfg.NIVEL_DETALHE || "NIVEL_B";
var NIVEL_ITEM = cfg.NIVEL_ITEM || "NIVEL_C";
function abrirNivelDetalhe(codigoEntidade) {
if (!codigoEntidade || typeof openLevel !== "function") return;
openLevel(NIVEL_DETALHE, {
ARG_CODENT: parseInt(codigoEntidade, 10),
P_PERIODO_INI: cfg.P_PERIODO_INI || "",
P_PERIODO_FIN: cfg.P_PERIODO_FIN || "",
P_CODMETA: cfg.P_CODMETA || ""
});
}
function abrirNivelItem(codigoEntidadeFilha) {
if (!codigoEntidadeFilha || typeof openLevel !== "function") return;
openLevel(NIVEL_ITEM, {
ARG_CODENT_FILHA: parseInt(codigoEntidadeFilha, 10),
P_PERIODO_INI: cfg.P_PERIODO_INI || "",
P_PERIODO_FIN: cfg.P_PERIODO_FIN || "",
P_CODMETA: cfg.P_CODMETA || ""
});
}
Segurança e bloqueio de acesso por escopo
WHERE para reaproveitamento em KPIs, grids e gráficos.CODUSU_LOG ou função equivalente de usuário logado) para evitar spoof de parâmetro de usuário.Os nomes de tabelas e campos abaixo são representativos e podem variar conforme a implementação da instância.
SELECT
M.CODMETA,
M.CODENTIDADE,
SUM(M.VLRPREV) AS VLR_PREV,
SUM(M.VLRREAL) AS VLR_REAL
FROM AD_DADOS_META M
WHERE M.CODMETA = :P_CODMETA
AND M.DTREF BETWEEN TO_DATE(:P_PERIODO_INI, 'DD/MM/YYYY')
AND TO_DATE(:P_PERIODO_FIN, 'DD/MM/YYYY')
AND EXISTS (
SELECT 1
FROM AD_META_USUARIO_LIB L
WHERE L.CODMETA = M.CODMETA
AND L.CODUSU = STP_GET_CODUSULOGADO
)
GROUP BY M.CODMETA, M.CODENTIDADE
Grid hierárquica com expansão/colapso
filhosPorPai e estado nosExpandidos para renderização incremental da árvore.var filhosPorPai = {};
var nosExpandidos = {};
function alternarNo(codNo) {
var id = String(codNo);
nosExpandidos[id] = !nosExpandidos[id];
renderizarGrid();
}
function obterVisiveis(raiz) {
var lista = [];
function visitar(pai) {
(filhosPorPai[pai] || []).forEach(function (no) {
lista.push(no);
if (nosExpandidos[String(no.CODNO)]) visitar(String(no.CODNO));
});
}
visitar(String(raiz || ""));
return lista;
}
Resiliência de carregamento
vazio) sem derrubar o layout inteiro.Navegação intra-nível (single JSP)
function abrirTelaNativa(resourceIdBase64, pkObj) {
var pk = btoa(JSON.stringify(pkObj));
top.location.href = "/mge/system.jsp#app/" + resourceIdBase64 + "/" + pk + "&pk-refresh=" + Date.now();
}
function onKpiClick(lista) {
abrirModalLista("Itens selecionados", "Navegação por atalho", lista);
}
function onGraficoClick(grupo) {
filtrarTabelaPorGrupo(grupo);
}
Feedback operacional de interface
executeQuery.Variáveis internas de segurança
CODUSU_LOG, CODGRU_LOG, CODVEN_LOG).