Construir um plugin de gestão de dados com integração front-back
Os exemplos anteriores eram puramente client-side (bloco, campo, ação) ou client + uma API simples (página de configurações). Este exemplo mostra um cenário mais completo — o servidor define a data table, o cliente herda de TableBlockModel para ganhar capacidades completas de tabela, mais um componente de campo personalizado e um botão de ação personalizado, formando um plugin de gestão de dados com CRUD.
Este exemplo costura o que aprendemos sobre bloco, campo e ação, mostrando o fluxo completo de desenvolvimento de um plugin.
É recomendável conhecer os seguintes tópicos antes:
- Escreva seu primeiro plugin — criação do plugin e estrutura de diretórios
- Plugin — entrada do plugin e ciclo de vida
load() - FlowEngine → Extensão de blocos — BlockModel, CollectionBlockModel, TableBlockModel
- FlowEngine → Extensão de campos — ClickableFieldModel, bindModelToInterface
- FlowEngine → Extensão de ações — ActionModel, ActionSceneEnum
- i18n internacionalização — escrita de arquivos de tradução e uso de
tExpr() - Visão geral do desenvolvimento server-side — fundamentos de plugins do servidor
Resultado final
Vamos construir um plugin de gestão de "Tarefas (To-Do)" com as seguintes capacidades:
- O servidor define uma data table
todoItems; ao instalar o plugin, dados de exemplo são automaticamente inseridos - O cliente herda de
TableBlockModel, fornecendo um bloco de tabela pronto para uso (colunas, paginação, barra de ações etc.) - Componente de campo personalizado — renderiza o campo priority como uma Tag colorida
- Botão de ação personalizado — botão "Nova tarefa" que, ao clicar, abre uma modal para preencher o formulário e criar o registro
O código-fonte completo está em @nocobase-example/plugin-custom-table-block-resource. Se quiser executar localmente para ver o resultado:
A seguir, montamos esse plugin do zero, passo a passo.
Passo 1: criar o esqueleto do plugin
Na raiz do repositório, execute:
Para mais detalhes, veja Escreva seu primeiro plugin.
Passo 2: definir a data table (server)
Crie src/server/collections/todoItems.ts. O NocoBase carrega automaticamente as definições de collection desse diretório:
Diferente do exemplo de página de configurações, aqui não é preciso registrar resource manualmente — o NocoBase gera automaticamente as APIs CRUD padrão para cada collection (list, get, create, update, destroy).
Passo 3: configurar permissões e dados de exemplo (server)
Edite src/server/plugin.ts. Em load(), configure as permissões ACL; em install(), insira os dados de exemplo:
Pontos-chave:
acl.allow()—['list', 'get', 'create', 'update', 'destroy']libera o CRUD completo;'loggedIn'indica que usuários logados podem acessarinstall()— só executa na primeira instalação do plugin; ideal para inserir dados iniciaisthis.db.getRepository()— obtém o objeto de operação de dados pelo nome da collection- Não é necessário
resourceManager.define()— o NocoBase gera automaticamente as APIs CRUD para a collection
Passo 4: criar o modelo do bloco (client)
Crie src/client-v2/models/TodoBlockModel.tsx. Herdando de TableBlockModel, você ganha diretamente as capacidades completas do bloco de tabela — colunas de campo, barra de ações, paginação, ordenação etc., sem precisar escrever renderComponent.

Em desenvolvimento real de plugins, se você não precisa personalizar o TableBlockModel, na verdade não é preciso herdá-lo nem registrá-lo — basta que o usuário escolha "Tabela" ao adicionar o bloco. Aqui o TodoBlockModel é escrito apenas para demonstrar a definição e o registro de um modelo de bloco. O TableBlockModel cuida de tudo o mais (colunas de campo, barra de ações, paginação etc.).
Com filterCollection, restringimos esse bloco à data table todoItems — ao adicionar "Todo block", a lista de seleção de data table mostrará apenas todoItems, sem outras tabelas não relacionadas.

Passo 5: criar o componente de campo personalizado (client)
Crie src/client-v2/models/PriorityFieldModel.tsx. Renderizar o campo priority com Tag colorida fica muito mais visual que texto puro:

Após registrar, na configuração da coluna priority, o menu suspenso "Componente de campo" terá a opção "Priority tag".
Passo 6: criar o botão de ação personalizado (client)
Crie src/client-v2/models/NewTodoActionModel.tsx. Ao clicar em "Nova tarefa", usamos ctx.viewer.dialog() para abrir uma modal e criar um registro após preencher o formulário:

Pontos-chave:
ActionSceneEnum.collection— o botão aparece na barra de ações no topo do blocoon: 'click'— escuta o eventoclickdo botão viaregisterFlowctx.viewer.dialog()— capacidade integrada de modal do NocoBase;contentrecebe uma função, e o parâmetroviewpermite chamarview.close()para fechar a modalresource.create(values)— chama a API create da data table para criar um registro; após a criação, a tabela é atualizada automaticamenteobservable+observer— usar o gerenciamento de estado reativo do flow-engine no lugar deuseState; o componente reage automaticamente às mudanças emformState.loading
Passo 7: adicionar arquivos multilíngues
Edite os arquivos de tradução em src/locale/ do plugin:
Adicionar um novo arquivo de idioma pela primeira vez requer reiniciar a aplicação para ter efeito.
Para mais informações sobre escrita de arquivos de tradução e uso de tExpr(), veja i18n internacionalização.
Passo 8: registrar no plugin (client)
Edite src/client-v2/plugin.tsx. Há duas coisas a fazer: registrar os modelos e registrar todoItems na fonte de dados do cliente.
Registrar manualmente uma data table no código do plugin via addCollection é uma prática rara, usada aqui apenas para demonstrar o fluxo completo de integração front-back. Em projetos reais, as data tables normalmente são criadas e configuradas pelo usuário na interface do NocoBase, ou gerenciadas via API / MCP, sem necessidade de registro explícito no código do cliente do plugin.
A tabela definida via defineCollection é uma tabela interna do servidor; por padrão, não aparece na lista de seleção de data tables do bloco. Após registrá-la manualmente com addCollection, o usuário poderá selecionar todoItems ao adicionar o bloco.

Pontos-chave:
registerModelLoaders— carregamento sob demanda registrando os três modelos: bloco, campo e açãothis.app.eventBus— barramento de eventos da aplicação, usado para escutar eventos do ciclo de vida- Evento
dataSource:loaded— disparado após o carregamento da fonte de dados. É preciso chamaraddCollectionno callback desse evento, porqueensureLoaded()é executado apósload()e chamasetCollections(), que limpa todas as collections antes de reconfigurá-las a partir do servidor — chamaraddCollectiondiretamente emload()faria com que ele fosse sobrescrito addCollection()— registra a collection na fonte de dados do cliente. Os campos precisam ter as propriedadesinterfaceeuiSchemapara que o NocoBase saiba como renderizá-losfilterTargetKey: 'id'— obrigatório, especifica o campo usado para identificar de forma única o registro (geralmente a chave primária). Sem isso, a collection não aparece na lista de seleção de data tables do bloco- O
defineCollectionno servidor é responsável por criar a tabela física e o mapeamento ORM; oaddCollectionno cliente é responsável por informar à UI a existência dessa tabela — os dois lados precisam funcionar em conjunto para a integração front-back
Passo 9: ativar o plugin
Após ativar:
- Crie uma nova página, clique em "Adicionar bloco", selecione "Todo block" e vincule à data table
todoItems - A tabela carrega os dados automaticamente, exibindo as colunas de campo, paginação etc.
- Em "Configurar ações", adicione o botão "New todo"; ao clicar, abre uma modal para preencher o formulário e criar registros
- Na configuração da coluna priority, em "Componente de campo", troque para "Priority tag" — priority será exibido como Tag colorida
Código-fonte completo
- @nocobase-example/plugin-custom-table-block-resource — exemplo completo de plugin de gestão de dados com integração front-back
Resumo
Capacidades usadas neste exemplo:
Links relacionados
- Escreva seu primeiro plugin — criar o esqueleto do plugin do zero
- Visão geral do FlowEngine — uso básico do FlowModel e registerFlow
- FlowEngine → Extensão de blocos — BlockModel, TableBlockModel
- FlowEngine → Extensão de campos — ClickableFieldModel, bindModelToInterface
- FlowEngine → Extensão de ações — ActionModel, ActionSceneEnum
- Construir um bloco de exibição personalizado — exemplo básico de BlockModel
- Construir um componente de campo personalizado — exemplo básico de FieldModel
- Construir um botão de ação personalizado — exemplo básico de ActionModel
- Visão geral do desenvolvimento server-side — fundamentos de plugins do servidor
- Server → Collections — defineCollection e addCollection
- Resumo da Resource API — assinaturas completas dos métodos de MultiRecordResource / SingleRecordResource
- Plugin — entrada do plugin e ciclo de vida load()
- i18n internacionalização — escrita de arquivos de tradução e uso de tExpr
- Server → Controle de permissões ACL — configuração de permissões
- Server → Plugin — ciclo de vida do plugin no servidor
- Context → Capacidades comuns — ctx.viewer, ctx.message etc.
- Desenvolvimento de Component — uso de Antd Form e outros componentes
- Documentação completa do FlowEngine — referência completa de FlowModel, Flow e Context

