Faire un plugin de gestion de données front+back
Les exemples précédents étaient soit purement côté client (bloc, champ, action), soit côté client + API simple (page de configuration). Cet exemple présente un scénario plus complet — le serveur définit une table de données, le client étend TableBlockModel pour bénéficier de capacités de tableau complètes, et on y ajoute des composants de champ et boutons d'action personnalisés, le tout formant un plugin de gestion de données avec CRUD.
Cet exemple combine ce qui a été vu dans les précédents — bloc, champ, action — et montre le flux de développement complet d'un plugin.
Il est conseillé de connaître les contenus suivants pour faciliter le développement :
- Écrire votre premier plugin — création d'un plugin et structure du répertoire
- Plugin — point d'entrée du plugin et cycle de vie
load() - FlowEngine → Extension de bloc — BlockModel, CollectionBlockModel, TableBlockModel
- FlowEngine → Extension de champ — ClickableFieldModel, bindModelToInterface
- FlowEngine → Extension d'action — ActionModel, ActionSceneEnum
- Internationalisation i18n — écriture des fichiers de traduction et utilisation de
tExpr() - Aperçu du développement côté serveur — bases du plugin serveur
Résultat final
Nous allons créer un plugin de gestion de « tâches à faire » avec les capacités suivantes :
- Le serveur définit une table de données
todoItems, et insère automatiquement des données d'exemple à l'installation du plugin - Le client étend
TableBlockModelpour un bloc tableau prêt à l'emploi (colonnes de champs, pagination, barre d'actions, etc.) - Composant de champ personnalisé — affiche le champ priority avec un Tag coloré
- Bouton d'action personnalisé — bouton « Nouvelle tâche » qui ouvre une boîte de dialogue avec un formulaire pour créer un enregistrement
Code source complet : @nocobase-example/plugin-custom-table-block-resource. Pour le faire tourner directement en local :
Construisons ce plugin pas à pas, à partir de zéro.
Étape 1 : créer le squelette du plugin
À la racine du dépôt :
Voir Écrire votre premier plugin pour les détails.
Étape 2 : définir la table de données (côté serveur)
Créez src/server/collections/todoItems.ts. NocoBase chargera automatiquement les définitions de collections de ce répertoire :
Contrairement à l'exemple de la page de configuration, ici il n'est pas nécessaire d'enregistrer une ressource manuellement — NocoBase génère automatiquement les endpoints CRUD standards (list, get, create, update, destroy) pour chaque collection.
Étape 3 : configurer les permissions et les données d'exemple (côté serveur)
Modifiez src/server/plugin.ts ; configurez les permissions ACL dans load() et insérez les données d'exemple dans install() :
Quelques points clés :
acl.allow()—['list', 'get', 'create', 'update', 'destroy']ouvre les permissions CRUD complètes ;'loggedIn'signifie que tout utilisateur connecté peut accéderinstall()— ne s'exécute qu'à la première installation du plugin, idéal pour l'écriture des données initialesthis.db.getRepository()— récupère l'objet d'opération sur les données via le nom de collection- Pas besoin de
resourceManager.define()— NocoBase génère automatiquement les endpoints CRUD pour les collections
Étape 4 : créer le modèle de bloc (côté client)
Créez src/client-v2/models/TodoBlockModel.tsx. En étendant TableBlockModel, vous obtenez immédiatement toutes les capacités d'un bloc tableau — colonnes de champs, barre d'actions, pagination, tri, etc., sans avoir à écrire renderComponent.

Dans le développement réel d'un plugin, si vous n'avez pas besoin de personnaliser TableBlockModel, vous pouvez vous passer d'étendre et d'enregistrer ce bloc, et laisser l'utilisateur choisir « Tableau » lors de l'ajout d'un bloc. Ici, nous écrivons TodoBlockModel qui étend TableBlockModel uniquement pour montrer le flux de définition et d'enregistrement d'un modèle de bloc. TableBlockModel se charge de tout le reste (colonnes, barre d'actions, pagination, etc.).
filterCollection limite ce bloc à la table todoItems — quand l'utilisateur ajoute « Todo block », seule todoItems apparaît dans la liste de sélection des tables, sans autre table sans rapport.

Étape 5 : créer le composant de champ personnalisé (côté client)
Créez src/client-v2/models/PriorityFieldModel.tsx. Affiche le champ priority avec un Tag coloré, bien plus parlant qu'un texte brut :

Une fois enregistré, dans la configuration de la colonne priority du tableau, vous pourrez basculer le menu déroulant « Composant de champ » sur « Priority tag ».
Étape 6 : créer le bouton d'action personnalisé (côté client)
Créez src/client-v2/models/NewTodoActionModel.tsx. Au clic sur « Nouvelle tâche », ctx.viewer.dialog() ouvre une boîte de dialogue ; après remplissage du formulaire, l'enregistrement est créé :

Quelques points clés :
ActionSceneEnum.collection— le bouton apparaît dans la barre d'actions en haut du blocon: 'click'— écoute l'événementclickdu bouton viaregisterFlowctx.viewer.dialog()— capacité de boîte de dialogue intégrée à NocoBase ;contentreçoit une fonction dont le paramètreviewpermet d'appelerview.close()pour fermerresource.create(values)— appelle l'endpoint create de la table pour créer un enregistrement ; le tableau se rafraîchit automatiquementobservable+observer— gestion d'état réactive fournie par flow-engine, en remplacement deuseState; le composant réagit automatiquement aux changements deformState.loading
Étape 7 : ajouter les fichiers de traduction
Modifiez les fichiers de traduction sous src/locale/ du plugin :
L'ajout initial des fichiers de langue nécessite un redémarrage de l'application pour prendre effet.
Pour l'écriture des fichiers de traduction et plus d'utilisations de tExpr(), voir Internationalisation i18n.
Étape 8 : enregistrer dans le plugin (côté client)
Modifiez src/client-v2/plugin.tsx. Deux choses à faire : enregistrer les modèles et déclarer todoItems auprès de la source de données client.
Enregistrer une table de données manuellement via addCollection dans le code du plugin est une pratique peu fréquente ; nous le faisons ici pour démontrer le flux complet d'intégration front-back. Dans un projet réel, les tables de données sont généralement créées et configurées par l'utilisateur dans l'interface NocoBase, ou gérées via API / MCP, sans avoir besoin d'être enregistrées explicitement dans le code client du plugin.
Les tables définies via defineCollection sont des tables internes côté serveur et n'apparaissent pas par défaut dans la liste de sélection des tables des blocs. Une fois enregistrées manuellement via addCollection, l'utilisateur pourra choisir todoItems lors de l'ajout d'un bloc.

Quelques points clés :
registerModelLoaders— enregistre les trois modèles avec chargement à la demande : bloc, champ, actionthis.app.eventBus— bus d'événements au niveau de l'application, sert à écouter les événements de cycle de vie- Événement
dataSource:loaded— déclenché après le chargement de la source de données.addCollectiondoit être appelé dans le callback de cet événement, carensureLoaded()s'exécute aprèsload()et vide d'abord puis rétablit toutes les collections — appeleraddCollectiondirectement dansload()serait écrasé addCollection()— déclare la collection auprès de la source de données client. Les champs doivent comporter les attributsinterfaceetuiSchemapour que NocoBase sache comment les afficherfilterTargetKey: 'id'— doit être défini ; il indique le champ qui identifie de manière unique un enregistrement (généralement la clé primaire). Sans cela, la collection n'apparaîtra pas dans la liste de sélection des tablesdefineCollectioncôté serveur crée la table physique et le mapping ORM ;addCollectioncôté client fait connaître la table à l'UI — la coopération des deux côtés rend l'intégration front-back possible
Étape 9 : activer le plugin
Une fois activé :
- Créez une nouvelle page, cliquez sur « Ajouter un bloc », choisissez « Todo block » et liez-le à la table
todoItems - Le tableau charge automatiquement les données et affiche les colonnes, la pagination, etc.
- Dans « Configurer les actions », ajoutez le bouton « New todo » : un clic ouvre une boîte de dialogue pour remplir le formulaire et créer un enregistrement
- Dans la colonne priority, basculez « Composant de champ » sur « Priority tag » : la priorité s'affichera avec un Tag coloré
Code source complet
- @nocobase-example/plugin-custom-table-block-resource — exemple complet de plugin de gestion de données front+back
Récapitulatif
Capacités utilisées dans cet exemple :
Liens connexes
- Écrire votre premier plugin — créer le squelette d'un plugin de zéro
- Aperçu de FlowEngine — utilisation de base de FlowModel et registerFlow
- FlowEngine → Extension de bloc — BlockModel, TableBlockModel
- FlowEngine → Extension de champ — ClickableFieldModel, bindModelToInterface
- FlowEngine → Extension d'action — ActionModel, ActionSceneEnum
- Faire un bloc d'affichage personnalisé — exemple de base BlockModel
- Faire un composant de champ personnalisé — exemple de base FieldModel
- Faire un bouton d'action personnalisé — exemple de base ActionModel
- Aperçu du développement côté serveur — bases du plugin serveur
- Serveur → Tables de données Collections — defineCollection et addCollection
- Aide-mémoire Resource API — signatures complètes des méthodes de MultiRecordResource / SingleRecordResource
- Plugin — point d'entrée et cycle de vie load()
- Internationalisation i18n — écriture des fichiers de traduction et utilisation de tExpr
- Serveur → Contrôle d'accès ACL — configuration des permissions
- Serveur → Plugin — cycle de vie du plugin serveur
- Context → Capacités courantes — ctx.viewer, ctx.message, etc.
- Développement de composants Component — utilisation des composants Antd Form, etc.
- Documentation complète FlowEngine — référence complète FlowModel, Flow, Context

