はじめに
承認フローや自動化シナリオを画面上で組み立てられる「ワークフロービルダー」、業務系のSaaSでよく見かけますよね。ステップをドラッグして並べ、条件分岐を挟み、JSONとして保存する。仕組みは単純そうに見えるのですが、いざ自分で作ろうとすると一気に沼にハマります。SVGでキャンバスを描画し、ドラッグ&ドロップの当たり判定を実装し、Undo/Redoを管理し、ステップごとの編集フォームを出し分ける……これを全部自前で書くのは、正直割に合いません。
Sequential-Workflow-Designerは、この「ワークフロー画面そのもの」を提供してくれるJavaScriptライブラリです。特徴は外部依存が一切ないこと。TypeScriptで書かれ、描画にはSVGを使っており、React・Angular・Svelte・素のJavaScriptのどれでも組み込めます。ワークフローエンジンとは切り離された汎用コンポーネントなので、承認フローに限らずグラフィカルプログラミングツールの土台としても使えます。
とはいえ、説明を読むより実際に触った方が早いと思います。ドラッグ&ドロップでステップを追加できるキャンバスを用意したので、先に挙動を見たい方はこちらからどうぞ。
Sequential-Workflow-Designerとは
Sequential-Workflow-Designerは、Webアプリケーション向けのビジュアルワークフローエディタです。ワークフローの定義は単純なJSONオブジェクトで表現され、Designer.create()にDOM要素と定義・設定を渡すだけでキャンバスが立ち上がります。特定のワークフローエンジンを前提にしていないため、実行部分は自分のアプリケーションに合わせて自由に組めるのも特徴です。
主な特徴
- ゼロ依存 -
package.jsonのdependenciesが空。バンドルに余計なライブラリを持ち込みません - SVGレンダリング - TypeScriptで実装されたキャンバスをSVGで描画するため、拡大縮小してもぼやけません
- JSON形式の定義 - ワークフローは
{ properties, sequence }というプレーンなオブジェクト。保存・復元・サーバー連携が容易です - カスタムエディタ -
stepEditorProviderでステップごとの編集フォームを、rootEditorProviderでワークフロー全体の設定フォームを自由に差し込めます - フレームワーク対応 - React・Angular・Svelte向けのラッパーが公式に提供されています
- ライト/ダーク/ソフトテーマ - CSSを差し替えるだけでテーマ切り替えが可能です
インストール
npmから通常のパッケージとしてインストールできます。
npm install sequential-workflow-designer
導入後は本体とテーマCSSをインポートします。
import { Designer } from 'sequential-workflow-designer';
import 'sequential-workflow-designer/css/designer.css';
import 'sequential-workflow-designer/css/designer-light.css';
ビルドツールを使わない場合は、jsDelivr経由のCDN読み込みにも対応しています。
<link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.40.0/css/designer.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.40.0/css/designer-light.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.40.0/dist/index.umd.js"></script>
Sequential-Workflow-Designerのサンプルを動かす
下のキャンバスは、Designer.create()に「在庫確認」「出荷手配」という2つのtaskステップを渡して初期化したものです。ステップをクリックするとonSelectedStepIdChangedイベントが発火し、選択中のステップ名が上部に表示されます。ツールボックスの「新しいタスク」をキャンバスへドラッグ&ドロップすれば、ステップを追加することもできます。
キャンバスを組み立てる部分だけを抜き出すと、こういう形になります。
const definition = {
properties: {},
sequence: [
{ id: 'step-1', componentType: 'task', type: 'checkStock', name: '在庫確認', properties: {} },
{ id: 'step-2', componentType: 'task', type: 'ship', name: '出荷手配', properties: {} },
],
};
const configuration = {
theme: 'light',
toolbox: {
groups: [{ name: '追加できるステップ', steps: [
{ componentType: 'task', type: 'checkStock', name: '新しいタスク', properties: {} },
] }],
},
controlBar: true,
};
const designer = Designer.create(placeholder, definition, configuration);
実際に動かせるものが下です。ステップをドラッグして順番を入れ替えたり、ツールボックスから新しいステップを追加したりしてみてください。
ステップの見た目はSVGで描かれているため、ズームインしても輪郭がぼやけません。iconUrlProviderにアイコン画像のURLを返す関数を渡すだけで、ステップごとにアイコンを出し分けられる点にも注目してください。
基本的な使い方
Sequential-Workflow-Designerの基本形は、ワークフローの定義(definition)と設定(configuration)をDesigner.create()に渡すだけです。
import { Designer } from 'sequential-workflow-designer';
const placeholder = document.getElementById('placeholder');
const definition = {
properties: {
workflowName: '発注承認フロー',
},
sequence: [
{ id: '1', componentType: 'task', type: 'approve', name: '承認依頼', properties: {} },
],
};
const configuration = {
theme: 'light', // 'light' | 'dark' | 'soft'
isReadonly: false,
undoStackSize: 10, // 0より大きい値でUndo/Redoを有効化
controlBar: true,
contextMenu: true,
};
const designer = Designer.create(placeholder, definition, configuration);
designer.onDefinitionChanged.subscribe((event) => {
console.log(event.definition);
});
ステップはcomponentType(task / switch / containerのいずれか)とtype(任意の文字列。アプリ側で意味を決める)、name、propertiesを持つJSONオブジェクトです。toolbox・editors・controlBar・contextMenuはそれぞれfalseを渡すことで非表示にでき、読み取り専用ビューアとしても使えます。
実践的なユースケース
条件分岐ワークフローを表現する
承認フローや自動化シナリオでは「条件によって処理を分ける」場面が必ず出てきます。Sequential-Workflow-DesignerではcomponentType: 'switch'のステップにbranchesオブジェクトを持たせることで、true/falseのような複数の分岐先シーケンスを1つのステップに束ねられます。下のサンプルは「在庫は十分か?」というswitchステップに、true分岐へ「そのまま出荷」、false分岐へ「追加発注する」というtaskステップを配置したものです。
const definition = {
properties: {},
sequence: [
{
id: 'switch-1',
componentType: 'switch',
type: 'if',
name: '在庫は十分か?',
properties: { condition: 'stock > 10' },
branches: {
true: [{ id: 'task-true', componentType: 'task', type: 'ship', name: 'そのまま出荷', properties: {} }],
false: [{ id: 'task-false', componentType: 'task', type: 'reorder', name: '追加発注する', properties: {} }],
},
},
],
};
「ワークフローを実行」ボタンを押すと、designer.getDefinition()で取得した定義からswitchステップのbranchesをランダムに1つ選び、実行結果を表示します。実際の業務ロジックでは、ここを在庫APIの返り値などに置き換えれば、キャンバス上の分岐がそのまま実行ロジックになります。
実行のたびに「そのまま出荷」と「追加発注する」がランダムに切り替わるのを確認できるはずです。conditionプロパティの中身は文字列として保持しているだけなので、実際の判定式の評価は自分のアプリ側で行う設計になっている点に注意してください。
カスタムステップエディタで担当者を編集する
ステップをクリックしたときに出てくる編集パネルは、editors.stepEditorProviderで完全に自作できます。標準のフォームでは足りない、業務固有の入力項目(担当者、期限、金額など)を持たせたいときに使う機能です。下のサンプルでは、ステップを選択すると「ステップ名」と「担当者」を編集できるフォームが表示され、context.notifyNameChanged()を呼ぶとキャンバス上のラベルがその場で書き換わります。
editors: {
stepEditorProvider: (step, context) => {
const nameInput = document.createElement('input');
nameInput.value = step.name;
nameInput.oninput = () => {
step.name = nameInput.value;
context.notifyNameChanged(); // キャンバスのラベルを即時更新
};
const assigneeInput = document.createElement('input');
assigneeInput.value = step.properties['assignee'];
assigneeInput.oninput = () => {
step.properties['assignee'] = assigneeInput.value;
context.notifyPropertiesChanged();
};
// ...inputをDOMに追加してreturn
},
}
「承認依頼」または「最終承認」のステップをクリックしてから、担当者欄を書き換えてみてください。ステップ名を変更すると、キャンバス上のラベルも連動して変わることが分かります。
notifyNameChanged()とnotifyPropertiesChanged()は、それぞれ「ステップ名が変わった」「プロパティが変わった」ことを設計側に伝えるためのAPIです。呼び出しを忘れると入力欄の値は変わってもキャンバスの表示は更新されないので、カスタムエディタを作るときは必ずセットで呼ぶようにしてください。
定義をJSONとして保存・復元する
Sequential-Workflow-Designerはワークフローエンジンを内蔵していないため、「編集した結果をどう保存するか」は自分で実装する必要があります。とはいえやることはシンプルで、designer.onDefinitionChangedを購読してdesigner.getDefinition()をJSONにシリアライズするだけです。サーバーへの保存やlocalStorageへの永続化も、この形をそのまま使えます。
const designer = Designer.create(placeholder, definition, configuration);
designer.onDefinitionChanged.subscribe(() => {
const json = JSON.stringify(designer.getDefinition(), null, 2);
localStorage.setItem('workflow', json); // 保存先は自由
});
下のサンプルでは、ステップを追加・削除・並び替えするたびにonDefinitionChangedが発火し、下のJSON表示がリアルタイムに更新されます。ツールボックスから「新しいタスク」をドラッグしてみてください。
onDefinitionChangedはステップの追加・削除だけでなく、名前変更やドラッグによる並び替えでも発火します。バックエンドへの自動保存を実装する場合は、ここにデバウンス処理を挟んでAPIを呼び出す形にすると実用的です。
まとめ
Sequential-Workflow-Designerは、ワークフロー画面という「作るのは大変だが需要は多い」UIを、ゼロ依存かつSVGベースで提供してくれるライブラリです。ワークフローの定義はプレーンなJSONで表現され、switchによる条件分岐、stepEditorProviderによるカスタム編集フォーム、onDefinitionChangedによる永続化まで、一通りの実装パターンが揃っています。実行エンジンを内蔵しない分、既存の業務ロジックにそのまま組み込みやすいのも実務的なポイントです。
承認フローや自動化シナリオのビルダー画面を内製したいなら、まずは今回のサンプルのようにタスクと条件分岐だけの小さなワークフローから試してみることをおすすめします。React・Angular・Svelte向けのラッパーも公式に用意されているので、既存プロジェクトへの組み込みも難しくありません。
