Implementação de tabelas e gráficos
Neste tutorial, criaremos a interface e a lógica de uma aplicação simples, com foco na visualização de dados. O desenvolvimento do projeto abordará os tópicos:
- A criação de "Formulários", "Campos" e "Relações" para estruturação da base de dados.
- A construção de "Serviços Web REST" para fornecer os dados e a exibição dinâmica de informações em tabelas e gráficos na aplicação, utilizando as bibliotecas React ChartJS 2 e a dependência Chart.js, além do componente de tabela do Ant Design.
Toda a estrutura visual do projeto será desenvolvida utilizando HTML, JavaScript e React.js. É recomendável que você tenha conhecimentos básicos de:
- JavaScript
- React.js
- HTML
💡 Caso tenha dúvidas nestas etapas, consulte:
- Guia da Interface: Formulários
- Guia da Interface: Campos
- Guia da Interface: Relações entre formulários
- Guia da Interface: Serviços Web REST
Produto Final
Ao seguir todos os passos deste tutorial, construirá um painel funcional na área de trabalho do Netuno, contendo:
- Uma tabela de dados listando os registros de trabalhadores e totais de horas.
- Um gráfico de barras dinâmico e colorido exibindo visualmente esses mesmos dados.

Arquitetura da Solução
Antes de escrever qualquer código, é importante entender como as peças se encaixam. A solução é dividida em 4 camadas que se comunicam de cima para baixo:
DashboardContainer (busca os dados no servidor)
│
▼
DataVisualization (organiza o layout em duas colunas)
│
┌────┴────┐
▼ ▼
TableList ChartBar (renderizam os dados recebidos)
A vantagem desta arquitetura é que cada componente tem uma única responsabilidade.
Passo 1: Estrutura de Dados
O primeiro passo é criar os formulários, configurar a relação entre eles e preenchê-los com dados para gerar a tabela e o gráfico mais à frente.
Este é o diagrama com a arquitetura dos formulários e os campos que deverá replicar no seu ambiente Netuno:

Importante: Embora o campo
idapareça no diagrama, não é necessário criá-lo manualmente. O Netuno gera esse identificador automaticamente logo após a criação da tabela.
Template Dashboard
Para exibir a tabela e o gráfico, precisaremos de um local na interface da sua aplicação. O Netuno já disponibiliza um template base para o painel principal.
Abra o seu editor de código e encontre o arquivo:
/apps/minhaapp/server/templates/dashboard.html
(Lembre-se de substituir minhaapp pelo nome real da sua pasta de aplicação).
Você notará a seguinte linha de código HTML:
<div id="app-dashboard"></div>
Passo 2: Serviço de Dados
Agora que temos a base de dados pronta e o HTML preparado, precisamos criar o "mensageiro" (um Serviço Web REST). Ele será responsável por ir até o banco de dados, calcular o total de horas de cada trabalhador e entregar essa informação pronta para a tabela e o gráfico.
Criando o arquivo do serviço
Os serviços no Netuno ficam guardados na pasta server/services/. Navegue até o diretório do seu projeto e crie o arquivo trabalhadores.js:
/apps/minhaapp/server/services/trabalhadores.js
O DashboardContainer detecta o idioma do painel e chama /services/trabalhadores quando o painel está em Português, ou /services/workers quando está em Inglês. Cada idioma tem seu próprio arquivo de serviço.
Escrevendo o código
Este código realiza três ações principais utilizando os recursos nativos do Netuno (_db, _val e _out):
-
Consulta _db.query: Busca somente os trabalhadores ativos no banco de dados e calcula a soma das horas trabalhadas por cada um.
-
Processamento _val.list e _val.map: Organiza o resultado em uma lista limpa com objetos estruturados.
-
Resposta _out.json: Envia os dados no formato JSON para que a interface (React) consiga ler.
Abra o arquivo trabalhadores.js e cole o código abaixo:
// 1. Consulta, _db.query() executa o SQL e retorna a lista de registros encontrados.
const dbRegistros = _db.query(`
SELECT DISTINCT
trabalhador.nome, SUM(DATEDIFF(HOUR, registro.inicio, registro.fim)) AS total
FROM trabalhador INNER JOIN registro
ON trabalhador.id = registro.trabalhador_id
WHERE trabalhador.active = true AND registro.active = true
GROUP BY trabalhador.nome
ORDER BY total ASC
`);
// 2. Processamento dos Dados, _val.list() cria uma lista vazia para guardar os dados processados.
const lista = _val.list();
// Percorre cada linha retornada pelo banco de dados
for (const dbRegistro of dbRegistros) {
lista.add(
// _val.map() cria um objeto com os campos que o React vai consumir
_val.map()
.set("name", dbRegistro.getString("nome")) // nome → campo "name"
.set("total", dbRegistro.getInt("total")) // total de horas → campo "total"
);
}
// 3. Resposta
// Envia a lista final em formato JSON para a interface React.
_out.json(lista);
-
Atenção ao nome dos campos: Os campos definidos aqui como "name" e "total" são exatamente os mesmos que os componentes React irão buscar nos próximos passos (dataIndex: 'name' e dataIndex: 'total'). Eles precisam ser idênticos.
-
Sobre o filtro active = true: O banco de dados possui uma coluna active nas tabelas trabalhador e registro. Ao filtrar apenas os registros ativos, garantimos que dados arquivados ou desativados não apareçam na tabela e no gráfico.