FlowEngine

NocoBase では、FlowEngine(フローエンジン) はビジュアル設定を駆動するコアエンジンです。NocoBase の画面上のブロック、フィールド、操作ボタンはすべて FlowEngine によって管理されています。レンダリング、設定パネル、設定の永続化を含みます。

20260403215904

プラグイン開発者にとって、FlowEngine は2つのコア概念を提供します:

  • FlowModel — 設定可能なコンポーネントモデル。UI のレンダリングと props の管理を担当
  • Flow — 設定フロー。コンポーネントの設定パネルとデータ処理ロジックを定義

コンポーネントを「ブロックの追加 / フィールド / 操作」メニューに表示したり、ユーザーが画面上でビジュアル設定できるようにする必要がある場合は、FlowModel でラップします。これらの機能が不要な場合は普通の React コンポーネントで十分です。Component vs FlowModel をご覧ください。

FlowModel とは

普通の React コンポーネントとは異なり、FlowModel は UI のレンダリングだけでなく、props のソース、設定パネルの定義、設定の永続化も管理します。簡単に言えば、普通のコンポーネントの props はハードコードされますが、FlowModel の props は Flow によって動的に生成されます。

FlowEngine の全体的なアーキテクチャを深く理解したい場合は、FlowEngine 完全ドキュメントをご覧ください。以下ではプラグイン開発者の視点から、使い方を紹介します。

最小限の例

FlowModel の作成から登録まで、3つのステップに分かれます:

1. 基底クラスを継承し、renderComponent を実装

// models/HelloBlockModel.tsx
import React from 'react';
import { BlockModel } from '@nocobase/client-v2';
import { tExpr } from '@nocobase/flow-engine';

export class HelloBlockModel extends BlockModel {
  renderComponent() {
    return (
      <div>
        <h3>Hello FlowEngine!</h3>
        <p>これはカスタムブロックです。</p>
      </div>
    );
  }
}

// define() でメニュー内の表示名を設定
HelloBlockModel.define({
  label: tExpr('Hello block'),
});

renderComponent() はこのモデルのレンダリングメソッドで、React コンポーネントの render() に相当します。tExpr() は遅延翻訳に使用します。define() はモジュール読み込み時に実行されますが、この時点では i18n がまだ初期化されていないためです。詳しくは Context 共通機能 → tExpr をご覧ください。

2. Plugin で登録

// plugin.tsx
import { Plugin } from '@nocobase/client-v2';

export class MyPlugin extends Plugin {
  async load() {
    this.flowEngine.registerModelLoaders({
      HelloBlockModel: {
        // 遅延読み込み。初めて使用される時にモジュールをロード
        loader: () => import('./models/HelloBlockModel'),
      },
    });
  }
}

3. 画面上で使用

登録完了後、プラグインを起動して(プラグインの有効化はプラグイン開発概要を参照)、NocoBase の画面で新しいページを作成し、「ブロックの追加」をクリックすると「Hello block」が表示されます。

20260403221815

registerFlow で設定項目を追加

レンダリングできるだけでは不十分です。FlowModel のコアバリューは設定可能であることです。registerFlow() でモデルに設定パネルを追加し、ユーザーが画面上でプロパティを変更できるようにします。

例えば HTML コンテンツの編集をサポートするブロック:

// models/SimpleBlockModel.tsx
import React from 'react';
import { BlockModel } from '@nocobase/client-v2';
import { tExpr } from '@nocobase/flow-engine';

export class SimpleBlockModel extends BlockModel {
  renderComponent() {
    // this.props の値は Flow handler での設定から取得
    return <div dangerouslySetInnerHTML={{ __html: this.props.html }} />;
  }
}

SimpleBlockModel.define({
  label: tExpr('Simple block'),
});

SimpleBlockModel.registerFlow({
  key: 'flow1',
  title: tExpr('Simple Block Flow'),
  on: 'beforeRender', // レンダリング前に実行
  steps: {
    editHtml: {
      title: tExpr('Edit HTML Content'),
      // uiSchema で設定パネルの UI を定義
      uiSchema: {
        html: {
          type: 'string',
          title: tExpr('HTML Content'),
          'x-decorator': 'FormItem',
          'x-component': 'Input.TextArea',
        },
      },
      // デフォルト値
      defaultParams: {
        html: `<h3>This is a simple block</h3>
<p>You can edit the HTML content.</p>`,
      },
      // handler で設定パネルの値を model の props に設定
      handler(ctx, params) {
        ctx.model.props.html = params.html;
      },
    },
  },
});

ここでの重要なポイント:

  • on: 'beforeRender' — この Flow がレンダリング前に実行されることを意味し、設定パネルの値がレンダリング前に this.props に書き込まれる
  • uiSchema — JSON Schema 形式で設定パネルの UI を定義。構文は UI Schema を参照
  • handler(ctx, params)params はユーザーが設定パネルで入力した値。ctx.model.props でモデルに設定する
  • defaultParams — 設定パネルのデフォルト値

uiSchema のよく使う書き方

uiSchema は JSON Schema ベースで、v2 の uiSchema 構文と互換性がありますが、使用シーンは限定的です。主に Flow の設定パネルでフォーム UI を記述するために使います。ほとんどのランタイムコンポーネントレンダリングは Antd コンポーネントを直接使って実装することを推奨し、uiSchema を経由する必要はありません。

ここでは最もよく使うコンポーネントを挙げます(完全なリファレンスは UI Schema を参照):

uiSchema: {
  // テキスト入力
  title: {
    type: 'string',
    title: 'タイトル',
    'x-decorator': 'FormItem',
    'x-component': 'Input',
  },
  // 複数行テキスト
  content: {
    type: 'string',
    title: 'コンテンツ',
    'x-decorator': 'FormItem',
    'x-component': 'Input.TextArea',
  },
  // ドロップダウン選択
  type: {
    type: 'string',
    title: 'タイプ',
    'x-decorator': 'FormItem',
    'x-component': 'Select',
    enum: [
      { label: 'プライマリ', value: 'primary' },
      { label: 'デフォルト', value: 'default' },
      { label: '破線', value: 'dashed' },
    ],
  },
  // スイッチ
  bordered: {
    type: 'boolean',
    title: 'ボーダーを表示',
    'x-decorator': 'FormItem',
    'x-component': 'Switch',
  },
}

各フィールドに 'x-decorator': 'FormItem' を付けると、タイトルとレイアウトが自動的に適用されます。

define() のパラメータ説明

FlowModel.define() はモデルのメタデータを設定し、メニュー内での表示方法を制御します。プラグイン開発で最もよく使うのは label ですが、他のパラメータもサポートしています:

パラメータ説明
labelstring | ReactNode「ブロックの追加 / フィールド / 操作」メニューでの表示名。tExpr() 遅延翻訳をサポート
iconReactNodeメニュー内のアイコン
sortnumberソートウェイト。数値が小さいほど前に表示。デフォルト 0
hideboolean | (ctx) => booleanメニュー内で非表示にするかどうか。動的判断をサポート
groupstringグループ識別子。特定のメニューグループに分類するために使用
childrenSubModelItem[] | (ctx) => SubModelItem[]サブメニュー項目。非同期関数での動的構築をサポート
toggleableboolean | (model) => booleanトグル動作をサポートするかどうか(同一親配下で一意)
searchablebooleanサブメニューで検索を有効にするかどうか

ほとんどのプラグインでは label の設定だけで十分です:

MyBlockModel.define({
  label: tExpr('My block'),
});

ソートや非表示の制御が必要な場合は sorthide を追加できます:

MyBlockModel.define({
  label: tExpr('My block'),
  sort: 10,       // 後方に表示
  hide: (ctx) => !ctx.someCondition,  // 条件に応じて非表示
});

FlowModel 基底クラスの選択

NocoBase は複数の FlowModel 基底クラスを提供しており、拡張するタイプに応じて選択します:

基底クラス用途詳細ドキュメント
BlockModel通常のブロックブロック拡張
DataBlockModel独自のデータ取得が必要なブロックブロック拡張
CollectionBlockModelデータテーブルにバインド、自動データ取得ブロック拡張
TableBlockModel完全なテーブルブロック、フィールド列・操作バーなど組み込み済みブロック拡張
FieldModelフィールドコンポーネントフィールド拡張
ActionModel操作ボタン操作拡張

通常、テーブルブロックには TableBlockModel(最もよく使われ、すぐに使える)、レンダリングの完全カスタマイズには CollectionBlockModelBlockModel、フィールドには FieldModel、操作ボタンには ActionModel を使います。

関連リンク