メインコンテンツまでスキップ

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 機構を通じて返してください。