@nyaruka/temba-components 0.130.5 → 0.131.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -20
- package/dist/temba-components.js +66 -65
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_random.js +1 -0
- package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js +254 -65
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
- package/out-tsc/src/form/ArrayEditor.js +195 -2
- package/out-tsc/src/form/ArrayEditor.js.map +1 -1
- package/out-tsc/src/form/ContactSearch.js +1 -1
- package/out-tsc/src/form/ContactSearch.js.map +1 -1
- package/out-tsc/src/form/select/Omnibox.js +4 -0
- package/out-tsc/src/form/select/Omnibox.js.map +1 -1
- package/out-tsc/test/nodes/wait_for_response.test.js +373 -8
- package/out-tsc/test/nodes/wait_for_response.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/basic-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/custom-result-name.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/no-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/short-timeout.png +0 -0
- package/src/flow/nodes/split_by_random.ts +1 -0
- package/src/flow/nodes/wait_for_response.ts +327 -72
- package/src/form/ArrayEditor.ts +260 -2
- package/src/form/ContactSearch.ts +1 -1
- package/src/form/select/Omnibox.ts +3 -0
- package/test/nodes/wait_for_response.test.ts +426 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"split_by_random.js","sourceRoot":"","sources":["../../../../src/flow/nodes/split_by_random.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAc,MAAM,UAAU,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,4DAA4D;AAC5D,MAAM,kBAAkB,GAAG,CACzB,cAAwB,EACxB,qBAAiC,EAAE,EACnC,gBAAwB,EAAE,EAC1B,EAAE;IACF,MAAM,UAAU,GAAe,EAAE,CAAC;IAClC,MAAM,KAAK,GAAW,EAAE,CAAC;IAEzB,uDAAuD;IACvD,cAAc,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE;QACtC,wCAAwC;QACxC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,IAAI,CAC9C,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,YAAY,CACnC,CAAC;QACF,MAAM,YAAY,GAAG,gBAAgB;YACnC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,gBAAgB,CAAC,SAAS,CAAC;YACxE,CAAC,CAAC,IAAI,CAAC;QAET,MAAM,QAAQ,GAAG,CAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,IAAI,KAAI,YAAY,EAAE,CAAC;QACtD,MAAM,YAAY,GAAG,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,IAAI,KAAI,YAAY,EAAE,CAAC;QAE9D,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,YAAY;YAClB,SAAS,EAAE,QAAQ;SACpB,CAAC,CAAC;QAEH,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,QAAQ;YACd,gBAAgB,EAAE,CAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,gBAAgB,KAAI,IAAI;SACzD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE;YACN,IAAI,EAAE,QAAiB;YACvB,UAAU,EAAE,UAAU;SACvB;QACD,KAAK,EAAE,KAAK;KACb,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAe;IACzC,IAAI,EAAE,iBAAiB;IACvB,IAAI,EAAE,iBAAiB;IACvB,KAAK,EAAE,MAAM,CAAC,KAAK;IACnB,IAAI,EAAE;QACJ,UAAU,EAAE;YACV,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,SAAS;YAChB,QAAQ,EAAE,oDAAoD;YAC9D,QAAQ,EAAE,IAAI;YACd,SAAS,EAAE,QAAQ;YACnB,QAAQ,EAAE,CAAC;YACX,QAAQ,EAAE,EAAE;YACZ,WAAW,EAAE,CAAC,IAAS,EAAE,EAAE;gBACzB,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;YAC/C,CAAC;YACD,UAAU,EAAE;gBACV,IAAI,EAAE;oBACJ,IAAI,EAAE,MAAM;oBACZ,WAAW,EAAE,aAAa;oBAC1B,QAAQ,EAAE,IAAI;iBACf;aACF;SACF;KACF;IACD,MAAM,EAAE,CAAC,YAAY,CAAC;IACtB,QAAQ,EAAE,CAAC,QAAa,EAAE,EAAE;QAC1B,MAAM,MAAM,GAA8B,EAAE,CAAC;QAE7C,qCAAqC;QACrC,IAAI,QAAQ,CAAC,UAAU,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9D,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,CAC3C,CAAC,IAAS,EAAE,EAAE,CAAC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,IAAI,KAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CACrD,CAAC;YAEF,yBAAyB;YACzB,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,MAAM,CAAC,UAAU,GAAG,kDAAkD,CAAC;YACzE,CAAC;YAED,8DAA8D;YAC9D,MAAM,mBAAmB,GAAG,EAAE,CAAC;YAC/B,MAAM,YAAY,GAAG,IAAI,GAAG,EAAE,CAAC;YAE/B,wDAAwD;YACxD,UAAU,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;gBAC9B,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;gBACrD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;oBACjC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;gBAClC,CAAC;gBACD,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACzD,CAAC,CAAC,CAAC;YAEH,4DAA4D;YAC5D,YAAY,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,EAAE;gBACrC,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC7B,mBAAmB,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;gBAC7C,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnC,MAAM,gBAAgB,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC;gBAC3D,MAAM,CAAC,UAAU,GAAG,iCAAiC,gBAAgB,CAAC,IAAI,CACxE,IAAI,CACL,EAAE,CAAC;YACN,CAAC;QACH,CAAC;QAED,OAAO;YACL,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC;YACvC,MAAM;SACP,CAAC;IACJ,CAAC;IACD,UAAU,EAAE,CAAC,IAAU,EAAE,EAAE;;QACzB,sDAAsD;QACtD,MAAM,UAAU,GACd,CAAA,MAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,UAAU,0CAAE,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,KAAI,EAAE,CAAC;QAEpE,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,UAAU,EAAE,UAAU;SACvB,CAAC;IACJ,CAAC;IACD,YAAY,EAAE,CAAC,QAAa,EAAE,YAAkB,EAAQ,EAAE;;QACxD,sBAAsB;QACtB,MAAM,cAAc,GAAG,CAAC,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAC;aAC/C,MAAM,CAAC,CAAC,IAAS,EAAE,EAAE,WAAC,OAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,IAAI,0CAAE,IAAI,EAAE,CAAA,EAAA,CAAC;aACzC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAExC,4DAA4D;QAC5D,MAAM,kBAAkB,GAAG,CAAA,MAAA,YAAY,CAAC,MAAM,0CAAE,UAAU,KAAI,EAAE,CAAC;QACjE,MAAM,aAAa,GAAG,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC;QAE/C,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,kBAAkB,CAC1C,cAAc,EACd,kBAAkB,EAClB,aAAa,CACd,CAAC;QAEF,2BAA2B;QAC3B,OAAO;YACL,IAAI,EAAE,YAAY,CAAC,IAAI;YACvB,OAAO,EAAE,YAAY,CAAC,OAAO,IAAI,EAAE;YACnC,MAAM,EAAE,MAAM;YACd,KAAK,EAAE,KAAK;SACb,CAAC;IACJ,CAAC;IACD,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;KACf;CACF,CAAC","sourcesContent":["import { COLORS, NodeConfig } from '../types';\nimport { Node, Category, Exit } from '../../store/flow-definition.d';\nimport { generateUUID } from '../../utils';\n\n// Helper function to create a random router with categories\nconst createRandomRouter = (\n userCategories: string[],\n existingCategories: Category[] = [],\n existingExits: Exit[] = []\n) => {\n const categories: Category[] = [];\n const exits: Exit[] = [];\n\n // Create categories and exits for user-defined buckets\n userCategories.forEach((categoryName) => {\n // Try to find existing category by name\n const existingCategory = existingCategories.find(\n (cat) => cat.name === categoryName\n );\n const existingExit = existingCategory\n ? existingExits.find((exit) => exit.uuid === existingCategory.exit_uuid)\n : null;\n\n const exitUuid = existingExit?.uuid || generateUUID();\n const categoryUuid = existingCategory?.uuid || generateUUID();\n\n categories.push({\n uuid: categoryUuid,\n name: categoryName,\n exit_uuid: exitUuid\n });\n\n exits.push({\n uuid: exitUuid,\n destination_uuid: existingExit?.destination_uuid || null\n });\n });\n\n return {\n router: {\n type: 'random' as const,\n categories: categories\n },\n exits: exits\n };\n};\n\nexport const split_by_random: NodeConfig = {\n type: 'split_by_random',\n name: 'Split by Random',\n color: COLORS.split,\n form: {\n categories: {\n type: 'array',\n label: 'Buckets',\n helpText: 'Define the buckets to randomly split contacts into',\n required: true,\n itemLabel: 'Bucket',\n minItems: 2,\n maxItems: 10,\n isEmptyItem: (item: any) => {\n return !item.name || item.name.trim() === '';\n },\n itemConfig: {\n name: {\n type: 'text',\n placeholder: 'Bucket name',\n required: true\n }\n }\n }\n },\n layout: ['categories'],\n validate: (formData: any) => {\n const errors: { [key: string]: string } = {};\n\n // Check for duplicate category names\n if (formData.categories && Array.isArray(formData.categories)) {\n const categories = formData.categories.filter(\n (item: any) => item?.name && item.name.trim() !== ''\n );\n\n // Ensure minimum buckets\n if (categories.length < 2) {\n errors.categories = 'At least 2 buckets are required for random split';\n }\n\n // Find all categories that have duplicates (case-insensitive)\n const duplicateCategories = [];\n const lowerCaseMap = new Map();\n\n // First pass: map lowercase names to all original cases\n categories.forEach((category) => {\n const lowerName = category.name.trim().toLowerCase();\n if (!lowerCaseMap.has(lowerName)) {\n lowerCaseMap.set(lowerName, []);\n }\n lowerCaseMap.get(lowerName).push(category.name.trim());\n });\n\n // Second pass: collect all names that appear more than once\n lowerCaseMap.forEach((originalNames) => {\n if (originalNames.length > 1) {\n duplicateCategories.push(...originalNames);\n }\n });\n\n if (duplicateCategories.length > 0) {\n const uniqueDuplicates = [...new Set(duplicateCategories)];\n errors.categories = `Duplicate bucket names found: ${uniqueDuplicates.join(\n ', '\n )}`;\n }\n }\n\n return {\n valid: Object.keys(errors).length === 0,\n errors\n };\n },\n toFormData: (node: Node) => {\n // Extract categories from the existing node structure\n const categories =\n node.router?.categories?.map((cat) => ({ name: cat.name })) || [];\n\n return {\n uuid: node.uuid,\n categories: categories\n };\n },\n fromFormData: (formData: any, originalNode: Node): Node => {\n // Get user categories\n const userCategories = (formData.categories || [])\n .filter((item: any) => item?.name?.trim())\n .map((item: any) => item.name.trim());\n\n // Create router and exits using existing data when possible\n const existingCategories = originalNode.router?.categories || [];\n const existingExits = originalNode.exits || [];\n\n const { router, exits } = createRandomRouter(\n userCategories,\n existingCategories,\n existingExits\n );\n\n // Return the complete node\n return {\n uuid: originalNode.uuid,\n actions: originalNode.actions || [],\n router: router,\n exits: exits\n };\n },\n router: {\n type: 'random'\n }\n};\n"]}
|
|
1
|
+
{"version":3,"file":"split_by_random.js","sourceRoot":"","sources":["../../../../src/flow/nodes/split_by_random.ts"],"names":[],"mappings":"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","sourcesContent":["import { COLORS, NodeConfig } from '../types';\nimport { Node, Category, Exit } from '../../store/flow-definition.d';\nimport { generateUUID } from '../../utils';\n\n// Helper function to create a random router with categories\nconst createRandomRouter = (\n userCategories: string[],\n existingCategories: Category[] = [],\n existingExits: Exit[] = []\n) => {\n const categories: Category[] = [];\n const exits: Exit[] = [];\n\n // Create categories and exits for user-defined buckets\n userCategories.forEach((categoryName) => {\n // Try to find existing category by name\n const existingCategory = existingCategories.find(\n (cat) => cat.name === categoryName\n );\n const existingExit = existingCategory\n ? existingExits.find((exit) => exit.uuid === existingCategory.exit_uuid)\n : null;\n\n const exitUuid = existingExit?.uuid || generateUUID();\n const categoryUuid = existingCategory?.uuid || generateUUID();\n\n categories.push({\n uuid: categoryUuid,\n name: categoryName,\n exit_uuid: exitUuid\n });\n\n exits.push({\n uuid: exitUuid,\n destination_uuid: existingExit?.destination_uuid || null\n });\n });\n\n return {\n router: {\n type: 'random' as const,\n categories: categories\n },\n exits: exits\n };\n};\n\nexport const split_by_random: NodeConfig = {\n type: 'split_by_random',\n name: 'Split by Random',\n color: COLORS.split,\n form: {\n categories: {\n type: 'array',\n label: 'Buckets',\n helpText: 'Define the buckets to randomly split contacts into',\n required: true,\n itemLabel: 'Bucket',\n sortable: true,\n minItems: 2,\n maxItems: 10,\n isEmptyItem: (item: any) => {\n return !item.name || item.name.trim() === '';\n },\n itemConfig: {\n name: {\n type: 'text',\n placeholder: 'Bucket name',\n required: true\n }\n }\n }\n },\n layout: ['categories'],\n validate: (formData: any) => {\n const errors: { [key: string]: string } = {};\n\n // Check for duplicate category names\n if (formData.categories && Array.isArray(formData.categories)) {\n const categories = formData.categories.filter(\n (item: any) => item?.name && item.name.trim() !== ''\n );\n\n // Ensure minimum buckets\n if (categories.length < 2) {\n errors.categories = 'At least 2 buckets are required for random split';\n }\n\n // Find all categories that have duplicates (case-insensitive)\n const duplicateCategories = [];\n const lowerCaseMap = new Map();\n\n // First pass: map lowercase names to all original cases\n categories.forEach((category) => {\n const lowerName = category.name.trim().toLowerCase();\n if (!lowerCaseMap.has(lowerName)) {\n lowerCaseMap.set(lowerName, []);\n }\n lowerCaseMap.get(lowerName).push(category.name.trim());\n });\n\n // Second pass: collect all names that appear more than once\n lowerCaseMap.forEach((originalNames) => {\n if (originalNames.length > 1) {\n duplicateCategories.push(...originalNames);\n }\n });\n\n if (duplicateCategories.length > 0) {\n const uniqueDuplicates = [...new Set(duplicateCategories)];\n errors.categories = `Duplicate bucket names found: ${uniqueDuplicates.join(\n ', '\n )}`;\n }\n }\n\n return {\n valid: Object.keys(errors).length === 0,\n errors\n };\n },\n toFormData: (node: Node) => {\n // Extract categories from the existing node structure\n const categories =\n node.router?.categories?.map((cat) => ({ name: cat.name })) || [];\n\n return {\n uuid: node.uuid,\n categories: categories\n };\n },\n fromFormData: (formData: any, originalNode: Node): Node => {\n // Get user categories\n const userCategories = (formData.categories || [])\n .filter((item: any) => item?.name?.trim())\n .map((item: any) => item.name.trim());\n\n // Create router and exits using existing data when possible\n const existingCategories = originalNode.router?.categories || [];\n const existingExits = originalNode.exits || [];\n\n const { router, exits } = createRandomRouter(\n userCategories,\n existingCategories,\n existingExits\n );\n\n // Return the complete node\n return {\n uuid: originalNode.uuid,\n actions: originalNode.actions || [],\n router: router,\n exits: exits\n };\n },\n router: {\n type: 'random'\n }\n};\n"]}
|
|
@@ -21,16 +21,115 @@ const TIMEOUT_OPTIONS = [
|
|
|
21
21
|
{ value: '259200', name: '3 days' },
|
|
22
22
|
{ value: '604800', name: '1 week' }
|
|
23
23
|
];
|
|
24
|
+
// Helper function to check if a category is a system category
|
|
25
|
+
const isSystemCategory = (categoryName) => {
|
|
26
|
+
return ['No Response', 'Other', 'All Responses', 'Timeout'].includes(categoryName);
|
|
27
|
+
};
|
|
28
|
+
// Helper function to check if a UUID belongs to a system category
|
|
29
|
+
const isSystemCategoryUuid = (uuid, categories) => {
|
|
30
|
+
const category = categories.find((cat) => cat.uuid === uuid);
|
|
31
|
+
return category ? isSystemCategory(category.name) : false;
|
|
32
|
+
};
|
|
33
|
+
// Helper function to generate default category name based on operator and operands
|
|
34
|
+
const generateDefaultCategoryName = (operator, value1, value2) => {
|
|
35
|
+
const operatorConfig = getOperatorConfig(operator);
|
|
36
|
+
if (!operatorConfig)
|
|
37
|
+
return '';
|
|
38
|
+
// Fixed category names (no operands)
|
|
39
|
+
if (operatorConfig.operands === 0) {
|
|
40
|
+
return operatorConfig.categoryName || '';
|
|
41
|
+
}
|
|
42
|
+
// Dynamic category names based on operands
|
|
43
|
+
const cleanValue1 = (value1 || '').trim();
|
|
44
|
+
const cleanValue2 = (value2 || '').trim();
|
|
45
|
+
// Helper to capitalize first letter
|
|
46
|
+
const capitalize = (str) => {
|
|
47
|
+
if (!str)
|
|
48
|
+
return '';
|
|
49
|
+
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
50
|
+
};
|
|
51
|
+
// Handle different operator types
|
|
52
|
+
switch (operator) {
|
|
53
|
+
// Word/phrase operators - capitalize first letter of value
|
|
54
|
+
case 'has_any_word':
|
|
55
|
+
case 'has_all_words':
|
|
56
|
+
case 'has_phrase':
|
|
57
|
+
case 'has_only_phrase':
|
|
58
|
+
case 'has_beginning':
|
|
59
|
+
return cleanValue1 ? capitalize(cleanValue1) : '';
|
|
60
|
+
// Pattern operators - show as-is
|
|
61
|
+
case 'has_pattern':
|
|
62
|
+
return cleanValue1;
|
|
63
|
+
// Number comparison operators - include symbol
|
|
64
|
+
case 'has_number_eq':
|
|
65
|
+
return cleanValue1 ? `= ${cleanValue1}` : '';
|
|
66
|
+
case 'has_number_lt':
|
|
67
|
+
return cleanValue1 ? `< ${cleanValue1}` : '';
|
|
68
|
+
case 'has_number_lte':
|
|
69
|
+
return cleanValue1 ? `≤ ${cleanValue1}` : '';
|
|
70
|
+
case 'has_number_gt':
|
|
71
|
+
return cleanValue1 ? `> ${cleanValue1}` : '';
|
|
72
|
+
case 'has_number_gte':
|
|
73
|
+
return cleanValue1 ? `≥ ${cleanValue1}` : '';
|
|
74
|
+
// Number between - range format
|
|
75
|
+
case 'has_number_between':
|
|
76
|
+
if (cleanValue1 && cleanValue2) {
|
|
77
|
+
return `${cleanValue1} - ${cleanValue2}`;
|
|
78
|
+
}
|
|
79
|
+
return '';
|
|
80
|
+
// Date operators - format with relative expressions
|
|
81
|
+
case 'has_date_lt':
|
|
82
|
+
case 'has_date_lte':
|
|
83
|
+
if (cleanValue1) {
|
|
84
|
+
// Parse relative date expression (e.g., "today + 5" or "today - 3")
|
|
85
|
+
const match = cleanValue1.match(/^(today)\s*([+-])\s*(\d+)$/i);
|
|
86
|
+
if (match) {
|
|
87
|
+
const [, base, operator, days] = match;
|
|
88
|
+
const dayWord = days === '1' ? 'day' : 'days';
|
|
89
|
+
return `Before ${base} ${operator} ${days} ${dayWord}`;
|
|
90
|
+
}
|
|
91
|
+
// Fallback for other date formats
|
|
92
|
+
return `Before ${cleanValue1}`;
|
|
93
|
+
}
|
|
94
|
+
return '';
|
|
95
|
+
case 'has_date_gt':
|
|
96
|
+
case 'has_date_gte':
|
|
97
|
+
if (cleanValue1) {
|
|
98
|
+
// Parse relative date expression
|
|
99
|
+
const match = cleanValue1.match(/^(today)\s*([+-])\s*(\d+)$/i);
|
|
100
|
+
if (match) {
|
|
101
|
+
const [, base, operator, days] = match;
|
|
102
|
+
const dayWord = days === '1' ? 'day' : 'days';
|
|
103
|
+
return `After ${base} ${operator} ${days} ${dayWord}`;
|
|
104
|
+
}
|
|
105
|
+
// Fallback for other date formats
|
|
106
|
+
return `After ${cleanValue1}`;
|
|
107
|
+
}
|
|
108
|
+
return '';
|
|
109
|
+
case 'has_date_eq':
|
|
110
|
+
if (cleanValue1) {
|
|
111
|
+
// Parse relative date expression
|
|
112
|
+
const match = cleanValue1.match(/^(today)\s*([+-])\s*(\d+)$/i);
|
|
113
|
+
if (match) {
|
|
114
|
+
const [, base, operator, days] = match;
|
|
115
|
+
const dayWord = days === '1' ? 'day' : 'days';
|
|
116
|
+
return `${base} ${operator} ${days} ${dayWord}`;
|
|
117
|
+
}
|
|
118
|
+
return cleanValue1;
|
|
119
|
+
}
|
|
120
|
+
return '';
|
|
121
|
+
default:
|
|
122
|
+
// Fallback - capitalize first value
|
|
123
|
+
return cleanValue1 ? capitalize(cleanValue1) : '';
|
|
124
|
+
}
|
|
125
|
+
};
|
|
24
126
|
// Helper function to create a wait_for_response router with user rules
|
|
25
127
|
const createWaitForResponseRouter = (userRules, existingCategories = [], existingExits = [], existingCases = []) => {
|
|
26
|
-
var _a;
|
|
27
128
|
const categories = [];
|
|
28
129
|
const exits = [];
|
|
29
130
|
const cases = [];
|
|
30
131
|
// Filter existing categories to get only user-defined rules (exclude system categories)
|
|
31
|
-
const existingUserCategories = existingCategories.filter((cat) => cat.name
|
|
32
|
-
cat.name !== 'Other' &&
|
|
33
|
-
cat.name !== 'Timeout');
|
|
132
|
+
const existingUserCategories = existingCategories.filter((cat) => !isSystemCategory(cat.name));
|
|
34
133
|
// Track categories as we create them (case-insensitive lookup)
|
|
35
134
|
const createdCategories = new Map();
|
|
36
135
|
// Process rules in their original order to preserve rule order
|
|
@@ -46,13 +145,24 @@ const createWaitForResponseRouter = (userRules, existingCategories = [], existin
|
|
|
46
145
|
const categoryCreationOrder = Array.from(createdCategories.keys()).length;
|
|
47
146
|
if (!existingCategory &&
|
|
48
147
|
categoryCreationOrder < existingUserCategories.length) {
|
|
49
|
-
|
|
148
|
+
const candidateCategory = existingUserCategories[categoryCreationOrder];
|
|
149
|
+
// Double-check that this candidate is not a system category UUID
|
|
150
|
+
if (candidateCategory &&
|
|
151
|
+
!isSystemCategoryUuid(candidateCategory.uuid, existingCategories)) {
|
|
152
|
+
existingCategory = candidateCategory;
|
|
153
|
+
}
|
|
50
154
|
}
|
|
51
155
|
const existingExit = existingCategory
|
|
52
156
|
? existingExits.find((exit) => exit.uuid === existingCategory.exit_uuid)
|
|
53
157
|
: null;
|
|
54
|
-
|
|
55
|
-
|
|
158
|
+
// Generate UUIDs, ensuring we don't reuse system category UUIDs
|
|
159
|
+
let exitUuid = (existingExit === null || existingExit === void 0 ? void 0 : existingExit.uuid) || generateUUID();
|
|
160
|
+
let categoryUuid = (existingCategory === null || existingCategory === void 0 ? void 0 : existingCategory.uuid) || generateUUID();
|
|
161
|
+
// Additional safety check: if somehow we got a system category UUID, generate new ones
|
|
162
|
+
if (isSystemCategoryUuid(categoryUuid, existingCategories)) {
|
|
163
|
+
categoryUuid = generateUUID();
|
|
164
|
+
exitUuid = generateUUID();
|
|
165
|
+
}
|
|
56
166
|
categoryInfo = {
|
|
57
167
|
uuid: categoryUuid,
|
|
58
168
|
name: categoryName,
|
|
@@ -128,39 +238,46 @@ const createWaitForResponseRouter = (userRules, existingCategories = [], existin
|
|
|
128
238
|
category_uuid: categoryInfo.uuid
|
|
129
239
|
});
|
|
130
240
|
});
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
241
|
+
// Add default category (always present)
|
|
242
|
+
// Name is "Other" if there are user rules, "All Responses" if there are no user rules
|
|
243
|
+
const defaultCategoryName = userRules.length > 0 ? 'Other' : 'All Responses';
|
|
244
|
+
// Try to find existing default category by name (prefer exact match)
|
|
245
|
+
let existingDefaultCategory = existingCategories.find((cat) => cat.name === defaultCategoryName);
|
|
246
|
+
// If no exact match, try to find the other possible default category name
|
|
247
|
+
if (!existingDefaultCategory) {
|
|
248
|
+
const alternateName = userRules.length > 0 ? 'All Responses' : 'Other';
|
|
249
|
+
existingDefaultCategory = existingCategories.find((cat) => cat.name === alternateName);
|
|
250
|
+
}
|
|
251
|
+
const existingDefaultExit = existingDefaultCategory
|
|
252
|
+
? existingExits.find((exit) => exit.uuid === existingDefaultCategory.exit_uuid)
|
|
253
|
+
: null;
|
|
254
|
+
const defaultExitUuid = (existingDefaultExit === null || existingDefaultExit === void 0 ? void 0 : existingDefaultExit.uuid) || generateUUID();
|
|
255
|
+
const defaultCategoryUuid = (existingDefaultCategory === null || existingDefaultCategory === void 0 ? void 0 : existingDefaultCategory.uuid) || generateUUID();
|
|
256
|
+
categories.push({
|
|
257
|
+
uuid: defaultCategoryUuid,
|
|
258
|
+
name: defaultCategoryName,
|
|
259
|
+
exit_uuid: defaultExitUuid
|
|
140
260
|
});
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
});
|
|
154
|
-
exits.push({
|
|
155
|
-
uuid: otherExitUuid,
|
|
156
|
-
destination_uuid: (existingOtherExit === null || existingOtherExit === void 0 ? void 0 : existingOtherExit.destination_uuid) || null
|
|
157
|
-
});
|
|
261
|
+
exits.push({
|
|
262
|
+
uuid: defaultExitUuid,
|
|
263
|
+
destination_uuid: (existingDefaultExit === null || existingDefaultExit === void 0 ? void 0 : existingDefaultExit.destination_uuid) || null
|
|
264
|
+
});
|
|
265
|
+
// Add "No Response" category last (if it exists in the original)
|
|
266
|
+
const existingNoResponseCategory = existingCategories.find((cat) => cat.name === 'No Response' || cat.name === 'Timeout');
|
|
267
|
+
if (existingNoResponseCategory) {
|
|
268
|
+
const existingNoResponseExit = existingExits.find((exit) => exit.uuid === existingNoResponseCategory.exit_uuid);
|
|
269
|
+
if (existingNoResponseExit) {
|
|
270
|
+
categories.push(existingNoResponseCategory);
|
|
271
|
+
exits.push(existingNoResponseExit);
|
|
272
|
+
}
|
|
158
273
|
}
|
|
274
|
+
// Find the default category (either "Other" or "All Responses")
|
|
275
|
+
const defaultCategory = categories.find((cat) => cat.name === 'Other' || cat.name === 'All Responses');
|
|
159
276
|
return {
|
|
160
277
|
router: {
|
|
161
278
|
type: 'switch',
|
|
162
279
|
categories: categories,
|
|
163
|
-
default_category_uuid:
|
|
280
|
+
default_category_uuid: defaultCategory === null || defaultCategory === void 0 ? void 0 : defaultCategory.uuid,
|
|
164
281
|
operand: '@input.text',
|
|
165
282
|
cases: cases
|
|
166
283
|
},
|
|
@@ -225,6 +342,55 @@ export const wait_for_response = {
|
|
|
225
342
|
// No value required for this operator
|
|
226
343
|
return false;
|
|
227
344
|
},
|
|
345
|
+
onItemChange: (itemIndex, field, value, allItems) => {
|
|
346
|
+
const updatedItems = [...allItems];
|
|
347
|
+
const item = { ...updatedItems[itemIndex] };
|
|
348
|
+
// Helper to get operator value from various formats
|
|
349
|
+
const getOperatorValue = (operator) => {
|
|
350
|
+
if (typeof operator === 'string') {
|
|
351
|
+
return operator.trim();
|
|
352
|
+
}
|
|
353
|
+
else if (Array.isArray(operator) && operator.length > 0) {
|
|
354
|
+
const firstOperator = operator[0];
|
|
355
|
+
if (firstOperator &&
|
|
356
|
+
typeof firstOperator === 'object' &&
|
|
357
|
+
firstOperator.value) {
|
|
358
|
+
return firstOperator.value.trim();
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
else if (operator &&
|
|
362
|
+
typeof operator === 'object' &&
|
|
363
|
+
operator.value) {
|
|
364
|
+
return operator.value.trim();
|
|
365
|
+
}
|
|
366
|
+
return '';
|
|
367
|
+
};
|
|
368
|
+
// Update the changed field
|
|
369
|
+
item[field] = value;
|
|
370
|
+
// Get operator values (before and after the change)
|
|
371
|
+
const oldItem = allItems[itemIndex] || {};
|
|
372
|
+
const oldOperatorValue = field === 'operator'
|
|
373
|
+
? getOperatorValue(oldItem.operator)
|
|
374
|
+
: getOperatorValue(item.operator);
|
|
375
|
+
const newOperatorValue = getOperatorValue(item.operator);
|
|
376
|
+
// Calculate what the default category name should be before the change
|
|
377
|
+
const oldDefaultCategory = generateDefaultCategoryName(oldOperatorValue, field === 'value1' ? oldItem.value1 : item.value1, field === 'value2' ? oldItem.value2 : item.value2);
|
|
378
|
+
// Calculate what the new default category name should be after the change
|
|
379
|
+
const newDefaultCategory = generateDefaultCategoryName(newOperatorValue, item.value1, item.value2);
|
|
380
|
+
// Determine if we should auto-update the category
|
|
381
|
+
const shouldUpdateCategory =
|
|
382
|
+
// Category is empty
|
|
383
|
+
!item.category ||
|
|
384
|
+
item.category.trim() === '' ||
|
|
385
|
+
// Category matches the old default (user hasn't customized it)
|
|
386
|
+
item.category === oldDefaultCategory;
|
|
387
|
+
// Auto-populate or update category if conditions are met
|
|
388
|
+
if (shouldUpdateCategory && newDefaultCategory) {
|
|
389
|
+
item.category = newDefaultCategory;
|
|
390
|
+
}
|
|
391
|
+
updatedItems[itemIndex] = item;
|
|
392
|
+
return updatedItems;
|
|
393
|
+
},
|
|
228
394
|
itemConfig: {
|
|
229
395
|
operator: {
|
|
230
396
|
type: 'select',
|
|
@@ -361,10 +527,8 @@ export const wait_for_response = {
|
|
|
361
527
|
node.router.cases.forEach((case_) => {
|
|
362
528
|
// Find the category for this case
|
|
363
529
|
const category = node.router.categories.find((cat) => cat.uuid === case_.category_uuid);
|
|
364
|
-
// Skip
|
|
365
|
-
if (category &&
|
|
366
|
-
category.name !== 'No Response' &&
|
|
367
|
-
category.name !== 'Other') {
|
|
530
|
+
// Skip system categories
|
|
531
|
+
if (category && !isSystemCategory(category.name)) {
|
|
368
532
|
// Handle different operator types
|
|
369
533
|
const operatorConfig = getOperatorConfig(case_.type);
|
|
370
534
|
const operatorDisplayName = operatorConfig
|
|
@@ -416,7 +580,7 @@ export const wait_for_response = {
|
|
|
416
580
|
};
|
|
417
581
|
},
|
|
418
582
|
fromFormData: (formData, originalNode) => {
|
|
419
|
-
var _a, _b, _c, _d, _e, _f, _g, _h
|
|
583
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
420
584
|
// Helper function to get operator value from various formats
|
|
421
585
|
const getOperatorValue = (operator) => {
|
|
422
586
|
if (typeof operator === 'string') {
|
|
@@ -490,14 +654,46 @@ export const wait_for_response = {
|
|
|
490
654
|
});
|
|
491
655
|
// If no user rules, clear cases but preserve other router config
|
|
492
656
|
if (userRules.length === 0) {
|
|
657
|
+
// Get existing router data for preservation
|
|
658
|
+
let existingCategories = ((_a = originalNode.router) === null || _a === void 0 ? void 0 : _a.categories) || [];
|
|
659
|
+
const existingExits = [...(originalNode.exits || [])]; // Create a copy to avoid extensibility issues
|
|
660
|
+
// Handle timeout: ensure "No Response" category exists if timeout is enabled,
|
|
661
|
+
// or remove it if timeout is disabled
|
|
662
|
+
if (formData.timeout_enabled) {
|
|
663
|
+
let noResponseCategory = existingCategories.find((cat) => cat.name === 'No Response');
|
|
664
|
+
if (!noResponseCategory) {
|
|
665
|
+
// Create new "No Response" category and exit
|
|
666
|
+
const noResponseExitUuid = generateUUID();
|
|
667
|
+
noResponseCategory = {
|
|
668
|
+
uuid: generateUUID(),
|
|
669
|
+
name: 'No Response',
|
|
670
|
+
exit_uuid: noResponseExitUuid
|
|
671
|
+
};
|
|
672
|
+
// Add to existing categories for processing
|
|
673
|
+
existingCategories = [...existingCategories, noResponseCategory];
|
|
674
|
+
// Add corresponding exit if it doesn't exist
|
|
675
|
+
if (!existingExits.find((exit) => exit.uuid === noResponseExitUuid)) {
|
|
676
|
+
existingExits.push({
|
|
677
|
+
uuid: noResponseExitUuid,
|
|
678
|
+
destination_uuid: null
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
// If timeout is disabled, remove "No Response" category from existing categories
|
|
685
|
+
existingCategories = existingCategories.filter((cat) => cat.name !== 'No Response');
|
|
686
|
+
}
|
|
687
|
+
// Create router with "All Responses" as default category
|
|
688
|
+
// This will now properly handle the "No Response" category if it exists
|
|
689
|
+
const { router: noRulesRouter, exits: noRulesExits } = createWaitForResponseRouter([], // No user rules
|
|
690
|
+
existingCategories, existingExits, [] // No cases
|
|
691
|
+
);
|
|
493
692
|
const router = {
|
|
494
|
-
...
|
|
495
|
-
result_name: formData.result_name || 'response'
|
|
693
|
+
...noRulesRouter,
|
|
694
|
+
result_name: formData.result_name || 'response',
|
|
695
|
+
cases: [] // Clear all cases when no rules
|
|
496
696
|
};
|
|
497
|
-
// Only set cases to empty if the original node had cases
|
|
498
|
-
if (((_a = originalNode.router) === null || _a === void 0 ? void 0 : _a.cases) !== undefined) {
|
|
499
|
-
router.cases = []; // Clear all cases when no rules
|
|
500
|
-
}
|
|
501
697
|
// Build wait configuration based on form data
|
|
502
698
|
const waitConfig = {
|
|
503
699
|
type: 'msg'
|
|
@@ -532,33 +728,26 @@ export const wait_for_response = {
|
|
|
532
728
|
if (isNaN(timeoutSeconds) || timeoutSeconds <= 0) {
|
|
533
729
|
timeoutSeconds = 300; // Default to 5 minutes
|
|
534
730
|
}
|
|
535
|
-
// Find
|
|
536
|
-
|
|
537
|
-
if (
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
exit_uuid: generateUUID()
|
|
731
|
+
// Find the "No Response" category (should exist now)
|
|
732
|
+
const noResponseCategory = router.categories.find((cat) => cat.name === 'No Response');
|
|
733
|
+
if (noResponseCategory) {
|
|
734
|
+
waitConfig.timeout = {
|
|
735
|
+
seconds: timeoutSeconds,
|
|
736
|
+
category_uuid: noResponseCategory.uuid
|
|
542
737
|
};
|
|
543
|
-
// Add to router categories
|
|
544
|
-
router.categories = router.categories || [];
|
|
545
|
-
router.categories.push(noResponseCategory);
|
|
546
738
|
}
|
|
547
|
-
waitConfig.timeout = {
|
|
548
|
-
seconds: timeoutSeconds,
|
|
549
|
-
category_uuid: noResponseCategory.uuid
|
|
550
|
-
};
|
|
551
739
|
}
|
|
552
740
|
router.wait = waitConfig;
|
|
553
741
|
return {
|
|
554
742
|
...originalNode,
|
|
555
|
-
router
|
|
743
|
+
router,
|
|
744
|
+
exits: noRulesExits
|
|
556
745
|
};
|
|
557
746
|
}
|
|
558
747
|
// Get existing router data for preservation
|
|
559
|
-
const existingCategories = ((
|
|
748
|
+
const existingCategories = ((_b = originalNode.router) === null || _b === void 0 ? void 0 : _b.categories) || [];
|
|
560
749
|
const existingExits = originalNode.exits || [];
|
|
561
|
-
const existingCases = ((
|
|
750
|
+
const existingCases = ((_c = originalNode.router) === null || _c === void 0 ? void 0 : _c.cases) || [];
|
|
562
751
|
// Create router and exits using existing data when possible
|
|
563
752
|
const { router, exits } = createWaitForResponseRouter(userRules, existingCategories, existingExits, existingCases);
|
|
564
753
|
// Build final router with wait configuration and result_name
|
|
@@ -584,7 +773,7 @@ export const wait_for_response = {
|
|
|
584
773
|
}
|
|
585
774
|
}
|
|
586
775
|
// Find or create the "No Response" category
|
|
587
|
-
const existingNoResponseCategory = (
|
|
776
|
+
const existingNoResponseCategory = (_e = (_d = originalNode.router) === null || _d === void 0 ? void 0 : _d.categories) === null || _e === void 0 ? void 0 : _e.find((cat) => cat.name === 'No Response');
|
|
588
777
|
const noResponseCategory = existingNoResponseCategory || {
|
|
589
778
|
uuid: generateUUID(),
|
|
590
779
|
name: 'No Response',
|
|
@@ -595,7 +784,7 @@ export const wait_for_response = {
|
|
|
595
784
|
category_uuid: noResponseCategory.uuid
|
|
596
785
|
};
|
|
597
786
|
// Ensure No Response category and exit exist
|
|
598
|
-
if (!((
|
|
787
|
+
if (!((_f = router.categories) === null || _f === void 0 ? void 0 : _f.some((cat) => cat.name === 'No Response'))) {
|
|
599
788
|
router.categories = router.categories || [];
|
|
600
789
|
router.categories.push(noResponseCategory);
|
|
601
790
|
// Add corresponding exit if it doesn't exist
|
|
@@ -603,7 +792,7 @@ export const wait_for_response = {
|
|
|
603
792
|
const noResponseExit = {
|
|
604
793
|
uuid: noResponseCategory.exit_uuid,
|
|
605
794
|
destination_uuid: (existingNoResponseCategory === null || existingNoResponseCategory === void 0 ? void 0 : existingNoResponseCategory.exit_uuid)
|
|
606
|
-
? ((
|
|
795
|
+
? ((_h = (_g = originalNode.exits) === null || _g === void 0 ? void 0 : _g.find((exit) => exit.uuid === existingNoResponseCategory.exit_uuid)) === null || _h === void 0 ? void 0 : _h.destination_uuid) || null
|
|
607
796
|
: null
|
|
608
797
|
};
|
|
609
798
|
exits.push(noResponseExit);
|