iGRPIGRP 3.0Documentation

Process Studio · SDK TypeScript

Os pacotes @igrp/framework-process-studio-client, -types e -bpmn-editor — criar o cliente, métodos por recurso, erros e o editor BPMN em React.

O frontend do Process Studio fala com o Process Studio API através de três pacotes, que também podes usar numa app tua (por exemplo, para listar ou publicar processos a partir de outro sistema):

PacoteVersãoPara quê
@igrp/framework-process-studio-client0.0.1-beta.16Cliente HTTP: projetos, definições, diagrama, publicação
@igrp/framework-process-studio-types0.0.1-beta.16Tipos partilhados (Project, ProcessDefinition, filtros, paginação)
@igrp/framework-process-studio-bpmn-editor0.1.0-beta.13Editor BPMN (bpmn-js + painel de propriedades) como componente React

Os pacotes estão no registry @igrp (Sonatype) e são ESM, para Node ≥ 20.

pnpm add @igrp/framework-process-studio-client @igrp/framework-process-studio-types

Criar o cliente

import { createProcessStudioClient } from "@igrp/framework-process-studio-client";

const client = createProcessStudioClient({
  baseUrl: process.env.API_GATEWAY ?? "", // rota do gateway, SEM /api/v1
  timeout: 30000,                          // ms (default 30000)
  headers: { Authorization: `Bearer ${accessToken}` },
});
OpçãoNotas
baseUrlRota do gateway do process-studio-api (http://<slug>:2575/gateway-api/<serviço>-process-studio-api). O /api/v1 já faz parte dos caminhos. Vazio → usa NEXT_PUBLIC_API_GATEWAY.
timeoutCancela o pedido (AbortController).
headersJunta-se a Content-Type/Accept: application/json. A autenticação vai aqui — não há opção token.

No frontend do Process Studio o cliente é criado no servidor, por pedido, com o token da sessão NextAuth, e as server actions são consumidas no browser via TanStack Query:

// lib/server-client.ts
import { createProcessStudioClient } from "@igrp/framework-process-studio-client";
import { serverSession } from "@/lib/auth";

export async function createServerClient() {
  const session = await serverSession();
  if (!session?.accessToken) throw new Error("Authentication required.");
  return createProcessStudioClient({
    baseUrl: process.env.API_GATEWAY ?? "",
    headers: { Authorization: `Bearer ${session.accessToken}` },
  });
}

O cliente regista cada pedido na consola

Nesta versão, cada pedido faz console.log do URL e das opções — incluindo o cabeçalho Authorization. Usa-o no servidor e não em produção com logs partilhados até isto ser removido.


Métodos

client.projects

MétodoPedidoDevolve
getAll(filter?)GET /api/v1/projects?appCode&pageNumber&pageSizePaginatedResponse<Project>
getById(id)GET /api/v1/projects/{id}Project
create(project)POST /api/v1/projectsProject
update(project)PUT /api/v1/projects/{projectId}Project
createOrUpdate(project)PUT se tiver projectId, senão POSTProject
enable(id) · disable(id)PATCH …/{id}/enable · /disable—
delete(id)igual a disable (apagamento lógico)—
getDeployedProcesses(id, filter?)GET /api/v1/projects/{id}/deployed-processProject com os processos publicados
getProcessHistory(id, filter?)GET /api/v1/projects/{id}/history-processProject

O corpo de create/update é { code, name, description, appCode }.

client.processDefinitions

MétodoPedidoDevolve
list(filter?)GET /api/v1/projects/process-definitionsPaginatedResponse<ProcessDefinition>
getAll()lista os 100 primeiros projetos e junta os processosProcessDefinition[]
getById(id)GET …/process-definitions/{id}ProcessDefinition (com bpmFileContent)
create(projectId, pd)POST /api/v1/projects/{projectId}/process-definitionsProcessDefinition
update(processId, pd)PUT …/process-definitions/{processId}ProcessDefinition
createOrUpdate(pd)conforme processDefinitionIdProcessDefinition
saveDiagram(processKey, { content })PUT …/process-definitions/{processKey}/diagramProcessDefinition
deploy(processKey, { content })POST …/process-definitions/{processKey}/deployProcessDefinition
getVariables(id) · createOrUpdateVariable(id, vars)GET · POST …/process-definitions/{id}/variablesVariableDefinition[]
delete(id) · restore(id)PATCH …/{id}/delete · /restore—
getStates()GET /parameterization/process-definition-stateEnumItem[]

O corpo de create/update é { title, processKey, description, projectId, status }. Os artefactos (User Tasks e Form Keys) chegam só em leitura, em ProcessDefinition.processArtifacts.

Namespace do XML

O editor trabalha em camunda; o motor guarda em activiti. O frontend do Process Studio converte o conteúdo (convertCamundaToActiviti) antes de saveDiagram e deploy. Se chamares o cliente diretamente, envia o XML já com activiti:formKey.

Exemplo — publicar um processo

"use server";
import { createServerClient } from "@/lib/server-client";

export async function publish(processKey: string, xml: string) {
  const client = await createServerClient();
  try {
    await client.processDefinitions.saveDiagram(processKey, { content: xml });
    return await client.processDefinitions.deploy(processKey, { content: xml });
  } catch (e) {
    const err = e as { status?: number; details?: { message?: string } };
    throw new Error(err.details?.message ?? `Falha ao publicar (HTTP ${err.status})`);
  }
}

Erros

Qualquer falha lança um ApiClientError com:

CampoConteúdo
messageHTTP Error: <status> <statusText>
statusCódigo HTTP; 0 em falha de rede ou timeout
detailsCorpo da resposta (JSON ou texto)

A classe não é exportada: lê status e details do erro, como no exemplo acima.


Ajudantes

FunçãoO que faz
formatDeploymentDate(valor)Data de publicação (ISO, array LocalDateTime do Java ou texto) → dd/MM/yyyy HH:mm
formatAuthorSuffix(user)" por <nome>" ou vazio
decorateProcessDefinitionRow(pd)Linha pronta para tabela (versão N/D, datas e autores formatados)
filterProcessDefinitionsBySubstring(rows, filtros)Filtro local por processKey, processName (título) e projectName
convertToMapOptions(items, nome?, valor?)Lista → { label, value }[] para selects

Tipos

@igrp/framework-process-studio-types exporta, entre outros:

TipoCampos principais
ProjectprojectId, code, name, description, appCode, active, processDefinitions[]
ProcessDefinitionprocessDefinitionId, processKey, title, status, statusDesc, version, deploymentDate, bpmFileContent, processArtifacts[]
ProcessArtifacttaskKey, name, formKey, artifactVariables[]
ProcessDefinitionStateDRAFT · VALIDATED · PUBLISHED · DEPRECATED · ARCHIVED · DISABLED · ERROR · DELETED
ProcessDefinitionFilterappCode, processKey, processName, projectCode, projectName, state, pageNumber, pageSize
PaginatedResponse<T>content, pageNumber, pageSize, totalElements, totalPages, first, last

Editor BPMN

pnpm add @igrp/framework-process-studio-bpmn-editor

Exporta IGRPBpmnModeler, IGRPBpmnControls e IGRPZoomControls. O modeler já inclui a barra de controlos e o zoom.

"use client";
import { IGRPBpmnModeler } from "@igrp/framework-process-studio-bpmn-editor";

export function Editor({ pd, onSave }: { pd: ProcessDefinition; onSave: (xml: string) => void }) {
  return (
    <IGRPBpmnModeler
      processKey={pd.processKey}
      processName={pd.title}
      xml={pd.bpmFileContent ?? ""}
      onChange={onSave} // chamado a cada alteração no canvas
    />
  );
}
PropNotas
processKey, processNameObrigatórios; com xml vazio, criam o diagrama inicial
xmlDiagrama a carregar; o editor ignora o eco do seu próprio onChange
onChange(xml)A cada alteração (commandStack.changed) e ao criar o diagrama inicial
onLoad(modeler)Acesso à instância bpmn-js
classNameAltura por defeito calc(100dvh - 13rem), mínimo 480 px

Requisitos:

  • Peers: next 15, next-auth 4, react/react-dom 19; usa botões e toasts do Design System (precisa do provider de toasts na app).

  • Estilos: o CSS do bpmn-js vem com o componente; as classes Tailwind não. Acrescenta ao CSS global da app:

    @source "../../node_modules/@igrp/framework-process-studio-bpmn-editor/dist/**/*.{js,mjs}";
  • Uma instância por página — o painel de propriedades usa um id fixo (#js-properties-panel).

  • Segue o tema escuro pela classe .dark no <html>.

Comportamentos desta versão

  • Carregar um ficheiro pelo botão de upload não chama onChange: grava o diagrama depois de uma alteração no canvas.
  • O diagrama inicial (xml vazio) começa por ?xml em vez de <?xml; o servidor rejeita-o ao guardar. Passa sempre um XML válido ou desenha antes de guardar.
How is this guide?

Última atualização: