BPMN Editor

Custom Detail Task

Membuat komponen Micro Frontend (MFE) yang tampil sebagai custom Detail View di tab Detail task melalui slot custom_views.DETAILS pada Addon.

Secara default, tab Detail sebuah task menampilkan tampilan bawaan AlurKerja. Bila perlu tampilan kustom — kartu ringkasan, layout multi-kolom, integrasi data eksternal, atau visualisasi — Anda bisa menggantinya dengan komponen React Anda sendiri yang dibungkus sebagai Addon dengan slot custom_views.DETAILS.

Hasil Akhir

Micro Frontend Component

Jika Addon Anda mendaftarkan komponen di slot custom_views.DETAILS, AlurKerja akan me-load komponen tersebut di tab Detail seperti berikut.

My Task Detail Micro Frontend

Tampilan di atas menunjukkan komponen MFE kustom sudah ter-render dan menampilkan data sesuai konteks task.

Konsep

Yang menentukan sebuah view tampil di tab Input atau tab Detail adalah slot tempat ia dideklarasikan di custom_views pada index.json Addon:

SlotTab yang dirender
custom_views.FORMSTab Input (writable form)
custom_views.DETAILSTab Detail (umumnya read-only)

Klasifikasi ini tidak di-hardcode di Studio — Studio mengiterasi custom_views.DETAILS, lalu mengambil label tampilan dari section details di index.json.

views/src/TaskSummaryView.tsx        ← 1. Komponen React (AlurkerjaMfeProps)


views/webpack.config.js  exposes     ← 2. Expose lewat Module Federation
        │  './task_summary_view'

index.json  custom_views.DETAILS     ← 3. Daftarkan: "ticket_summary": "task_summary_view"
index.json  details                  ← 4. Beri label tampilan


yarn build  →  alurkerja addon publish   ← 5. Build + publish via CLI


Studio → tab Detail                  ← 6. Verifikasi

Detail View bersifat read-only. Komponen di slot DETAILS umumnya hanya membaca data (mis. via form.getValues() atau fetch ke API) lalu menampilkannya — bukan menerima input. Tombol submit/aksi ditangani oleh platform.

Prasyarat

  • Node.js & yarn/npm untuk membangun bundle MFE.
  • AlurKerja CLI sudah terpasang dan login ke environment target — lihat AlurKerja CLI.
  • Project Addon sudah disiapkan (struktur folder Addon + index.json) — lihat Pembuatan Addon pada AlurKerja.

Step 1 — Buat Komponen Detail View

Buat file komponen di views/src/. Pakai tipe prop AlurkerjaMfeProps (didefinisikan di views/src/type/AlurkerjaType.ts), yang menyediakan:

  • form — helper React Hook Form: getValues, watch, register, setValue, control.
  • alurkerjaParams — konteks runtime: apiBaseUrl, token, activeTenant, probis, taskId, dst.

Karena ini Detail View, komponen umumnya membaca data lalu menampilkannya (read-only).

File: views/src/TaskSummaryView.tsx

import React, { useEffect, useState } from "react";
import { AlurkerjaMfeProps } from "./type/AlurkerjaType";

export default function TaskSummaryView({ form, alurkerjaParams }: AlurkerjaMfeProps) {
    // Baca data yang sudah ada di form (mis. hasil action sebelumnya).
    const values = form.getValues?.() ?? {};
    const ticket = values?.ticket_summary ?? values?.value ?? {};

    const { apiBaseUrl, token, activeTenant, taskId } = alurkerjaParams ?? {};

    // (Opsional) ambil detail tambahan dari API.
    const [detail, setDetail] = useState<any>(null);
    const [loading, setLoading] = useState(false);

    useEffect(() => {
        if (!apiBaseUrl || !ticket?.id) return;
        setLoading(true);
        fetch(`${apiBaseUrl}/api/tickets/${ticket.id}`, {
            headers: {
                Authorization: `Bearer ${token}`,
                "X-Tenant": activeTenant ?? "",
            },
        })
            .then((r) => r.json())
            .then(setDetail)
            .catch(() => setDetail(null))
            .finally(() => setLoading(false));
    }, [apiBaseUrl, token, activeTenant, ticket?.id]);

    const priority = detail?.priority ?? ticket?.priority ?? "Normal";
    const priorityColor =
        priority === "High"   ? "bg-red-100 text-red-700" :
        priority === "Medium" ? "bg-yellow-100 text-yellow-700" :
                                "bg-gray-100 text-gray-700";

    const row = (label: string, value?: React.ReactNode) => (
        <div className="grid grid-cols-[180px_1fr] gap-3 py-2 border-b border-gray-100">
            <span className="text-sm text-gray-500">{label}</span>
            <span className="text-sm text-gray-900">{value ?? "-"}</span>
        </div>
    );

    return (
        <div className="card max-w-4xl mx-auto p-4">
            <h2 className="text-2xl font-bold text-gray-900 mb-6">Ringkasan Tiket</h2>

            {loading && <p className="text-sm text-gray-500">Memuat detail…</p>}

            <div className="bg-white rounded-lg">
                {row("Nomor Tiket", detail?.nomor ?? ticket?.nomor)}
                {row("Pelapor", detail?.reporter ?? ticket?.reporter)}
                {row("Prioritas", (
                    <span className={`inline-block rounded px-2 py-0.5 text-xs ${priorityColor}`}>
                        {priority}
                    </span>
                ))}
                {row("Dibuat", detail?.created_at ?? ticket?.created_at)}
                {row("Task ID", taskId)}
            </div>
        </div>
    );
}

Pola data: Detail/Action views membaca field langsung (ticket_summary, nomor, dst.). Config views (CREATE/EDIT) memakai prefix value. (mis. value.fileName). Komponen view tidak berisi tombol submit — aksi ditangani oleh platform.

Step 2 — Expose Komponen di Webpack

Tambahkan komponen baru ke exposes pada ModuleFederationPlugin di views/webpack.config.js:

new ModuleFederationPlugin({
    name: 'task_summary_view',                   // ← samakan dengan component_scope di index.json
    filename: 'remoteEntry.js',
    exposes: {
        './task_summary_view': './src/TaskSummaryView.tsx',   // ← samakan dengan custom_views
    },
    shared: {
        react: { singleton: true },
        'react-dom': { singleton: true },
        'react-hook-form': { singleton: true },
    },
}),

Aturan penamaan: key di exposes ('./task_summary_view') harus sama persis dengan nilai yang dipakai di custom_views.DETAILS ("task_summary_view", tanpa ./). Gunakan snake_case, tanpa spasi/karakter khusus.

Step 3 — Daftarkan di custom_views.DETAILS

Edit index.json. Tambahkan entri pada slot DETAILS (key = identifier detail, value = nama komponen yang di-expose):

"custom_views": {
    "DETAILS": {
        "ticket_summary": "task_summary_view"
    }
}

Step 4 — Beri Nama Tampilan di Section details

Label yang tampil di tab Detail Studio diambil dari section details (paralel dengan forms / views):

"details": {
    "ticket_summary": {
        "name": "Ringkasan Tiket",
        "description": "Detail view yang menampilkan ringkasan tiket."
    }
}

Perbedaan Input vs Detail:

  • Input — sebuah form wajib ada di forms dan custom_views.FORMS.
  • Detail — cukup ada di custom_views.DETAILS; label diambil dari details. Section details membuat label lebih rapi, mekanisme tab Detail-nya berpusat pada custom_views.DETAILS.

Potongan index.json yang sudah lengkap untuk bagian ini:

{
    "component_scope": "task_summary_view",
    "custom_views": {
        "DETAILS": {
            "ticket_summary": "task_summary_view"
        }
    },
    "details": {
        "ticket_summary": {
            "name": "Ringkasan Tiket",
            "description": "Detail view yang menampilkan ringkasan tiket."
        }
    }
}

Validasi JSON sebelum lanjut:

python3 -c "import json; d=json.load(open('index.json')); print('OK'); print(d['custom_views']['DETAILS']); print(d['details'])"

Step 5 — Build & Publish

Karena ada perubahan kode di views/src, wajib rebuild bundle MFE:

cd views
yarn build          # atau: npm run build  → output ke views/dist
cd ..

Lalu publish via AlurKerja CLI (jalankan di terminal interaktif — CLI akan meminta tenant id):

alurkerja addon publish

Bila perubahan hanya di index.json (Step 3 & 4) tanpa menyentuh kode view, rebuild tidak diperlukan — cukup publish ulang. Karena di sini kita menambah komponen baru (Step 1), build tetap wajib.

Step 6 — Verifikasi

  1. Buka Addon di Studio, masuk ke task/elemen yang relevan.
  2. Pindah ke tab Detail (FormTabSwitcher: Input ↔ Detail).
  3. Komponen task_summary_view di-load via Module Federation dan tampil dengan label "Ringkasan Tiket".

Cek konsistensi cepat

Pastikan setiap komponen yang dirujuk di custom_views benar-benar di-expose:

python3 - <<'PY'
import json, re
d = json.load(open('index.json'))
exposed = set(re.findall(r"\./([A-Za-z0-9_]+)':", open('views/webpack.config.js').read()))
refs = set()
for v in d.get('custom_views', {}).values():
    refs.update(v.values() if isinstance(v, dict) else [v])
missing = refs - exposed
print("Exposed:", sorted(exposed))
print("Direferensikan:", sorted(refs))
print("BELUM di-expose:", missing or "tidak ada — semua valid")
PY

Troubleshooting

GejalaPenyebab & Solusi
View tidak muncul di tab DetailPastikan entri ada di custom_views.DETAILS (bukan FORMS / VIEWS / CONFIGS).
Komponen gagal load / blankNilai di custom_views.DETAILS tidak cocok dengan key exposes di webpack. Samakan (tanpa ./).
Build gagalAda komponen dirujuk di custom_views tapi file/expose-nya belum ada. Lengkapi Step 1 & 2.
Perubahan tidak terlihatLupa yarn build atau lupa publish ulang via CLI.
Label salah/kosong di tab DetailTambahkan/rapikan entri di section details.

Ringkasan Checklist

  • Step 1views/src/TaskSummaryView.tsx dibuat (pakai AlurkerjaMfeProps).
  • Step 2 — di-expose di views/webpack.config.js sebagai './task_summary_view'.
  • Step 3 — terdaftar di index.jsoncustom_views.DETAILS.
  • Step 4 — label tampilan di index.jsondetails.
  • Step 5yarn build lalu alurkerja addon publish.
  • Step 6 — komponen muncul di tab Detail Studio.

Lihat Juga