Enhance Documentation for Gateway Decision Logic in Process Builder
- Added detailed documentation for the new Gateway Decision Logic, including UI components for gateway condition configuration and evaluation processes. - Introduced examples for condition evaluation and decision path selection, improving clarity for users on how to implement and utilize gateway conditions. - Updated the process definition and variables to support the new gateway logic, ensuring seamless integration within the existing workflow. - Enhanced the user interface to display decision paths and condition evaluation results, providing better feedback during workflow execution.
This commit is contained in:
parent
03fdbb5d96
commit
6009b1ecbe
@ -1,309 +0,0 @@
|
||||
this.hideField("form_jeniskp_1");
|
||||
this.hideField("form_jeniskp_2");
|
||||
this.hideField("form_jeniskp_3");
|
||||
|
||||
this.onFieldChange("select_1", (value) => {
|
||||
this.hideField("form_jeniskp_1");
|
||||
this.hideField("form_jeniskp_2");
|
||||
this.hideField("form_jeniskp_3");
|
||||
if (value && value.trim()) {
|
||||
if (value == "jeniskp_1") this.showField("form_jeniskp_1");
|
||||
if (value == "jeniskp_2") this.showField("form_jeniskp_2");
|
||||
if (value == "jeniskp_3") this.showField("form_jeniskp_3");
|
||||
}
|
||||
});
|
||||
// Conditional Logic Script
|
||||
|
||||
// Conditional Logic Script
|
||||
|
||||
// Conditional Logic Script
|
||||
|
||||
// Conditional Logic Script
|
||||
|
||||
// Conditional Logic Script
|
||||
|
||||
// Conditional Logic Script
|
||||
|
||||
// Conditional logic for field: nyatakan_lain2
|
||||
onFieldChange("radio_bangsa", function () {
|
||||
if (getField("radio_bangsa") !== "lain") {
|
||||
hideField("nyatakan_lain2");
|
||||
} else {
|
||||
showField("nyatakan_lain2");
|
||||
}
|
||||
});
|
||||
|
||||
// Initial evaluation for field: nyatakan_lain2
|
||||
(function () {
|
||||
if (getField("radio_bangsa") !== "lain") {
|
||||
hideField("nyatakan_lain2");
|
||||
} else {
|
||||
showField("nyatakan_lain2");
|
||||
}
|
||||
})();
|
||||
// Conditional Logic Script
|
||||
|
||||
// Conditional logic for field: nyatakan_lain2
|
||||
onFieldChange("radio_bangsa", function () {
|
||||
if (getField("radio_bangsa") !== "lain") {
|
||||
hideField("nyatakan_lain2");
|
||||
} else {
|
||||
showField("nyatakan_lain2");
|
||||
}
|
||||
});
|
||||
|
||||
// Initial evaluation for field: nyatakan_lain2
|
||||
(function () {
|
||||
if (getField("radio_bangsa") !== "lain") {
|
||||
hideField("nyatakan_lain2");
|
||||
} else {
|
||||
showField("nyatakan_lain2");
|
||||
}
|
||||
})();
|
||||
// Conditional Logic Script
|
||||
|
||||
// Conditional logic for field: nyatakan_lain2
|
||||
onFieldChange("radio_bangsa", function () {
|
||||
if (getField("radio_bangsa") !== "lain") {
|
||||
hideField("nyatakan_lain2");
|
||||
} else {
|
||||
showField("nyatakan_lain2");
|
||||
}
|
||||
});
|
||||
|
||||
// Initial evaluation for field: nyatakan_lain2
|
||||
(function () {
|
||||
if (getField("radio_bangsa") !== "lain") {
|
||||
hideField("nyatakan_lain2");
|
||||
} else {
|
||||
showField("nyatakan_lain2");
|
||||
}
|
||||
})();
|
||||
|
||||
// Conditional logic for field: text_14
|
||||
onFieldChange("radio_pendidikan", function () {
|
||||
if (getField("radio_pendidikan") !== "lain") {
|
||||
hideField("text_14");
|
||||
} else {
|
||||
showField("text_14");
|
||||
}
|
||||
});
|
||||
|
||||
// Initial evaluation for field: text_14
|
||||
(function () {
|
||||
if (getField("radio_pendidikan") !== "lain") {
|
||||
hideField("text_14");
|
||||
} else {
|
||||
showField("text_14");
|
||||
}
|
||||
})();
|
||||
// Conditional Logic Script
|
||||
|
||||
// Conditional logic for field: nyatakan_lain2
|
||||
onFieldChange("radio_bangsa", function () {
|
||||
if (getField("radio_bangsa") !== "lain") {
|
||||
hideField("nyatakan_lain2");
|
||||
} else {
|
||||
showField("nyatakan_lain2");
|
||||
}
|
||||
});
|
||||
|
||||
// Initial evaluation for field: nyatakan_lain2
|
||||
(function () {
|
||||
if (getField("radio_bangsa") !== "lain") {
|
||||
hideField("nyatakan_lain2");
|
||||
} else {
|
||||
showField("nyatakan_lain2");
|
||||
}
|
||||
})();
|
||||
|
||||
// Conditional logic for field: text_14
|
||||
onFieldChange("radio_pendidikan", function () {
|
||||
if (getField("radio_pendidikan") !== "lain") {
|
||||
hideField("text_14");
|
||||
} else {
|
||||
showField("text_14");
|
||||
}
|
||||
});
|
||||
|
||||
// Initial evaluation for field: text_14
|
||||
(function () {
|
||||
if (getField("radio_pendidikan") !== "lain") {
|
||||
hideField("text_14");
|
||||
} else {
|
||||
showField("text_14");
|
||||
}
|
||||
})();
|
||||
// Conditional Logic Script
|
||||
|
||||
// Conditional logic for field: nyatakan_lain2
|
||||
onFieldChange("radio_bangsa", function () {
|
||||
if (getField("radio_bangsa") !== "lain") {
|
||||
hideField("nyatakan_lain2");
|
||||
} else {
|
||||
showField("nyatakan_lain2");
|
||||
}
|
||||
});
|
||||
|
||||
// Initial evaluation for field: nyatakan_lain2
|
||||
(function () {
|
||||
if (getField("radio_bangsa") !== "lain") {
|
||||
hideField("nyatakan_lain2");
|
||||
} else {
|
||||
showField("nyatakan_lain2");
|
||||
}
|
||||
})();
|
||||
|
||||
// Conditional logic for field: text_14
|
||||
onFieldChange("radio_pendidikan", function () {
|
||||
if (getField("radio_pendidikan") !== "lain") {
|
||||
hideField("text_14");
|
||||
} else {
|
||||
showField("text_14");
|
||||
}
|
||||
});
|
||||
|
||||
// Initial evaluation for field: text_14
|
||||
(function () {
|
||||
if (getField("radio_pendidikan") !== "lain") {
|
||||
hideField("text_14");
|
||||
} else {
|
||||
showField("text_14");
|
||||
}
|
||||
})();
|
||||
// Conditional Logic Script
|
||||
|
||||
// Conditional logic for field: nyatakan_lain2
|
||||
onFieldChange("radio_bangsa", function () {
|
||||
if (getField("radio_bangsa") !== "lain") {
|
||||
hideField("nyatakan_lain2");
|
||||
} else {
|
||||
showField("nyatakan_lain2");
|
||||
}
|
||||
});
|
||||
|
||||
// Initial evaluation for field: nyatakan_lain2
|
||||
(function () {
|
||||
if (getField("radio_bangsa") !== "lain") {
|
||||
hideField("nyatakan_lain2");
|
||||
} else {
|
||||
showField("nyatakan_lain2");
|
||||
}
|
||||
})();
|
||||
|
||||
// Conditional logic for field: text_14
|
||||
onFieldChange("radio_pendidikan", function () {
|
||||
if (getField("radio_pendidikan") !== "lain") {
|
||||
hideField("text_14");
|
||||
} else {
|
||||
showField("text_14");
|
||||
}
|
||||
});
|
||||
|
||||
// Initial evaluation for field: text_14
|
||||
(function () {
|
||||
if (getField("radio_pendidikan") !== "lain") {
|
||||
hideField("text_14");
|
||||
} else {
|
||||
showField("text_14");
|
||||
}
|
||||
})();
|
||||
// Conditional Logic Script
|
||||
|
||||
// Conditional logic for field: nyatakan_lain2
|
||||
onFieldChange("radio_bangsa", function () {
|
||||
if (getField("radio_bangsa") !== "lain") {
|
||||
hideField("nyatakan_lain2");
|
||||
} else {
|
||||
showField("nyatakan_lain2");
|
||||
}
|
||||
});
|
||||
|
||||
// Initial evaluation for field: nyatakan_lain2
|
||||
(function () {
|
||||
if (getField("radio_bangsa") !== "lain") {
|
||||
hideField("nyatakan_lain2");
|
||||
} else {
|
||||
showField("nyatakan_lain2");
|
||||
}
|
||||
})();
|
||||
|
||||
// Conditional logic for field: text_14
|
||||
onFieldChange("radio_pendidikan", function () {
|
||||
if (getField("radio_pendidikan") !== "lain") {
|
||||
hideField("text_14");
|
||||
} else {
|
||||
showField("text_14");
|
||||
}
|
||||
});
|
||||
|
||||
// Initial evaluation for field: text_14
|
||||
(function () {
|
||||
if (getField("radio_pendidikan") !== "lain") {
|
||||
hideField("text_14");
|
||||
} else {
|
||||
showField("text_14");
|
||||
}
|
||||
})();
|
||||
|
||||
// Hide "Nyatakan Hubungan Lain-lain" initially
|
||||
this.hideField("hubungan_lain_nyatakan");
|
||||
|
||||
// Show/hide relationship specification field
|
||||
this.onFieldChange("hubungan_keluarga", (value) => {
|
||||
if (value && value.includes("lain_lain")) {
|
||||
this.showField("hubungan_lain_nyatakan");
|
||||
} else {
|
||||
this.hideField("hubungan_lain_nyatakan");
|
||||
}
|
||||
});
|
||||
|
||||
// Hide "Sebab Pembayaran Tunai" initially
|
||||
this.hideField("sebab_tunai");
|
||||
|
||||
// Show/hide cash payment reason field
|
||||
this.onFieldChange("cara_pembayaran", (value) => {
|
||||
if (value && value.includes("tunai")) {
|
||||
this.showField("sebab_tunai");
|
||||
} else {
|
||||
this.hideField("sebab_tunai");
|
||||
}
|
||||
});
|
||||
|
||||
// Hide education specification field initially
|
||||
this.hideField("pendidikan_lain_tanggungan");
|
||||
|
||||
// Show/hide education specification field
|
||||
this.onFieldChange("pendidikan_tertinggi_tanggungan", (value) => {
|
||||
if (value && value.includes("lain_lain")) {
|
||||
this.showField("pendidikan_lain_tanggungan");
|
||||
} else {
|
||||
this.hideField("pendidikan_lain_tanggungan");
|
||||
}
|
||||
});
|
||||
|
||||
// Hide school information initially
|
||||
this.hideField("maklumat_sekolah");
|
||||
|
||||
// Show/hide school information based on schooling status
|
||||
this.onFieldChange("bersekolah_tanggungan", (value) => {
|
||||
if (value === "ya") {
|
||||
this.showField("maklumat_sekolah");
|
||||
} else {
|
||||
this.hideField("maklumat_sekolah");
|
||||
}
|
||||
});
|
||||
|
||||
// Handle repeating group conditional logic for each dependent
|
||||
this.onFieldChange("tanggungan_maklumat", (value) => {
|
||||
if (value && Array.isArray(value)) {
|
||||
value.forEach((item, index) => {
|
||||
// Handle race specification for each dependent
|
||||
if (item.bangsa_tanggungan !== "lain_lain") {
|
||||
// Hide the specification field for this item
|
||||
const fieldName = `tanggungan_maklumat[${index}].bangsa_lain_tanggungan`;
|
||||
// Note: Repeating group field hiding requires specific handling
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -2,9 +2,9 @@
|
||||
{
|
||||
"type": "heading",
|
||||
"props": {
|
||||
"name": "heading_2",
|
||||
"name": "heading_kategori_asnaf",
|
||||
"level": 2,
|
||||
"value": "SEKSYEN A",
|
||||
"value": "PILIHAN KATEGORI ASNAF",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"conditionalLogic": {
|
||||
@ -16,11 +16,10 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "heading",
|
||||
"type": "paragraph",
|
||||
"props": {
|
||||
"name": "heading_1",
|
||||
"level": 3,
|
||||
"value": "1. MAKLUMAT PENDAFTARAN ASNAF (KETUA KELUARGA)",
|
||||
"name": "paragraph_kategori_asnaf",
|
||||
"value": "Sila pilih kategori asnaf yang bersesuaian.",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"conditionalLogic": {
|
||||
@ -31,139 +30,19 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"props": {
|
||||
"help": "Untuk Mualaf, nama mengikut kad pengenalan",
|
||||
"name": "text_3",
|
||||
"type": "text",
|
||||
"label": "Nama",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"validation": "required",
|
||||
"placeholder": "",
|
||||
"conditionalLogic": {
|
||||
"action": "show",
|
||||
"enabled": false,
|
||||
"operator": "and",
|
||||
"conditions": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"props": {
|
||||
"help": "",
|
||||
"name": "select_1",
|
||||
"type": "select",
|
||||
"label": "Jenis Kad Pengenalan",
|
||||
"width": "100%",
|
||||
"options": [
|
||||
{ "label": "Sila Pilih Jenis Kad Pengenalan", "value": "jeniskp" },
|
||||
{ "label": "MyKad/MyKid", "value": "jeniskp_1" },
|
||||
{ "label": "No. K/P/Polis/Tentera/No. Pasport", "value": "jeniskp_2" },
|
||||
{ "label": "No. Sijil Beranak", "value": "jeniskp_3" }
|
||||
],
|
||||
"gridColumn": "span 12",
|
||||
"validation": "required",
|
||||
"placeholder": "",
|
||||
"conditionalLogic": {
|
||||
"action": "show",
|
||||
"enabled": false,
|
||||
"operator": "and",
|
||||
"conditions": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"props": {
|
||||
"help": "",
|
||||
"name": "form_jeniskp_1",
|
||||
"type": "text",
|
||||
"label": "MyKad/MyKid",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"validation": "required",
|
||||
"placeholder": "",
|
||||
"conditionalLogic": {
|
||||
"action": "show",
|
||||
"enabled": false,
|
||||
"operator": "and",
|
||||
"conditions": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"props": {
|
||||
"help": "",
|
||||
"name": "form_jeniskp_2",
|
||||
"type": "text",
|
||||
"label": "No. K/P/Polis/Tentera/No. Pasport",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"validation": "required",
|
||||
"placeholder": "",
|
||||
"conditionalLogic": {
|
||||
"action": "show",
|
||||
"enabled": false,
|
||||
"operator": "and",
|
||||
"conditions": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"props": {
|
||||
"help": "",
|
||||
"name": "form_jeniskp_3",
|
||||
"type": "text",
|
||||
"label": "No. Sijil Beranak",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"validation": "required",
|
||||
"placeholder": "",
|
||||
"conditionalLogic": {
|
||||
"action": "show",
|
||||
"enabled": false,
|
||||
"operator": "and",
|
||||
"conditions": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"props": {
|
||||
"help": "Isi Jika Berkenaan",
|
||||
"name": "text_warganegara",
|
||||
"type": "text",
|
||||
"label": "Warganegara",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"validation": "",
|
||||
"placeholder": "",
|
||||
"conditionalLogic": {
|
||||
"action": "show",
|
||||
"enabled": false,
|
||||
"operator": "and",
|
||||
"conditions": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "radio",
|
||||
"props": {
|
||||
"help": "",
|
||||
"name": "radio_jantina",
|
||||
"help": "Pilih kategori asnaf",
|
||||
"name": "kategori_asnaf",
|
||||
"type": "radio",
|
||||
"label": "Jantina",
|
||||
"width": "50%",
|
||||
"label": "Kategori Asnaf",
|
||||
"width": "100%",
|
||||
"options": [
|
||||
{ "label": "Lelaki", "value": "lelaki" },
|
||||
{ "label": "Perempuan", "value": "perempuan" }
|
||||
{ "label": "Fakir Miskin", "value": "fakir_miskin" },
|
||||
{ "label": "Bukan Fakir Miskin", "value": "bukan_fakir_miskin" }
|
||||
],
|
||||
"gridColumn": "span 6",
|
||||
"gridColumn": "span 12",
|
||||
"validation": "required",
|
||||
"conditionalLogic": {
|
||||
"action": "show",
|
||||
@ -173,60 +52,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"props": {
|
||||
"help": "",
|
||||
"name": "radio_bangsa",
|
||||
"type": "select",
|
||||
"label": "Bangsa",
|
||||
"width": "50%",
|
||||
"options": [
|
||||
{ "label": "Melayu", "value": "melayu" },
|
||||
{ "label": "Cina", "value": "cina" },
|
||||
{ "label": "India", "value": "india" },
|
||||
{ "label": "Lain-lain", "value": "lain" }
|
||||
],
|
||||
"gridColumn": "span 6",
|
||||
"validation": "required",
|
||||
"placeholder": "Select an option"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"props": {
|
||||
"help": "",
|
||||
"name": "nyatakan_lain2",
|
||||
"name": "nama_asnaf",
|
||||
"type": "text",
|
||||
"label": "Nyatakan (Bangsa Lain-Lain)",
|
||||
"label": "Nama Asnaf",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"validation": "",
|
||||
"validation": "required",
|
||||
"placeholder": "Enter text...",
|
||||
"conditionalLogic": {
|
||||
"action": "hide",
|
||||
"enabled": true,
|
||||
"operator": "and",
|
||||
"conditions": [
|
||||
{ "field": "radio_bangsa", "value": "lain", "operator": "not_equals" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "radio",
|
||||
"props": {
|
||||
"help": "",
|
||||
"name": "radio_9_copy",
|
||||
"type": "radio",
|
||||
"label": "Bersekolah",
|
||||
"width": "50%",
|
||||
"options": [
|
||||
{ "label": "Ya", "value": "ya" },
|
||||
{ "label": "Tidak", "value": "tidak" }
|
||||
],
|
||||
"gridColumn": "span 6",
|
||||
"validation": "",
|
||||
"conditionalLogic": {
|
||||
"action": "show",
|
||||
"enabled": false,
|
||||
@ -234,569 +70,5 @@
|
||||
"conditions": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"props": {
|
||||
"help": "",
|
||||
"name": "radio_pendidikan",
|
||||
"type": "select",
|
||||
"label": "Pendidikan Tertinggi",
|
||||
"width": "50%",
|
||||
"options": [
|
||||
{ "label": "Peringkat Rendah", "value": "rendah" },
|
||||
{ "label": "SRP/PMR", "value": "srp" },
|
||||
{ "label": "SPM", "value": "spm" },
|
||||
{ "label": "Sijil", "value": "sijil" },
|
||||
{ "label": "Diploma", "value": "diploma" },
|
||||
{ "label": "STPM", "value": "stpm" },
|
||||
{ "label": "Ijazah", "value": "ijazah" },
|
||||
{ "label": "Lain-Lain", "value": "lain" }
|
||||
],
|
||||
"gridColumn": "span 6",
|
||||
"validation": "required",
|
||||
"placeholder": "Select an option"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"props": {
|
||||
"help": "",
|
||||
"name": "text_14",
|
||||
"type": "text",
|
||||
"label": "Nyatakan (Pendidikan Tertinggi Lain-Lain)",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"validation": "",
|
||||
"placeholder": "Enter text...",
|
||||
"conditionalLogic": {
|
||||
"action": "hide",
|
||||
"enabled": true,
|
||||
"operator": "and",
|
||||
"conditions": [
|
||||
{
|
||||
"field": "radio_pendidikan",
|
||||
"value": "lain",
|
||||
"operator": "not_equals"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "date",
|
||||
"props": {
|
||||
"help": "Isi Jika Berkenaan",
|
||||
"name": "date_masukislam",
|
||||
"type": "date",
|
||||
"label": "Tarikh Masuk Islam",
|
||||
"width": "50%",
|
||||
"gridColumn": "span 6",
|
||||
"validation": "",
|
||||
"conditionalLogic": {
|
||||
"action": "show",
|
||||
"enabled": false,
|
||||
"operator": "and",
|
||||
"conditions": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "date",
|
||||
"props": {
|
||||
"help": "Isi Jika Berkenaan",
|
||||
"name": "date_masukislam_copy",
|
||||
"type": "date",
|
||||
"label": "Tarikh Mula Kelas fardu Ain Muallaf (KFAM)",
|
||||
"width": "50%",
|
||||
"gridColumn": "span 6",
|
||||
"validation": "",
|
||||
"conditionalLogic": {
|
||||
"action": "show",
|
||||
"enabled": false,
|
||||
"operator": "and",
|
||||
"conditions": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"props": {
|
||||
"help": "",
|
||||
"name": "select_statusperkahwinan",
|
||||
"type": "select",
|
||||
"label": "Status Perkahwinan",
|
||||
"width": "100%",
|
||||
"options": [
|
||||
{ "label": "Berkahwin", "value": "berkahwin" },
|
||||
{ "label": "Ibu Tinggal/Bapa Tinggal", "value": "ibubapatunggal" },
|
||||
{ "label": "Bujang", "value": "bujang" },
|
||||
{ "label": "Duda", "value": "duda" },
|
||||
{ "label": "Janda", "value": "janda" },
|
||||
{ "label": "Balu", "value": "balu" }
|
||||
],
|
||||
"gridColumn": "span 12",
|
||||
"validation": "required",
|
||||
"placeholder": "Select an option",
|
||||
"conditionalLogic": {
|
||||
"action": "show",
|
||||
"enabled": false,
|
||||
"operator": "and",
|
||||
"conditions": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "heading",
|
||||
"props": {
|
||||
"name": "heading_seksyen_b",
|
||||
"level": 2,
|
||||
"value": "SEKSYEN B",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"conditionalLogic": {
|
||||
"action": "show",
|
||||
"enabled": false,
|
||||
"operator": "and",
|
||||
"conditions": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "heading",
|
||||
"props": {
|
||||
"name": "heading_tanggungan",
|
||||
"level": 3,
|
||||
"value": "1. MAKLUMAT PERIBADI TANGGUNGAN (Ruangan WAJIB diisi)",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"conditionalLogic": {
|
||||
"action": "show",
|
||||
"enabled": false,
|
||||
"operator": "and",
|
||||
"conditions": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "checkbox",
|
||||
"props": {
|
||||
"help": "Pilih semua yang berkenaan",
|
||||
"name": "hubungan_keluarga",
|
||||
"type": "checkbox",
|
||||
"label": "Hubungan dengan Pemohon/Asnaf",
|
||||
"width": "100%",
|
||||
"options": [
|
||||
{ "label": "Pasangan Pemohon", "value": "pasangan" },
|
||||
{ "label": "Isteri Kedua", "value": "isteri_kedua" },
|
||||
{ "label": "Isteri Ketiga", "value": "isteri_ketiga" },
|
||||
{ "label": "Isteri Keempat", "value": "isteri_keempat" },
|
||||
{ "label": "Ipar", "value": "ipar" },
|
||||
{ "label": "Abang", "value": "abang" },
|
||||
{ "label": "Bapa", "value": "bapa" },
|
||||
{ "label": "Ibu", "value": "ibu" },
|
||||
{ "label": "Kakak", "value": "kakak" },
|
||||
{ "label": "Adik", "value": "adik" },
|
||||
{ "label": "Anak", "value": "anak" },
|
||||
{ "label": "Cucu", "value": "cucu" },
|
||||
{ "label": "Bapa Mertua", "value": "bapa_mertua" },
|
||||
{ "label": "Ibu Mertua", "value": "ibu_mertua" },
|
||||
{ "label": "Lain-lain (Sila Nyatakan)", "value": "lain_lain" }
|
||||
],
|
||||
"gridColumn": "span 12",
|
||||
"validation": "required"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"props": {
|
||||
"name": "hubungan_lain_nyatakan",
|
||||
"type": "text",
|
||||
"label": "Nyatakan Hubungan Lain-lain",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"validation": "",
|
||||
"placeholder": "Sila nyatakan hubungan lain-lain",
|
||||
"conditionalLogic": {
|
||||
"action": "hide",
|
||||
"enabled": true,
|
||||
"operator": "and",
|
||||
"conditions": [
|
||||
{
|
||||
"field": "hubungan_keluarga",
|
||||
"value": "lain_lain",
|
||||
"operator": "not_contains"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "repeating-group",
|
||||
"props": {
|
||||
"help": "Tambah maklumat untuk setiap tanggungan",
|
||||
"name": "tanggungan_maklumat",
|
||||
"label": "Maklumat Tanggungan",
|
||||
"width": "100%",
|
||||
"fields": [
|
||||
{
|
||||
"name": "nama_tanggungan",
|
||||
"type": "text",
|
||||
"label": "Nama (Untuk Mualaf, nama mengikut kad pengenalan)",
|
||||
"validation": "required",
|
||||
"placeholder": "Masukkan nama lengkap"
|
||||
},
|
||||
{
|
||||
"name": "jenis_kad_tanggungan",
|
||||
"type": "select",
|
||||
"label": "Jenis Pengenalan",
|
||||
"options": [
|
||||
{ "label": "MyKad/MyKid", "value": "mykad" },
|
||||
{
|
||||
"label": "No. K/P/Polis/Tentera/No. Pasport",
|
||||
"value": "kp_polis"
|
||||
},
|
||||
{ "label": "No. Sijil Beranak", "value": "sijil_beranak" }
|
||||
],
|
||||
"validation": "required"
|
||||
},
|
||||
{
|
||||
"name": "no_pengenalan_tanggungan",
|
||||
"type": "text",
|
||||
"label": "No. Pengenalan",
|
||||
"validation": "required",
|
||||
"placeholder": "Masukkan nombor pengenalan"
|
||||
},
|
||||
{
|
||||
"name": "jantina_tanggungan",
|
||||
"type": "radio",
|
||||
"label": "Jantina",
|
||||
"options": [
|
||||
{ "label": "Lelaki", "value": "lelaki" },
|
||||
{ "label": "Perempuan", "value": "perempuan" }
|
||||
],
|
||||
"validation": "required"
|
||||
},
|
||||
{
|
||||
"name": "tarikh_lahir_tanggungan",
|
||||
"type": "date",
|
||||
"label": "Tarikh Lahir",
|
||||
"validation": "required"
|
||||
},
|
||||
{
|
||||
"name": "tempat_lahir_tanggungan",
|
||||
"type": "text",
|
||||
"label": "Tempat Lahir",
|
||||
"placeholder": "Masukkan tempat lahir"
|
||||
},
|
||||
{
|
||||
"name": "bangsa_tanggungan",
|
||||
"type": "select",
|
||||
"label": "Bangsa",
|
||||
"options": [
|
||||
{ "label": "Melayu", "value": "melayu" },
|
||||
{ "label": "Cina", "value": "cina" },
|
||||
{ "label": "India", "value": "india" },
|
||||
{ "label": "Lain-lain (Sila Nyatakan)", "value": "lain_lain" }
|
||||
],
|
||||
"validation": "required"
|
||||
},
|
||||
{
|
||||
"name": "bangsa_lain_tanggungan",
|
||||
"type": "text",
|
||||
"label": "Nyatakan Bangsa Lain-lain",
|
||||
"placeholder": "Sila nyatakan"
|
||||
},
|
||||
{
|
||||
"name": "status_kahwin_tanggungan",
|
||||
"type": "select",
|
||||
"label": "Status Perkahwinan",
|
||||
"options": [
|
||||
{ "label": "Berkahwin", "value": "berkahwin" },
|
||||
{
|
||||
"label": "Ibu Tinggal/Bapa Tinggal",
|
||||
"value": "ibu_bapa_tinggal"
|
||||
},
|
||||
{ "label": "Bujang", "value": "bujang" },
|
||||
{ "label": "Duda", "value": "duda" },
|
||||
{ "label": "Janda", "value": "janda" },
|
||||
{ "label": "Balu", "value": "balu" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"help": "Jika Berkenaan",
|
||||
"name": "tarikh_masuk_islam_tanggungan",
|
||||
"type": "date",
|
||||
"label": "Tarikh Masuk Islam"
|
||||
},
|
||||
{
|
||||
"help": "Jika Berkenaan",
|
||||
"name": "tarikh_mula_kfam_tanggungan",
|
||||
"type": "date",
|
||||
"label": "Tarikh Mula KFAM"
|
||||
},
|
||||
{
|
||||
"help": "Jika Berkenaan",
|
||||
"name": "warganegara_tanggungan",
|
||||
"type": "text",
|
||||
"label": "Warganegara",
|
||||
"placeholder": "Masukkan warganegara"
|
||||
},
|
||||
{
|
||||
"name": "tempat_menetap_tanggungan",
|
||||
"type": "text",
|
||||
"label": "Tempoh Menetap Di Selangor",
|
||||
"placeholder": "Contoh: 5 Tahun"
|
||||
},
|
||||
{
|
||||
"name": "no_telefon_tanggungan",
|
||||
"type": "text",
|
||||
"label": "No. Telefon/Telefon Bimbit",
|
||||
"placeholder": "Contoh: 03-12345678"
|
||||
}
|
||||
],
|
||||
"maxItems": 10,
|
||||
"minItems": 1,
|
||||
"buttonText": "Tambah Tanggungan",
|
||||
"gridColumn": "span 12",
|
||||
"removeText": "Buang"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "heading",
|
||||
"props": {
|
||||
"name": "heading_maklumat_perbankan",
|
||||
"level": 3,
|
||||
"value": "MAKLUMAT PERBANKAN (Jika Berkenaan)",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"props": {
|
||||
"name": "nama_pemegang_akaun",
|
||||
"type": "text",
|
||||
"label": "Nama Pemegang Akaun",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"placeholder": "Masukkan nama pemegang akaun"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"props": {
|
||||
"name": "nama_bank",
|
||||
"type": "text",
|
||||
"label": "Bank",
|
||||
"width": "50%",
|
||||
"gridColumn": "span 6",
|
||||
"placeholder": "Masukkan nama bank"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"props": {
|
||||
"name": "no_akaun_bank",
|
||||
"type": "text",
|
||||
"label": "No. Akaun Bank",
|
||||
"width": "50%",
|
||||
"gridColumn": "span 6",
|
||||
"placeholder": "Masukkan nombor akaun"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "checkbox",
|
||||
"props": {
|
||||
"name": "cara_pembayaran",
|
||||
"type": "checkbox",
|
||||
"label": "Cara Pembayaran",
|
||||
"width": "100%",
|
||||
"options": [
|
||||
{ "label": "Akaun", "value": "akaun" },
|
||||
{ "label": "Cek", "value": "cek" },
|
||||
{ "label": "Tunai, Nyatakan Sebab", "value": "tunai" },
|
||||
{ "label": "Uzur/Sakit", "value": "uzur_sakit" },
|
||||
{ "label": "Muflis", "value": "muflis" },
|
||||
{ "label": "Disenarai Hitam", "value": "disenarai_hitam" }
|
||||
],
|
||||
"gridColumn": "span 12"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"props": {
|
||||
"name": "sebab_tunai",
|
||||
"type": "text",
|
||||
"label": "Sebab Pembayaran Tunai",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"placeholder": "Sila nyatakan sebab",
|
||||
"conditionalLogic": {
|
||||
"action": "hide",
|
||||
"enabled": true,
|
||||
"operator": "and",
|
||||
"conditions": [
|
||||
{
|
||||
"field": "cara_pembayaran",
|
||||
"value": "tunai",
|
||||
"operator": "not_contains"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "heading",
|
||||
"props": {
|
||||
"name": "heading_pendidikan",
|
||||
"level": 3,
|
||||
"value": "2. PENDIDIKAN",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "radio",
|
||||
"props": {
|
||||
"name": "bersekolah_tanggungan",
|
||||
"type": "radio",
|
||||
"label": "Bersekolah",
|
||||
"width": "100%",
|
||||
"options": [
|
||||
{ "label": "Ya", "value": "ya" },
|
||||
{ "label": "Tidak", "value": "tidak" }
|
||||
],
|
||||
"gridColumn": "span 12",
|
||||
"validation": "required"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "checkbox",
|
||||
"props": {
|
||||
"name": "pendidikan_tertinggi_tanggungan",
|
||||
"type": "checkbox",
|
||||
"label": "Pendidikan Tertinggi",
|
||||
"width": "100%",
|
||||
"options": [
|
||||
{ "label": "Peringkat Rendah", "value": "peringkat_rendah" },
|
||||
{ "label": "SRP/PMR", "value": "srp_pmr" },
|
||||
{ "label": "SPM", "value": "spm" },
|
||||
{ "label": "STPM", "value": "stpm" },
|
||||
{ "label": "Pra Sekolah", "value": "pra_sekolah" },
|
||||
{ "label": "Sekolah Rendah Kebangsaan", "value": "srk" },
|
||||
{ "label": "Sekolah Menengah Kebangsaan", "value": "smk" },
|
||||
{ "label": "Sekolah Menengah Agama", "value": "sma" },
|
||||
{ "label": "Sijil", "value": "sijil" },
|
||||
{ "label": "Diploma", "value": "diploma" },
|
||||
{ "label": "Ijazah", "value": "ijazah" },
|
||||
{ "label": "Lain-Lain (Sila Nyatakan)", "value": "lain_lain" },
|
||||
{
|
||||
"label": "Sekolah Rendah Kebangsaan dan Agama",
|
||||
"value": "srk_agama"
|
||||
},
|
||||
{ "label": "IPTA/IPTS", "value": "ipta_ipts" },
|
||||
{ "label": "Maahad Tahfiz", "value": "maahad_tahfiz" }
|
||||
],
|
||||
"gridColumn": "span 12"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"props": {
|
||||
"name": "pendidikan_lain_tanggungan",
|
||||
"type": "text",
|
||||
"label": "Nyatakan Pendidikan Lain-lain",
|
||||
"width": "100%",
|
||||
"gridColumn": "span 12",
|
||||
"placeholder": "Sila nyatakan",
|
||||
"conditionalLogic": {
|
||||
"action": "hide",
|
||||
"enabled": true,
|
||||
"operator": "and",
|
||||
"conditions": [
|
||||
{
|
||||
"field": "pendidikan_tertinggi_tanggungan",
|
||||
"value": "lain_lain",
|
||||
"operator": "not_contains"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "repeating-group",
|
||||
"props": {
|
||||
"help": "Tambah maklumat sekolah untuk setiap tanggungan yang bersekolah",
|
||||
"name": "maklumat_sekolah",
|
||||
"label": "Nama dan Alamat Sekolah/Institusi",
|
||||
"width": "100%",
|
||||
"fields": [
|
||||
{
|
||||
"name": "nama_sekolah",
|
||||
"type": "text",
|
||||
"label": "Nama Sekolah",
|
||||
"validation": "required",
|
||||
"placeholder": "Masukkan nama sekolah/institusi"
|
||||
},
|
||||
{
|
||||
"name": "alamat_sekolah",
|
||||
"type": "textarea",
|
||||
"label": "Alamat Sekolah",
|
||||
"validation": "required",
|
||||
"placeholder": "Masukkan alamat lengkap sekolah/institusi"
|
||||
},
|
||||
{
|
||||
"name": "daerah_sekolah",
|
||||
"type": "text",
|
||||
"label": "Daerah",
|
||||
"placeholder": "Masukkan daerah"
|
||||
},
|
||||
{
|
||||
"name": "negeri_sekolah",
|
||||
"type": "text",
|
||||
"label": "Negeri",
|
||||
"placeholder": "Masukkan negeri"
|
||||
},
|
||||
{
|
||||
"name": "poskod_sekolah",
|
||||
"type": "text",
|
||||
"label": "Poskod",
|
||||
"placeholder": "Masukkan poskod"
|
||||
}
|
||||
],
|
||||
"maxItems": 10,
|
||||
"minItems": 0,
|
||||
"buttonText": "Tambah Sekolah",
|
||||
"gridColumn": "span 12",
|
||||
"removeText": "Buang",
|
||||
"conditionalLogic": {
|
||||
"action": "hide",
|
||||
"enabled": true,
|
||||
"operator": "and",
|
||||
"conditions": [
|
||||
{
|
||||
"field": "bersekolah_tanggungan",
|
||||
"value": "ya",
|
||||
"operator": "not_equals"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "radio",
|
||||
"props": {
|
||||
"name": "tinggal_bersama_keluarga",
|
||||
"type": "radio",
|
||||
"label": "Tinggal Bersama Keluarga",
|
||||
"width": "100%",
|
||||
"options": [
|
||||
{ "label": "Ya", "value": "ya" },
|
||||
{ "label": "Tidak", "value": "tidak" },
|
||||
{ "label": "Asrama", "value": "asrama" }
|
||||
],
|
||||
"gridColumn": "span 12"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -33,17 +33,6 @@
|
||||
"sourceHandle": "api-1752550319410-right",
|
||||
"targetHandle": "script-1752550430989-left"
|
||||
},
|
||||
{
|
||||
"id": "script-1752550430989-html-1752550500000",
|
||||
"data": {},
|
||||
"type": "custom",
|
||||
"label": "",
|
||||
"source": "script-1752550430989",
|
||||
"target": "html-1752550500000",
|
||||
"animated": true,
|
||||
"sourceHandle": "script-1752550430989-right",
|
||||
"targetHandle": "html-1752550500000-left"
|
||||
},
|
||||
{
|
||||
"id": "html-1752550500000-end-1752546716111-1752550899936",
|
||||
"data": {},
|
||||
@ -76,6 +65,39 @@
|
||||
"animated": true,
|
||||
"sourceHandle": "notification-1752621850786-right",
|
||||
"targetHandle": "end-1752546716111-left"
|
||||
},
|
||||
{
|
||||
"id": "script-1752550430989-gateway-1752550505000",
|
||||
"data": {},
|
||||
"type": "custom",
|
||||
"label": "",
|
||||
"source": "script-1752550430989",
|
||||
"target": "gateway-1752550505000",
|
||||
"animated": true,
|
||||
"sourceHandle": "script-1752550430989-right",
|
||||
"targetHandle": "gateway-1752550505000-left"
|
||||
},
|
||||
{
|
||||
"id": "gateway-1752550505000-html-1752550500000",
|
||||
"data": { "condition": "todoStatus === true" },
|
||||
"type": "custom",
|
||||
"label": "Completed",
|
||||
"source": "gateway-1752550505000",
|
||||
"target": "html-1752550500000",
|
||||
"animated": true,
|
||||
"sourceHandle": "gateway-1752550505000-right",
|
||||
"targetHandle": "html-1752550500000-left"
|
||||
},
|
||||
{
|
||||
"id": "gateway-1752550505000-notification-1752621850786",
|
||||
"data": { "condition": "todoStatus === false" },
|
||||
"type": "custom",
|
||||
"label": "Not Completed",
|
||||
"source": "gateway-1752550505000",
|
||||
"target": "notification-1752621850786",
|
||||
"animated": true,
|
||||
"sourceHandle": "gateway-1752550505000-bottom",
|
||||
"targetHandle": "notification-1752621850786-left"
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
@ -84,15 +106,18 @@
|
||||
"data": { "label": "Start", "description": "Process start point" },
|
||||
"type": "start",
|
||||
"label": "Start",
|
||||
"position": { "x": 270, "y": 345 }
|
||||
"position": { "x": 300, "y": 135 }
|
||||
},
|
||||
{
|
||||
"id": "form-1752546702226",
|
||||
"data": {
|
||||
"label": "Pilihan Kategori Asnaf",
|
||||
"shape": "rectangle",
|
||||
"formId": 7,
|
||||
"formName": "Pilihan Kategori Asnaf",
|
||||
"formUuid": "d3612e05-b31a-46dc-b5e5-67e6c5bd3e78",
|
||||
"textColor": "#6b21a8",
|
||||
"borderColor": "#9333ea",
|
||||
"description": "Form: Pilihan Kategori Asnaf",
|
||||
"assignedRoles": [
|
||||
{ "label": "Pemohon", "value": "2", "description": "" }
|
||||
@ -104,20 +129,21 @@
|
||||
{ "formField": "kategori_asnaf", "processVariable": "kategoriAsnaf" },
|
||||
{ "formField": "nama_asnaf", "processVariable": "namaAsnaf" }
|
||||
],
|
||||
"backgroundColor": "#faf5ff",
|
||||
"fieldConditions": [],
|
||||
"assignmentVariable": "",
|
||||
"assignmentVariableType": "user_id"
|
||||
},
|
||||
"type": "form",
|
||||
"label": "Pilihan Kategori Asnaf",
|
||||
"position": { "x": 540, "y": 330 }
|
||||
"position": { "x": 510, "y": 105 }
|
||||
},
|
||||
{
|
||||
"id": "end-1752546716111",
|
||||
"data": { "label": "End", "description": "Process end point" },
|
||||
"type": "end",
|
||||
"label": "End",
|
||||
"position": { "x": 1890, "y": 135 }
|
||||
"position": { "x": 2070, "y": 300 }
|
||||
},
|
||||
{
|
||||
"id": "api-1752550319410",
|
||||
@ -144,7 +170,7 @@
|
||||
},
|
||||
"type": "api",
|
||||
"label": "API Call",
|
||||
"position": { "x": 855, "y": 345 }
|
||||
"position": { "x": 795, "y": 105 }
|
||||
},
|
||||
{
|
||||
"id": "script-1752550430989",
|
||||
@ -189,7 +215,62 @@
|
||||
},
|
||||
"type": "script",
|
||||
"label": "Script Task",
|
||||
"position": { "x": 1185, "y": 330 }
|
||||
"position": { "x": 1050, "y": 120 }
|
||||
},
|
||||
{
|
||||
"id": "gateway-1752550505000",
|
||||
"data": {
|
||||
"label": "Decision: Todo Status",
|
||||
"shape": "diamond",
|
||||
"textColor": "#c2410c",
|
||||
"conditions": [
|
||||
{
|
||||
"id": "condition-group-1",
|
||||
"output": "Completed",
|
||||
"conditions": [
|
||||
{
|
||||
"id": "condition-1",
|
||||
"value": true,
|
||||
"operator": "eq",
|
||||
"variable": "todoStatus",
|
||||
"valueType": "boolean",
|
||||
"logicalOperator": "and"
|
||||
},
|
||||
{
|
||||
"id": "condition-1753408402567",
|
||||
"value": "afiq",
|
||||
"maxValue": "",
|
||||
"minValue": "",
|
||||
"operator": "contains",
|
||||
"variable": "namaAsnaf",
|
||||
"valueType": "string",
|
||||
"logicalOperator": "and"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "condition-group-2",
|
||||
"output": "Not Completed",
|
||||
"conditions": [
|
||||
{
|
||||
"id": "condition-2",
|
||||
"value": false,
|
||||
"operator": "eq",
|
||||
"variable": "todoStatus",
|
||||
"valueType": "boolean",
|
||||
"logicalOperator": "and"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"borderColor": "#f97316",
|
||||
"defaultPath": "Default",
|
||||
"description": "Branch based on todoStatus",
|
||||
"backgroundColor": "#fff7ed"
|
||||
},
|
||||
"type": "gateway",
|
||||
"label": "Decision: Todo Status",
|
||||
"position": { "x": 1365, "y": 120 }
|
||||
},
|
||||
{
|
||||
"id": "html-1752550500000",
|
||||
@ -210,7 +291,7 @@
|
||||
},
|
||||
"type": "html",
|
||||
"label": "Show Result",
|
||||
"position": { "x": 1425, "y": 75 }
|
||||
"position": { "x": 1590, "y": 150 }
|
||||
},
|
||||
{
|
||||
"id": "notification-1752621850786",
|
||||
@ -239,8 +320,8 @@
|
||||
}
|
||||
],
|
||||
"viewport": {
|
||||
"x": -193.044397463002,
|
||||
"y": 197.8681289640592,
|
||||
"zoom": 1.049154334038055
|
||||
"x": -271.3433493533669,
|
||||
"y": 163.8456958483416,
|
||||
"zoom": 0.6965142034495484
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,18 @@
|
||||
"scope": "global",
|
||||
"description": "Title from API response"
|
||||
},
|
||||
"asnafScore": {
|
||||
"name": "asnafScore",
|
||||
"type": "number",
|
||||
"scope": "global",
|
||||
"description": "Calculated score based on input lengths"
|
||||
},
|
||||
"todoStatus": {
|
||||
"name": "todoStatus",
|
||||
"type": "boolean",
|
||||
"scope": "global",
|
||||
"description": "Completion status (true if id > 100)"
|
||||
},
|
||||
"apiResponse": {
|
||||
"name": "apiResponse",
|
||||
"type": "object",
|
||||
@ -31,28 +43,16 @@
|
||||
"scope": "global",
|
||||
"description": ""
|
||||
},
|
||||
"todoStatus": {
|
||||
"name": "todoStatus",
|
||||
"type": "boolean",
|
||||
"resultSummary": {
|
||||
"name": "resultSummary",
|
||||
"type": "string",
|
||||
"scope": "global",
|
||||
"description": "Completion status (true if id > 100)"
|
||||
},
|
||||
"asnafScore": {
|
||||
"name": "asnafScore",
|
||||
"type": "number",
|
||||
"scope": "global",
|
||||
"description": "Calculated score based on input lengths"
|
||||
"description": "Summary string for result"
|
||||
},
|
||||
"resultTimestamp": {
|
||||
"name": "resultTimestamp",
|
||||
"type": "string",
|
||||
"scope": "global",
|
||||
"description": "Timestamp when script ran"
|
||||
},
|
||||
"resultSummary": {
|
||||
"name": "resultSummary",
|
||||
"type": "string",
|
||||
"scope": "global",
|
||||
"description": "Summary string for result"
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,8 @@ components/process-flow/
|
||||
│ ├── NotificationManager.vue
|
||||
│ ├── NotificationQueue.vue
|
||||
│ └── NotificationLogs.vue
|
||||
├── GatewayConditionManager.vue # Gateway condition configuration UI
|
||||
├── GatewayConditionManagerModal.vue # Modal for gateway setup
|
||||
└── [25+ other process flow files]
|
||||
```
|
||||
|
||||
@ -454,6 +456,153 @@ const customProperties = computed(() => props.data?.customProperties || {})
|
||||
</template>
|
||||
```
|
||||
|
||||
### **4. Gateway Decision Logic**
|
||||
|
||||
#### **Gateway Configuration UI Components**
|
||||
```vue
|
||||
<!-- GatewayConditionManager.vue - Main condition builder -->
|
||||
<template>
|
||||
<div class="gateway-condition-manager">
|
||||
<!-- Empty state when no paths defined -->
|
||||
<div v-if="localConditions.length === 0" class="text-center p-6">
|
||||
<h3>No Decision Paths Defined</h3>
|
||||
<p>Your process will always follow the default path</p>
|
||||
<button @click="addConditionGroup">Add Your First Path</button>
|
||||
</div>
|
||||
|
||||
<!-- Decision paths list -->
|
||||
<div v-else class="conditions-list">
|
||||
<div v-for="(group, groupIndex) in localConditions" :key="group.id">
|
||||
<!-- Path header with collapse/expand -->
|
||||
<div class="path-header" @click="toggleGroupCollapse(group.id)">
|
||||
<span>Path {{ groupIndex + 1 }}</span>
|
||||
<span v-if="group.output">{{ group.output }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Path details when expanded -->
|
||||
<div v-if="!isGroupCollapsed(group.id)" class="path-details">
|
||||
<!-- Path name input -->
|
||||
<input v-model="group.output" placeholder="Path label (e.g. 'Yes', 'Approved')" />
|
||||
|
||||
<!-- Conditions list -->
|
||||
<div class="conditions-list">
|
||||
<div v-for="(condition, conditionIndex) in group.conditions" :key="condition.id">
|
||||
<!-- Variable selection -->
|
||||
<VariableBrowser v-model="condition.variable" :availableVariables="availableVariables" />
|
||||
|
||||
<!-- Operator selection -->
|
||||
<select v-model="condition.operator">
|
||||
<option v-for="op in getOperatorsForType(condition.valueType)" :key="op.value" :value="op.value">
|
||||
{{ op.label }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<!-- Value input -->
|
||||
<input v-model="condition.value" :placeholder="getValuePlaceholder(condition)" />
|
||||
|
||||
<!-- Logical operator for multiple conditions -->
|
||||
<div v-if="conditionIndex > 0">
|
||||
<label>Combine with: AND/OR</label>
|
||||
<input type="radio" v-model="condition.logicalOperator" value="and" /> AND
|
||||
<input type="radio" v-model="condition.logicalOperator" value="or" /> OR
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
#### **Condition Evaluation Process**
|
||||
```javascript
|
||||
// Workflow execution evaluates gateway conditions
|
||||
function evaluateConditionGroup(conditionGroup, variables) {
|
||||
if (!conditionGroup.conditions || conditionGroup.conditions.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If only one condition, evaluate it directly
|
||||
if (conditionGroup.conditions.length === 1) {
|
||||
return evaluateCondition(conditionGroup.conditions[0], variables);
|
||||
}
|
||||
|
||||
// For multiple conditions, evaluate based on logical operators
|
||||
let result = evaluateCondition(conditionGroup.conditions[0], variables);
|
||||
|
||||
for (let i = 1; i < conditionGroup.conditions.length; i++) {
|
||||
const condition = conditionGroup.conditions[i];
|
||||
const conditionResult = evaluateCondition(condition, variables);
|
||||
const operator = condition.logicalOperator || 'and';
|
||||
|
||||
if (operator === 'and') {
|
||||
result = result && conditionResult;
|
||||
} else if (operator === 'or') {
|
||||
result = result || conditionResult;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Single condition evaluation
|
||||
function evaluateCondition(condition, variables) {
|
||||
const { variable, operator, value, valueType } = condition;
|
||||
const variableValue = variables[variable];
|
||||
|
||||
// Handle boolean type conversions
|
||||
let compareValue = value;
|
||||
if (valueType === 'boolean') {
|
||||
if (typeof value === 'string') {
|
||||
compareValue = value.toLowerCase() === 'true';
|
||||
} else {
|
||||
compareValue = Boolean(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate based on operator
|
||||
switch (operator) {
|
||||
case 'eq':
|
||||
return variableValue == compareValue;
|
||||
case 'gt':
|
||||
return Number(variableValue) > Number(compareValue);
|
||||
case 'is_true':
|
||||
return Boolean(variableValue) === true;
|
||||
// ... other operators
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **Decision Path Selection**
|
||||
```javascript
|
||||
// Determine which path to follow based on conditions
|
||||
function getNextNodeIdForDecision(currentNodeId) {
|
||||
const currentNodeObj = workflowData.nodes.find(n => n.id === currentNodeId);
|
||||
const outgoingEdges = getOutgoingEdges(currentNodeId);
|
||||
|
||||
if (!currentNodeObj || !outgoingEdges.length) return null;
|
||||
|
||||
const { conditions = [] } = currentNodeObj.data || {};
|
||||
|
||||
// Evaluate condition groups (each group represents a path)
|
||||
for (const conditionGroup of conditions) {
|
||||
if (evaluateConditionGroup(conditionGroup, variables)) {
|
||||
// Find the edge that matches this condition group's output label
|
||||
const edge = outgoingEdges.find(e => e.label === conditionGroup.output);
|
||||
if (edge) return edge.target;
|
||||
}
|
||||
}
|
||||
|
||||
// If no conditions match, use default path
|
||||
const defaultEdge = outgoingEdges.find(e => e.data?.isDefault);
|
||||
if (defaultEdge) return defaultEdge.target;
|
||||
|
||||
// Fallback to first edge
|
||||
return outgoingEdges[0]?.target || null;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Styling System
|
||||
@ -577,7 +726,7 @@ export default defineNuxtPlugin(() => {
|
||||
formId: 'form-uuid', // For form nodes
|
||||
apiEndpoint: 'url', // For API nodes
|
||||
scriptCode: 'javascript', // For script nodes
|
||||
conditions: [], // For gateway nodes
|
||||
conditions: [], // For gateway nodes (see Gateway Conditions section)
|
||||
|
||||
// Custom properties
|
||||
customProperties: {}
|
||||
@ -585,6 +734,73 @@ export default defineNuxtPlugin(() => {
|
||||
}
|
||||
```
|
||||
|
||||
### **Gateway Conditions Structure**
|
||||
```javascript
|
||||
// Gateway node conditions format (group-based)
|
||||
{
|
||||
id: 'gateway-node-id',
|
||||
type: 'gateway',
|
||||
data: {
|
||||
label: 'Decision Point',
|
||||
conditions: [
|
||||
{
|
||||
id: 'condition-group-1',
|
||||
output: 'Path Label', // Label for this decision path
|
||||
conditions: [ // Array of conditions for this path
|
||||
{
|
||||
id: 'condition-1',
|
||||
variable: 'processVariable', // Process variable to evaluate
|
||||
operator: 'eq', // Comparison operator
|
||||
value: 'expectedValue', // Value to compare against
|
||||
valueType: 'string', // Data type (string, boolean, number, etc.)
|
||||
logicalOperator: 'and' // How to combine with next condition (and/or)
|
||||
}
|
||||
// ... more conditions for this path
|
||||
]
|
||||
}
|
||||
// ... more condition groups (paths)
|
||||
],
|
||||
defaultPath: 'Default' // Default path if no conditions match
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **Supported Condition Operators**
|
||||
```javascript
|
||||
// String operators
|
||||
'eq', 'equals', '==' // Equal to
|
||||
'neq', 'not_equals', '!=' // Not equal to
|
||||
'contains' // Contains substring
|
||||
'not_contains' // Does not contain
|
||||
'starts_with' // Starts with
|
||||
'ends_with' // Ends with
|
||||
'empty' // Is empty/null
|
||||
'not_empty' // Is not empty/null
|
||||
'regex' // Matches regex pattern
|
||||
|
||||
// Numeric operators
|
||||
'gt', 'greater_than', '>' // Greater than
|
||||
'lt', 'less_than', '<' // Less than
|
||||
'gte', 'greater_than_or_equal', '>=' // Greater than or equal
|
||||
'lte', 'less_than_or_equal', '<=' // Less than or equal
|
||||
'between' // Between two values
|
||||
'not_between' // Not between two values
|
||||
|
||||
// Boolean operators
|
||||
'is_true' // Is true
|
||||
'is_false' // Is false
|
||||
|
||||
// Date operators
|
||||
'today' // Is today
|
||||
'this_week' // Is this week
|
||||
'this_month' // Is this month
|
||||
'this_year' // Is this year
|
||||
|
||||
// Object operators
|
||||
'has_property' // Has specific property
|
||||
'property_equals' // Property equals value
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Common Issues & Solutions
|
||||
@ -700,4 +916,46 @@ const nodeTypes = {
|
||||
|
||||
**🔄 Version**: 1.0 - Comprehensive system documentation
|
||||
|
||||
**👥 For New Team Members**: This document contains everything needed to understand and work with the Vue Flow Process Builder system. Start with the "File Structure" section and follow the implementation patterns for any new features.
|
||||
**👥 For New Team Members**: This document contains everything needed to understand and work with the Vue Flow Process Builder system. Start with the "File Structure" section and follow the implementation patterns for any new features.
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Gateway Decisions
|
||||
|
||||
### **Form Field Integration**
|
||||
To test gateway decisions, add form fields that map to process variables:
|
||||
|
||||
```json
|
||||
// Form component with gateway test field
|
||||
{
|
||||
"type": "checkbox",
|
||||
"props": {
|
||||
"name": "todoStatus",
|
||||
"label": "Test Gateway Decision",
|
||||
"help": "Toggle to test gateway paths"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **Process Variable Mapping**
|
||||
Map form fields to process variables for gateway testing:
|
||||
|
||||
```json
|
||||
// Form node output mappings
|
||||
{
|
||||
"outputMappings": [
|
||||
{ "formField": "todoStatus", "processVariable": "todoStatus" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### **Gateway Testing Scenarios**
|
||||
1. **"Completed" Path**: Check the test field → `todoStatus = true` → Follow "Completed" path
|
||||
2. **"Not Completed" Path**: Leave test field unchecked → `todoStatus = false` → Follow "Not Completed" path
|
||||
|
||||
### **Workflow Execution**
|
||||
The workflow execution engine (`pages/workflow/[id].vue`) automatically:
|
||||
- Evaluates gateway conditions based on current process variables
|
||||
- Shows visual feedback of which conditions are true/false
|
||||
- Follows the first matching path
|
||||
- Falls back to default path if no conditions match
|
@ -155,63 +155,204 @@ function getNextNodeIdForDecision(currentNodeId) {
|
||||
|
||||
if (!currentNodeObj || !outgoingEdges.length) return null;
|
||||
|
||||
const { conditions = [], defaultPath } = currentNodeObj.data || {};
|
||||
const { conditions = [] } = currentNodeObj.data || {};
|
||||
|
||||
// Evaluate conditions
|
||||
for (const condition of conditions) {
|
||||
if (evaluateCondition(condition, processVariables.value)) {
|
||||
// Find the edge that matches this condition's target
|
||||
const edge = outgoingEdges.find(e => e.data?.conditionId === condition.id || e.label === condition.label);
|
||||
// Evaluate condition groups (each group represents a path)
|
||||
for (const conditionGroup of conditions) {
|
||||
if (evaluateConditionGroup(conditionGroup, processVariables.value)) {
|
||||
// Find the edge that matches this condition group's output label
|
||||
const edge = outgoingEdges.find(e => e.label === conditionGroup.output || e.data?.condition === conditionGroup.output);
|
||||
if (edge) return edge.target;
|
||||
}
|
||||
}
|
||||
|
||||
// If no conditions match, use default path
|
||||
if (defaultPath) {
|
||||
const defaultEdge = outgoingEdges.find(e => e.data?.isDefault || e.label?.toLowerCase().includes('default'));
|
||||
if (defaultEdge) return defaultEdge.target;
|
||||
}
|
||||
// If no conditions match, look for default path
|
||||
const defaultEdge = outgoingEdges.find(e => e.data?.isDefault || e.label?.toLowerCase().includes('default'));
|
||||
if (defaultEdge) return defaultEdge.target;
|
||||
|
||||
// Fallback to first edge
|
||||
return outgoingEdges[0]?.target || null;
|
||||
}
|
||||
|
||||
// Helper: Evaluate a condition group (multiple conditions with AND/OR logic)
|
||||
function evaluateConditionGroup(conditionGroup, variables) {
|
||||
if (!conditionGroup.conditions || conditionGroup.conditions.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If only one condition, evaluate it directly
|
||||
if (conditionGroup.conditions.length === 1) {
|
||||
const singleResult = evaluateCondition(conditionGroup.conditions[0], variables);
|
||||
console.log(`[Gateway Debug] Group '${conditionGroup.output}': single condition result=`, singleResult);
|
||||
return singleResult;
|
||||
}
|
||||
|
||||
// For multiple conditions, evaluate based on logical operators
|
||||
let result = evaluateCondition(conditionGroup.conditions[0], variables);
|
||||
console.log(`[Gateway Debug] Group '${conditionGroup.output}': condition 0 result=`, result);
|
||||
|
||||
for (let i = 1; i < conditionGroup.conditions.length; i++) {
|
||||
const condition = conditionGroup.conditions[i];
|
||||
const conditionResult = evaluateCondition(condition, variables);
|
||||
const operator = condition.logicalOperator || 'and';
|
||||
if (operator === 'and') {
|
||||
result = result && conditionResult;
|
||||
} else if (operator === 'or') {
|
||||
result = result || conditionResult;
|
||||
}
|
||||
console.log(`[Gateway Debug] Group '${conditionGroup.output}': after condition ${i}, operator='${operator}', conditionResult=`, conditionResult, ', groupResult=', result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper: Evaluate a single condition
|
||||
function evaluateCondition(condition, variables) {
|
||||
const { variable, operator, value } = condition;
|
||||
const { variable, operator, value, valueType, minValue, maxValue } = condition;
|
||||
const variableValue = variables[variable];
|
||||
|
||||
|
||||
// Handle boolean type conversions
|
||||
let compareValue = value;
|
||||
if (valueType === 'boolean') {
|
||||
if (typeof value === 'string') {
|
||||
compareValue = value.toLowerCase() === 'true';
|
||||
} else {
|
||||
compareValue = Boolean(value);
|
||||
}
|
||||
}
|
||||
|
||||
let result;
|
||||
switch (operator) {
|
||||
case 'eq':
|
||||
case 'equals':
|
||||
case '==':
|
||||
return variableValue == value;
|
||||
result = variableValue == compareValue;
|
||||
break;
|
||||
case 'neq':
|
||||
case 'not_equals':
|
||||
case '!=':
|
||||
return variableValue != value;
|
||||
result = variableValue != compareValue;
|
||||
break;
|
||||
case 'gt':
|
||||
case 'greater_than':
|
||||
case '>':
|
||||
return Number(variableValue) > Number(value);
|
||||
result = Number(variableValue) > Number(compareValue);
|
||||
break;
|
||||
case 'lt':
|
||||
case 'less_than':
|
||||
case '<':
|
||||
return Number(variableValue) < Number(value);
|
||||
result = Number(variableValue) < Number(compareValue);
|
||||
break;
|
||||
case 'gte':
|
||||
case 'greater_than_or_equal':
|
||||
case '>=':
|
||||
return Number(variableValue) >= Number(value);
|
||||
result = Number(variableValue) >= Number(compareValue);
|
||||
break;
|
||||
case 'lte':
|
||||
case 'less_than_or_equal':
|
||||
case '<=':
|
||||
return Number(variableValue) <= Number(value);
|
||||
result = Number(variableValue) <= Number(compareValue);
|
||||
break;
|
||||
case 'between':
|
||||
result = (
|
||||
Number(variableValue) >= Number(minValue) &&
|
||||
Number(variableValue) <= Number(maxValue)
|
||||
);
|
||||
break;
|
||||
case 'not_between':
|
||||
result = (
|
||||
Number(variableValue) < Number(minValue) ||
|
||||
Number(variableValue) > Number(maxValue)
|
||||
);
|
||||
break;
|
||||
case 'contains':
|
||||
return String(variableValue).includes(String(value));
|
||||
result = String(variableValue).includes(String(compareValue));
|
||||
break;
|
||||
case 'not_contains':
|
||||
return !String(variableValue).includes(String(value));
|
||||
result = !String(variableValue).includes(String(compareValue));
|
||||
break;
|
||||
case 'starts_with':
|
||||
result = String(variableValue).startsWith(String(compareValue));
|
||||
break;
|
||||
case 'ends_with':
|
||||
result = String(variableValue).endsWith(String(compareValue));
|
||||
break;
|
||||
case 'regex':
|
||||
try {
|
||||
result = new RegExp(compareValue).test(variableValue);
|
||||
} catch (e) {
|
||||
result = false;
|
||||
}
|
||||
break;
|
||||
case 'has_property':
|
||||
result = variableValue && typeof variableValue === 'object' && value in variableValue;
|
||||
break;
|
||||
case 'property_equals': {
|
||||
if (!variableValue || typeof variableValue !== 'object' || typeof compareValue !== 'string') { result = false; break; }
|
||||
const [prop, val] = compareValue.split(':');
|
||||
result = variableValue[prop] == val;
|
||||
break;
|
||||
}
|
||||
case 'empty':
|
||||
case 'is_empty':
|
||||
return !variableValue || variableValue === '' || variableValue === null || variableValue === undefined;
|
||||
result = !variableValue || variableValue === '' || variableValue === null || variableValue === undefined;
|
||||
break;
|
||||
case 'not_empty':
|
||||
case 'is_not_empty':
|
||||
return variableValue && variableValue !== '' && variableValue !== null && variableValue !== undefined;
|
||||
result = variableValue && variableValue !== '' && variableValue !== null && variableValue !== undefined;
|
||||
break;
|
||||
case 'is_true':
|
||||
result = Boolean(variableValue) === true;
|
||||
break;
|
||||
case 'is_false':
|
||||
result = Boolean(variableValue) === false;
|
||||
break;
|
||||
// Date operators
|
||||
case 'today': {
|
||||
if (!variableValue) { result = false; break; }
|
||||
const date = new Date(variableValue);
|
||||
const now = new Date();
|
||||
result = (
|
||||
date.getFullYear() === now.getFullYear() &&
|
||||
date.getMonth() === now.getMonth() &&
|
||||
date.getDate() === now.getDate()
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'this_week': {
|
||||
if (!variableValue) { result = false; break; }
|
||||
const date = new Date(variableValue);
|
||||
const now = new Date();
|
||||
const startOfWeek = new Date(now);
|
||||
startOfWeek.setDate(now.getDate() - now.getDay());
|
||||
const endOfWeek = new Date(startOfWeek);
|
||||
endOfWeek.setDate(startOfWeek.getDate() + 6);
|
||||
result = date >= startOfWeek && date <= endOfWeek;
|
||||
break;
|
||||
}
|
||||
case 'this_month': {
|
||||
if (!variableValue) { result = false; break; }
|
||||
const date = new Date(variableValue);
|
||||
const now = new Date();
|
||||
result = (
|
||||
date.getFullYear() === now.getFullYear() &&
|
||||
date.getMonth() === now.getMonth()
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'this_year': {
|
||||
if (!variableValue) { result = false; break; }
|
||||
const date = new Date(variableValue);
|
||||
const now = new Date();
|
||||
result = date.getFullYear() === now.getFullYear();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.warn('[Workflow] Unknown condition operator:', operator);
|
||||
return false;
|
||||
result = false;
|
||||
}
|
||||
console.log(`[Gateway Debug] Condition: variable='${variable}', operator='${operator}', value=`, value, ', minValue=', minValue, ', maxValue=', maxValue, '| variableValue=', variableValue, '| result=', result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Move to a specific node by its ID
|
||||
@ -744,7 +885,10 @@ const executeDecisionNode = async () => {
|
||||
stepLoading.value = true;
|
||||
const currentNodeObj = workflowData.value.nodes[currentStep.value];
|
||||
const { executionType = 'automatic' } = currentNodeObj.data || {};
|
||||
|
||||
|
||||
// Debug: Log process variables before evaluating gateway
|
||||
console.log('[Gateway Debug] Current processVariables:', JSON.stringify(processVariables.value, null, 2));
|
||||
|
||||
if (executionType === 'automatic') {
|
||||
// Automatic decision based on conditions
|
||||
const nextNodeId = getNextNodeIdForDecision(currentNodeObj.id);
|
||||
@ -837,6 +981,16 @@ const htmlNodeStyles = computed(() => {
|
||||
return currentNode.value?.data?.cssCode || '';
|
||||
});
|
||||
|
||||
// Computed: Condition evaluation results for gateway nodes
|
||||
const conditionEvaluationResults = computed(() => {
|
||||
if (!['decision', 'gateway'].includes(currentNode.value?.type)) return [];
|
||||
if (!currentNode.value?.data?.conditions) return [];
|
||||
|
||||
return currentNode.value.data.conditions.map(conditionGroup =>
|
||||
getConditionGroupResult(conditionGroup, processVariables.value)
|
||||
);
|
||||
});
|
||||
|
||||
// CSS injection for HTML nodes
|
||||
let currentStyleElement = null;
|
||||
// JS injection for HTML nodes
|
||||
@ -923,6 +1077,51 @@ function getNodeLabel(nodeId) {
|
||||
const node = workflowData.value.nodes.find(n => n.id === nodeId);
|
||||
return node?.data?.label || node?.label || 'Next Step';
|
||||
}
|
||||
|
||||
// Helper: Get human-readable condition description
|
||||
function getConditionDescription(condition, variables) {
|
||||
const { variable, operator, value, valueType } = condition;
|
||||
const variableValue = variables[variable];
|
||||
|
||||
let operatorText = operator;
|
||||
switch (operator) {
|
||||
case 'eq': operatorText = '='; break;
|
||||
case 'neq': operatorText = '≠'; break;
|
||||
case 'gt': operatorText = '>'; break;
|
||||
case 'lt': operatorText = '<'; break;
|
||||
case 'gte': operatorText = '≥'; break;
|
||||
case 'lte': operatorText = '≤'; break;
|
||||
case 'contains': operatorText = 'contains'; break;
|
||||
case 'not_contains': operatorText = 'does not contain'; break;
|
||||
case 'starts_with': operatorText = 'starts with'; break;
|
||||
case 'ends_with': operatorText = 'ends with'; break;
|
||||
case 'empty': operatorText = 'is empty'; break;
|
||||
case 'not_empty': operatorText = 'is not empty'; break;
|
||||
case 'is_true': operatorText = 'is true'; break;
|
||||
case 'is_false': operatorText = 'is false'; break;
|
||||
}
|
||||
|
||||
if (['empty', 'not_empty', 'is_true', 'is_false'].includes(operator)) {
|
||||
return `${variable} ${operatorText}`;
|
||||
}
|
||||
|
||||
return `${variable} ${operatorText} ${value}`;
|
||||
}
|
||||
|
||||
// Helper: Get condition group evaluation result
|
||||
function getConditionGroupResult(conditionGroup, variables) {
|
||||
const results = conditionGroup.conditions.map(condition => {
|
||||
const result = evaluateCondition(condition, variables);
|
||||
const description = getConditionDescription(condition, variables);
|
||||
return { result, description };
|
||||
});
|
||||
|
||||
return {
|
||||
group: conditionGroup,
|
||||
results,
|
||||
finalResult: evaluateConditionGroup(conditionGroup, variables)
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -1280,12 +1479,36 @@ function getNodeLabel(nodeId) {
|
||||
|
||||
<!-- Show conditions being evaluated -->
|
||||
<div v-if="currentNode.data?.conditions?.length" class="mt-6 text-left">
|
||||
<h5 class="font-medium text-gray-700 mb-3">Conditions:</h5>
|
||||
<div class="space-y-2">
|
||||
<div v-for="(condition, index) in currentNode.data.conditions" :key="index"
|
||||
class="flex items-center gap-2 text-sm text-gray-600 bg-gray-50 p-2 rounded">
|
||||
<Icon name="material-symbols:rule" class="w-4 h-4" />
|
||||
<span>{{ condition.variable }} {{ condition.operator }} {{ condition.value }}</span>
|
||||
<h5 class="font-medium text-gray-700 mb-3">Decision Paths:</h5>
|
||||
<div class="space-y-3">
|
||||
<div v-for="(evaluationResult, groupIndex) in conditionEvaluationResults" :key="groupIndex"
|
||||
class="border rounded-lg p-3"
|
||||
:class="evaluationResult.finalResult ? 'border-green-300 bg-green-50' : 'border-gray-200 bg-gray-50'">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<Icon name="material-symbols:alt-route" class="w-4 h-4"
|
||||
:class="evaluationResult.finalResult ? 'text-green-500' : 'text-orange-500'" />
|
||||
<span class="font-medium text-sm">{{ evaluationResult.group.output || `Path ${groupIndex + 1}` }}</span>
|
||||
<span v-if="evaluationResult.finalResult"
|
||||
class="px-2 py-0.5 text-xs bg-green-100 text-green-700 rounded-full">
|
||||
MATCH
|
||||
</span>
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<div v-for="(conditionResult, conditionIndex) in evaluationResult.results" :key="conditionIndex"
|
||||
class="flex items-center gap-2 text-xs">
|
||||
<Icon name="material-symbols:rule" class="w-3 h-3"
|
||||
:class="conditionResult.result ? 'text-green-500' : 'text-red-500'" />
|
||||
<span v-if="conditionIndex > 0" class="text-orange-600 font-medium">
|
||||
{{ evaluationResult.group.conditions[conditionIndex].logicalOperator?.toUpperCase() || 'AND' }}
|
||||
</span>
|
||||
<span :class="conditionResult.result ? 'text-green-700' : 'text-red-700'">
|
||||
{{ conditionResult.description }}
|
||||
</span>
|
||||
<span class="text-gray-500">
|
||||
({{ conditionResult.result ? '✓' : '✗' }})
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1324,12 +1547,12 @@ function getNodeLabel(nodeId) {
|
||||
<pre class="text-gray-600 bg-white p-2 rounded border overflow-auto">{{ JSON.stringify(currentNode.data.fieldConditions, null, 2) }}</pre>
|
||||
</div>
|
||||
<!-- Current Field States -->
|
||||
<div v-if="Object.keys(fieldStates).length">
|
||||
<div v-if="Object.keys(fieldStates || {}).length">
|
||||
<p class="font-medium text-gray-700">Active Field States:</p>
|
||||
<pre class="text-gray-600 bg-white p-2 rounded border overflow-auto">{{ JSON.stringify(fieldStates, null, 2) }}</pre>
|
||||
</div>
|
||||
<!-- Form Data -->
|
||||
<div v-if="Object.keys(formData).length">
|
||||
<div v-if="Object.keys(formData || {}).length">
|
||||
<p class="font-medium text-gray-700">Current Form Data:</p>
|
||||
<pre class="text-gray-600 bg-white p-2 rounded border overflow-auto">{{ JSON.stringify(formData, null, 2) }}</pre>
|
||||
</div>
|
||||
@ -1343,7 +1566,7 @@ function getNodeLabel(nodeId) {
|
||||
</div>
|
||||
|
||||
<!-- Process Variables Debug (only in development) -->
|
||||
<div v-if="Object.keys(processVariables).length > 0" class="bg-gray-100 rounded-lg p-4 mt-4">
|
||||
<div v-if="Object.keys(processVariables || {}).length > 0" class="bg-gray-100 rounded-lg p-4 mt-4">
|
||||
<details>
|
||||
<summary class="font-medium text-gray-700 cursor-pointer mb-2">Process Variables (Debug)</summary>
|
||||
<pre class="text-xs text-gray-600 bg-white p-2 rounded border overflow-auto">{{ JSON.stringify(processVariables, null, 2) }}</pre>
|
||||
|
Loading…
x
Reference in New Issue
Block a user