Plugin Development Cheatsheet

When writing plugins, you often wonder "which file should I put this in and which API should I call?" This cheatsheet helps you quickly find the answer.

Plugin Directory Structure

Create a plugin with yarn pm create @my-project/plugin-name, which automatically generates the following directory structure. Do not create directories manually to avoid missing registration steps that would cause the plugin to not work. See Writing Your First Plugin for details.

plugin-name/
├── src/
   ├── client-v2/              # Client-side code (v2)
   ├── plugin.tsx          # Client plugin entry
   ├── locale.ts           # useT / tExpr translation hook
   ├── models/             # FlowModel (blocks, fields, actions)
   └── pages/              # Page components
   ├── client/                 # Client-side code (v1, compatible)
   ├── plugin.tsx
   ├── locale.ts
   ├── models/
   └── pages/
   ├── server/                 # Server-side code
   ├── plugin.ts           # Server plugin entry
   └── collections/        # Data table definitions
   └── locale/                 # Multilingual translation files
       ├── zh-CN.json
       └── en-US.json
├── client-v2.js                # Root entry (points to build output)
├── client-v2.d.ts
├── client.js
├── client.d.ts
├── server.js
├── server.d.ts
└── package.json

Client-Side: What I Want to Do -> How to Write It

What I want to doWhich fileWhich APIDocs
Register a page routeplugin.tsx's load()this.router.add()Router
Register a plugin settings pageplugin.tsx's load()pluginSettingsManager.addMenuItem() + addPageTabItem()Router
Register a custom blockplugin.tsx's load()this.flowEngine.registerModelLoaders()FlowEngine - Block Extension
Register a custom fieldplugin.tsx's load()this.flowEngine.registerModelLoaders()FlowEngine - Field Extension
Register a custom actionplugin.tsx's load()this.flowEngine.registerModelLoaders()FlowEngine - Action Extension
Make an internal table appear in block data source selectionplugin.tsx's load()mainDS.addCollection()Collections
Translate plugin textlocale/zh-CN.json + locale/en-US.jsoni18n Internationalization

Server-Side: What I Want to Do -> How to Write It

What I want to doWhich fileWhich APIDocs
Define a data tableserver/collections/xxx.tsdefineCollection()Collections
Extend an existing data tableserver/collections/xxx.tsextendCollection()Collections
Register a custom API endpointserver/plugin.ts's load()this.app.resourceManager.define()ResourceManager
Configure API permissionsserver/plugin.ts's load()this.app.acl.allow()ACL
Write initial data on plugin installserver/plugin.ts's install()this.db.getRepository().create()Plugin

FlowModel Cheatsheet

What I want to doWhich base class to extendKey API
Build a display-only blockBlockModelrenderComponent() + define()
Build a data-bound block (custom rendering)CollectionBlockModelcreateResource() + renderComponent()
Build a full table block (customizing the built-in table)TableBlockModelfilterCollection() + customModelClasses
Build a field display componentClickableFieldModelrenderComponent(value) + bindModelToInterface()
Build an action buttonActionModelstatic scene + registerFlow({ on: 'click' })

Translation Method Cheatsheet

ContextWhat to useWhere to import
In Plugin load()this.t('key')Built into Plugin base class
In React componentsconst t = useT(); t('key')locale.ts
In FlowModel static definitions (define(), registerFlow())tExpr('key')locale.ts

Common API Call Cheatsheet

What I want to doIn PluginIn Components
Send an API requestthis.context.api.request()ctx.api.request()
Get translationsthis.t()useT()
Get loggerthis.context.loggerctx.logger
Register a routethis.router.add()
Navigate to a pagectx.router.navigate()
Open a dialogctx.viewer.dialog()