Spark Workbench カスタムフィールドタイププラグイン開発ガイド
このガイドは Spark Workbench のタスクフィールドタイプ を拡張する開発者向けです。第三者プラグインでも Spark の既定プラグインと同じように、フィールドタイプ定義、システムフィールド定義、フィールド設定ロジック、TQL 演算子、対応する Vue コンポーネントを独立して提供できます。
既定フィールドプラグインは次の場所にあります。
spark-plugins/spark-workbench-default-plugin/
Text、Rich Text、Markdown、User、Attachment などの組み込みフィールドタイプと、Title、Assignee、Description などのシステムフィールドは、このプラグインから登録されます。プラットフォーム本体は拡張点を消費するだけで、具体的なフィールドタイプをタスクデザイナーにハードコードしません。
1. フィールドプラグインモデル
フィールドタイププラグインは通常、次の2つで構成されます。
- バックエンド拡張点:Lattice Ability を通じて、フィールドタイプ、システムフィールド、設定フォーム、対応する TQL 演算子、フィルタープロトコルを返します。
- フロントエンドコンポーネント:Vue コンポーネントで作成 / 編集用コントロールを描画し、必要に応じて読み取り専用やタスク詳細用コンポーネントも提供します。
推奨構成:
my-task-field-plugin/
pom.xml
src/main/java/
.../MyTaskFieldPlugin.java
.../MyFieldRegistryExt.java
.../PriorityFieldTypeProvider.java
src/main/frontend/
package.json
vite.config.js
src/
index.js
PriorityField.vue
PriorityDetailField.vue
プラグイン jar には Java 拡張点とフロントエンド静的資産を同梱し、実行時に Spark が読み込みます。
2. ビジネス ID
プラグインは独自の Lattice ビジネス ID を宣言する必要があります。
@Business(code = "my.task.field.plugin", name = "My Task Field Plugin")
public class MyTaskFieldPlugin extends BusinessTemplate {
}
フィールド登録時、Spark は登録済みのすべての Lattice ビジネス ID を走査し、それぞれに対してフィールド登録 Ability を呼び出します。第三者プラグインは @Realization をプラットフォーム組み込み code に紐付けず、自分のプラグインのビジネス ID を使用してください。
3. バックエンドでのフィールドタイプ登録
フィールド登録拡張点は SparkEraTaskFieldRegistryExt です。通常は空実装を継承します。
@Realization(codes = "my.task.field.plugin")
public class MyFieldRegistryExt extends BlankSparkEraTaskFieldRegistryExt {
private static final String FRONTEND_RESOURCE =
"/spark-gadgets/my-task-field-plugin/index.umd.js";
@Override
public List<SparkEraTaskCustomFieldTypeProvider> listCustomFieldTypeProviders(
SparkEraTaskFieldRegistryContext context) {
return List.of(new PriorityFieldTypeProvider(FRONTEND_RESOURCE));
}
}
フィールドタイプ Provider の例:
public class PriorityFieldTypeProvider implements SparkEraTaskCustomFieldTypeProvider {
private final String frontendResource;
public PriorityFieldTypeProvider(String frontendResource) {
this.frontendResource = frontendResource;
}
@Override
public String getCode() {
return "priority_score";
}
@Override
public String getTitle() {
return "Priority Score";
}
@Override
public SparkEraTaskFieldCategory getCategory() {
return SparkEraTaskFieldCategory.BASIC;
}
@Override
public String getDescription() {
return "A numeric priority score with visual emphasis.";
}
@Override
public String getComponentType() {
return "priorityScore";
}
@Override
public String getTaskFieldType() {
return "number";
}
@Override
public String getPreviewIcon() {
return "gauge";
}
@Override
public boolean isSortable() {
return true;
}
@Override
public List<String> supportOperators() {
return List.of("eq", "neq", "gt", "ge", "lt", "le");
}
@Override
public String getFrontendResource() {
return frontendResource;
}
@Override
public String getEditComponent() {
return "my$field-priority-score";
}
@Override
public String getDetailComponent() {
return "my$task-detail-priority-score-field";
}
}
主な項目:
code:フィールドタイプコード。グローバルに一意であることを推奨します。componentType:実行時コントロールの意味を表します。taskFieldType:基礎となる値タイプ。検索、インデックス、表示に影響します。previewIcon:タスクデザイナーのフィールドパレットに表示するアイコン。supportOperators:このフィールドで利用できる TQL 演算子。全演算子をそのまま返さないでください。frontendResource:プラグインのフロントエンド UMD エントリ。editComponent:作成 / 編集フォーム用 Vue コンポーネント key。readonlyComponent:通常の読み取り専用フォーム用 Vue コンポーネント key。省略可能です。detailComponent:タスク詳細レンダープロトコル用コンポーネント key。
4. システムフィールドの登録
システムフィールドは SparkEraTaskSystemFieldProvider を使用します。
@Override
public List<SparkEraTaskSystemFieldProvider> listSystemFieldProviders(
SparkEraTaskFieldRegistryContext context) {
return List.of(new EscalationLevelSystemFieldProvider(FRONTEND_RESOURCE));
}
システムフィールド Provider は、安定した code、表示 label、フィールドタイプ、一覧表示可否、検索可否、ソート可否、対応演算子を返す必要があります。システムフィールドも frontendResource とコンポーネント key を宣言できます。
5. フロントエンドコンポーネント登録
プラグインのフロントエンドエントリは、ホストが公開する window.__SPARK_TASK_FIELDS__ でコンポーネントを登録します。
import PriorityField from "./PriorityField.vue";
import PriorityDetailField from "./PriorityDetailField.vue";
const api = typeof window === "undefined" ? null : window.__SPARK_TASK_FIELDS__;
if (api?.registerFieldComponent) {
api.registerFieldComponent("my$field-priority-score", PriorityField);
}
if (api?.registerDetailFieldComponent) {
api.registerDetailFieldComponent("my$task-detail-priority-score-field", PriorityDetailField);
}
作成 / 編集コンポーネントの主な props:
defineProps({
modelValue: [String, Number, Boolean, Array, Object],
field: Object,
definition: Object,
placeholder: String,
disabled: Boolean,
context: Object
});
値を書き戻すには emit("update:modelValue", value) を使用します。context には t、apiFetch、openUserSelect、chooseAttachmentFiles など、ホストが提供する機能が含まれます。第三者コンポーネントは、共通のプラットフォーム操作を再実装せず、ホスト機能を優先して再利用してください。
タスク詳細コンポーネントは Spark レンダープロトコルに接続し、componentModel、renderContext、t を受け取ります。
<template>
<div class="priority-detail">
<span>{{ field.label }}</span>
<strong>{{ field.value }}</strong>
</div>
</template>
<script setup>
import { computed } from "vue";
const props = defineProps({
componentModel: Object
});
const field = computed(() => props.componentModel?.props?.field || {});
</script>
6. Vite ビルド
フィールドプラグインのフロントエンドは Gadget プラグインと同じく Vite library モードを使用し、Vue を external にします。
import { resolve } from "node:path";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
export default defineConfig({
plugins: [vue()],
build: {
outDir: resolve(__dirname, "../../../target/classes/META-INF/resources/spark-gadgets/my-task-field-plugin"),
lib: {
entry: resolve(__dirname, "src/index.js"),
name: "MyTaskFieldPlugin",
formats: ["umd"],
fileName: () => "index.umd.js",
cssFileName: "index"
},
rollupOptions: {
external: ["vue"],
output: {
globals: {
vue: "__SPARK_VUE__"
}
}
}
}
});
ビルド後、実行時リソース URL は次のようになります。
/spark-gadgets/my-task-field-plugin/index.umd.js
7. 開発チェックリスト
- フィールドタイプコードとシステムフィールドコードは安定している必要があります。
@Realization(codes = "...")は必ずプラグイン自身のビジネス ID を使用してください。- 検索演算子はフィールド値タイプと一致させ、すべての演算子を返さないでください。
- ソート可否はフィールドタイプで明示します。リッチテキスト、添付ファイル、長文テキストは通常ソート対象に適しません。
- フロントエンドコンポーネントに独自の Vue ランタイムをバンドルしないでください。
- コンポーネントのスタイルは Spark テーマ変数を使い、単一テーマ色をハードコードしないでください。
- フィールド label、description、設定項目の文言は、バックエンドの i18n 機構を通じて返してください。