Crear un plugin de gestión de datos full-stack
Los ejemplos anteriores eran o bien puramente de cliente (bloques, campos, acciones) o bien cliente + un endpoint sencillo (página de configuración). Este ejemplo presenta un escenario más completo: en el servidor se define una tabla y, en el cliente, se hereda de TableBlockModel para obtener una tabla completa, con campo personalizado y acción personalizada, formando un plugin de gestión de datos con CRUD.
Aquí se combinan los conceptos vistos antes (bloques, campos, acciones) en un único plugin completo.
Se recomienda revisar antes los siguientes contenidos:
- Crear el primer plugin: creación del plugin y estructura de directorios.
- Plugin: entrada del plugin y ciclo de vida de
load(). - FlowEngine → Extensión de bloques: BlockModel, CollectionBlockModel, TableBlockModel.
- FlowEngine → Extensión de campos: ClickableFieldModel, bindModelToInterface.
- FlowEngine → Extensión de acciones: ActionModel, ActionSceneEnum.
- Internacionalización (i18n): archivos de traducción y
tExpr(). - Visión general del desarrollo en servidor: bases del plugin de servidor.
Resultado final
Vamos a crear un plugin de "tareas pendientes" con las siguientes capacidades:
- En el servidor se define una tabla
todoItemsy se inyectan datos de ejemplo al instalar el plugin. - En el cliente se hereda de
TableBlockModelpara obtener un bloque de tabla listo para usar (columnas, paginación, barra de acciones, etc.). - Componente de campo personalizado: el campo
priorityse muestra con un Tag de color. - Acción personalizada: botón "New todo" que abre un diálogo con un formulario para crear registros.
Código fuente completo en @nocobase-example/plugin-custom-table-block-resource. Para ejecutarlo en local:
A continuación se construye el plugin paso a paso.
Paso 1: crear el esqueleto del plugin
Desde la raíz del repositorio:
Para más detalles, consulte Crear el primer plugin.
Paso 2: definir la tabla (servidor)
Cree src/server/collections/todoItems.ts. NocoBase carga automáticamente las definiciones de Collection de este directorio:
A diferencia del ejemplo de la página de configuración, aquí no es necesario registrar manualmente un resource: NocoBase genera automáticamente las acciones CRUD estándar (list, get, create, update, destroy) para cada Collection.
Paso 3: configurar permisos y datos de ejemplo (servidor)
Edite src/server/plugin.ts. En load() configure los permisos ACL y en install() inserte datos de ejemplo:
Puntos clave:
acl.allow():['list', 'get', 'create', 'update', 'destroy']abre los permisos completos de CRUD;'loggedIn'indica que basta con estar autenticado.install(): solo se ejecuta la primera vez que se instala el plugin; ideal para datos iniciales.this.db.getRepository(): devuelve el objeto de operaciones de datos a partir del nombre de la Collection.- No es necesario
resourceManager.define(): NocoBase genera las acciones CRUD automáticamente.
Paso 4: crear el modelo del bloque (cliente)
Cree src/client-v2/models/TodoBlockModel.tsx. Heredar de TableBlockModel proporciona directamente toda la funcionalidad de un bloque de tabla (columnas, barra de acciones, paginación, ordenación, etc.); no es necesario implementar renderComponent.

En el desarrollo real, si no necesita personalizar TableBlockModel, no es indispensable heredarlo y registrarlo: el usuario puede elegir directamente "Table" al añadir el bloque. En este tutorial se hace así para mostrar el flujo de definición y registro de un modelo de bloque, por eso se escribe TodoBlockModel heredando de TableBlockModel. TableBlockModel se ocupa de todo lo demás (columnas, barra de acciones, paginación, etc.).
Mediante filterCollection restringimos el bloque a la Collection todoItems: cuando el usuario añada el "Todo block", la lista de Collections solo mostrará todoItems, sin el resto de tablas no relacionadas.

Paso 5: crear el componente de campo personalizado (cliente)
Cree src/client-v2/models/PriorityFieldModel.tsx. Mostrar el campo priority con un Tag de color es mucho más intuitivo que mostrarlo como texto plano:

Tras el registro, en la configuración de la columna priority de la tabla, el desplegable "Componente de campo" permitirá cambiar a "Priority tag".
Paso 6: crear el botón de acción personalizado (cliente)
Cree src/client-v2/models/NewTodoActionModel.tsx. Al pulsar "New todo" se abre un diálogo con ctx.viewer.dialog(); tras enviar el formulario se crea el registro:

Puntos clave:
ActionSceneEnum.collection: el botón aparece en la barra de acciones superior del bloque.on: 'click': conregisterFlowse escucha el eventoclickdel botón.ctx.viewer.dialog(): capacidad de diálogo integrada en NocoBase.contentrecibe una función cuyo parámetroviewpermite cerrar el diálogo conview.close().resource.create(values): invoca la accióncreatede la Collection; tras la creación, la tabla se refresca automáticamente.observable+observer: gestión reactiva de estado provista por flow-engine; el componente reacciona automáticamente al cambio deformState.loading.
Paso 7: añadir los archivos de traducción
Edite los archivos en src/locale/:
La primera vez que añada un archivo de idioma debe reiniciar la aplicación para que surta efecto.
Para más detalles sobre los archivos de traducción y tExpr(), consulte Internacionalización (i18n).
Paso 8: registrar en el plugin (cliente)
Edite src/client-v2/plugin.tsx. Hay dos cosas que hacer: registrar los modelos y registrar todoItems en la fuente de datos del cliente.
Registrar manualmente una Collection con addCollection desde el código del plugin es una práctica poco habitual; aquí solo se hace para demostrar el flujo full-stack completo. En proyectos reales, las Collections suelen crearse y configurarse desde la interfaz de NocoBase, o gestionarse vía API / MCP, sin necesidad de registrarlas explícitamente desde el cliente del plugin.
Las Collections definidas con defineCollection son tablas internas del servidor y, por defecto, no aparecen en la lista de Collections cuando se añade un bloque. Tras registrarlas con addCollection, el usuario podrá seleccionar todoItems al añadir un bloque.

Puntos clave:
registerModelLoaders: registro con carga bajo demanda de los tres modelos: bloque, campo y acción.this.app.eventBus: bus de eventos a nivel de aplicación, sirve para escuchar eventos del ciclo de vida.- Evento
dataSource:loaded: se dispara al terminar de cargarse la fuente de datos. Es obligatorio llamar aaddCollectiondentro del callback de este evento, porqueensureLoaded()se ejecuta después deload()y limpia todas las Collections antes de volver a fijarlas; llamarlo directamente enload()haría que la operación se sobrescribiera. addCollection(): registra la Collection en la fuente de datos del cliente. Los campos deben llevarinterfaceyuiSchemapara que NocoBase sepa cómo renderizarlos.filterTargetKey: 'id': obligatorio; especifica el campo que identifica unívocamente el registro (normalmente la clave primaria). Si no se configura, la Collection no aparece en la lista del bloque.- En el servidor,
defineCollectionse encarga de crear la tabla física y el mapeo ORM; en el cliente,addCollectionpermite a la UI saber que esa tabla existe; la combinación de ambos completa la integración full-stack.
Paso 9: activar el plugin
Una vez activado:
- Cree una página, haga clic en "Añadir bloque", seleccione "Todo block" y enlácelo a la Collection
todoItems. - La tabla cargará los datos automáticamente y mostrará columnas, paginación, etc.
- Desde "Configurar acciones", añada el botón "New todo": al pulsarlo se abrirá un diálogo con el formulario para crear registros.
- En la columna
priority, dentro de "Componente de campo", cambie a "Priority tag" para que el valor se muestre con un Tag de color.
Código fuente completo
- @nocobase-example/plugin-custom-table-block-resource: plugin de gestión de datos full-stack completo.
Resumen
Capacidades utilizadas en este ejemplo:
Enlaces relacionados
- Crear el primer plugin: crear el esqueleto desde cero.
- Visión general de FlowEngine: uso básico de FlowModel y
registerFlow. - FlowEngine → Extensión de bloques: BlockModel, TableBlockModel.
- FlowEngine → Extensión de campos: ClickableFieldModel, bindModelToInterface.
- FlowEngine → Extensión de acciones: ActionModel, ActionSceneEnum.
- Crear un bloque de presentación personalizado: ejemplo básico de BlockModel.
- Crear un componente de campo personalizado: ejemplo básico de FieldModel.
- Crear un botón de acción personalizado: ejemplo básico de ActionModel.
- Visión general del desarrollo en servidor: bases del plugin de servidor.
- Servidor → Collections:
defineCollectionyaddCollection. - Tabla rápida de Resource API: firmas completas de
MultiRecordResource/SingleRecordResource. - Plugin: entrada del plugin y ciclo de vida.
- Internacionalización (i18n): archivos de traducción y
tExpr. - Servidor → ACL: configuración de permisos.
- Servidor → Plugin: ciclo de vida del plugin de servidor.
- Context → Capacidades comunes:
ctx.viewer,ctx.message, etc. - Desarrollo de Component: uso de Form de Antd, etc.
- Documentación completa de FlowEngine: referencia completa.

