@nyaruka/temba-components 0.130.0 → 0.130.2
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 +34 -4
- package/DEV_DATA.md +89 -0
- package/demo/data/flows/food-order.json +4 -4
- package/demo/data/flows/sample-flow.json +132 -147
- package/dist/temba-components.js +764 -628
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/display/Chat.js +5 -3
- package/out-tsc/src/display/Chat.js.map +1 -1
- package/out-tsc/src/events.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +83 -78
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +1 -0
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +47 -3
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/actions/add_contact_groups.js +13 -1
- package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -1
- package/out-tsc/src/flow/actions/add_contact_urn.js +1 -1
- package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -1
- package/out-tsc/src/flow/actions/add_input_labels.js +1 -0
- package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_field.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_language.js +3 -1
- package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_name.js +1 -1
- package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_status.js +17 -14
- package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
- package/out-tsc/src/flow/actions/set_run_result.js +1 -1
- package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm.js +12 -12
- package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js +609 -6
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
- package/out-tsc/src/flow/operators.js +194 -0
- package/out-tsc/src/flow/operators.js.map +1 -0
- package/out-tsc/src/flow/types.js.map +1 -1
- package/out-tsc/src/form/ArrayEditor.js +84 -19
- package/out-tsc/src/form/ArrayEditor.js.map +1 -1
- package/out-tsc/src/form/Checkbox.js +12 -0
- package/out-tsc/src/form/Checkbox.js.map +1 -1
- package/out-tsc/src/form/FieldRenderer.js +13 -3
- package/out-tsc/src/form/FieldRenderer.js.map +1 -1
- package/out-tsc/src/form/TextInput.js +20 -1
- package/out-tsc/src/form/TextInput.js.map +1 -1
- package/out-tsc/src/form/select/Select.js +14 -1
- package/out-tsc/src/form/select/Select.js.map +1 -1
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/layout/Dialog.js +3 -4
- package/out-tsc/src/layout/Dialog.js.map +1 -1
- package/out-tsc/src/list/RunList.js +2 -2
- package/out-tsc/src/list/RunList.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +114 -34
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/live/ContactDetails.js +7 -0
- package/out-tsc/src/live/ContactDetails.js.map +1 -1
- package/out-tsc/src/live/ContactNameFetch.js +1 -1
- package/out-tsc/src/live/ContactNameFetch.js.map +1 -1
- package/out-tsc/test/NodeHelper.js +25 -27
- package/out-tsc/test/NodeHelper.js.map +1 -1
- package/out-tsc/test/nodes/split_by_llm.test.js +12 -4
- package/out-tsc/test/nodes/split_by_llm.test.js.map +1 -1
- package/out-tsc/test/nodes/split_by_llm_categorize.test.js +101 -91
- package/out-tsc/test/nodes/split_by_llm_categorize.test.js.map +1 -1
- package/out-tsc/test/nodes/split_by_random.test.js +120 -112
- package/out-tsc/test/nodes/split_by_random.test.js.map +1 -1
- package/out-tsc/test/nodes/wait_for_digits.test.js +131 -111
- package/out-tsc/test/nodes/wait_for_digits.test.js.map +1 -1
- package/out-tsc/test/nodes/wait_for_response.test.js +549 -85
- package/out-tsc/test/nodes/wait_for_response.test.js.map +1 -1
- package/out-tsc/test/temba-checkbox.test.js +32 -32
- package/out-tsc/test/temba-checkbox.test.js.map +1 -1
- package/out-tsc/test/temba-contact-chat.test.js +2 -1
- package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
- package/out-tsc/test/temba-dropdown.test.js +0 -4
- package/out-tsc/test/temba-dropdown.test.js.map +1 -1
- package/out-tsc/test/temba-flow-editor-node.test.js +9 -4
- package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
- package/out-tsc/test/temba-integration-markdown.test.js +13 -15
- package/out-tsc/test/temba-integration-markdown.test.js.map +1 -1
- package/out-tsc/test/temba-node-editor.test.js +5 -38
- package/out-tsc/test/temba-node-editor.test.js.map +1 -1
- package/out-tsc/test/temba-run-list.test.js +2 -2
- package/out-tsc/test/temba-run-list.test.js.map +1 -1
- package/out-tsc/test/utils.test.js +2 -1
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +6 -2
- package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
- package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
- package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
- package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
- package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
- package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
- package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
- package/screenshots/truth/actions/send_email/render/complex-business-email.png +0 -0
- package/screenshots/truth/actions/send_email/render/empty-body.png +0 -0
- package/screenshots/truth/actions/send_email/render/empty-subject.png +0 -0
- package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
- package/screenshots/truth/actions/send_email/render/multiline-body.png +0 -0
- package/screenshots/truth/actions/send_email/render/multiple-recipients.png +0 -0
- package/screenshots/truth/actions/send_email/render/simple-email.png +0 -0
- package/screenshots/truth/actions/send_email/render/with-expressions.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-without-quick-replies.png +0 -0
- package/screenshots/truth/checkbox/checkbox-label-background-hover.png +0 -0
- package/screenshots/truth/checkbox/checkbox-whitespace-label-no-background-hover.png +0 -0
- package/screenshots/truth/checkbox/checkbox-with-help-text.png +0 -0
- package/screenshots/truth/checkbox/checked.png +0 -0
- package/screenshots/truth/checkbox/default.png +0 -0
- package/screenshots/truth/editor/wait.png +0 -0
- package/screenshots/truth/integration/textinput-markdown-errors.png +0 -0
- package/screenshots/truth/lightbox/img-zoomed.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/information-extraction.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/sentiment-analysis.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/summarization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/translation-task.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/summarization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/translation-task.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/basic-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/custom-input-and-result-name.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/many-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/minimal-categories.png +0 -0
- 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/split_by_random/render/ab-test-multiple-variants.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/sampling-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/three-way-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/two-bucket-split.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/verification-code.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.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/screenshots/truth/run-list/basic.png +0 -0
- package/screenshots/truth/templates/default.png +0 -0
- package/screenshots/truth/wait-for-response/rules-editor.png +0 -0
- package/screenshots/truth/wait-for-response/timeout-editor-unchecked.png +0 -0
- package/screenshots/truth/wait-for-response/timeout-editor.png +0 -0
- package/scripts/dev-data-sync.mjs +182 -0
- package/src/display/Chat.ts +6 -4
- package/src/events.ts +6 -5
- package/src/flow/CanvasNode.ts +89 -79
- package/src/flow/Editor.ts +1 -0
- package/src/flow/NodeEditor.ts +55 -3
- package/src/flow/actions/add_contact_groups.ts +16 -1
- package/src/flow/actions/add_contact_urn.ts +1 -1
- package/src/flow/actions/add_input_labels.ts +1 -0
- package/src/flow/actions/set_contact_channel.ts +1 -1
- package/src/flow/actions/set_contact_field.ts +2 -1
- package/src/flow/actions/set_contact_language.ts +3 -1
- package/src/flow/actions/set_contact_name.ts +1 -1
- package/src/flow/actions/set_contact_status.ts +18 -18
- package/src/flow/actions/set_run_result.ts +1 -1
- package/src/flow/nodes/split_by_llm.ts +14 -13
- package/src/flow/nodes/wait_for_response.ts +717 -5
- package/src/flow/operators.ts +215 -0
- package/src/flow/types.ts +10 -2
- package/src/form/ArrayEditor.ts +117 -37
- package/src/form/Checkbox.ts +12 -0
- package/src/form/FieldRenderer.ts +24 -3
- package/src/form/TextInput.ts +19 -1
- package/src/form/select/Select.ts +15 -4
- package/src/interfaces.ts +1 -1
- package/src/layout/Dialog.ts +4 -4
- package/src/list/RunList.ts +2 -2
- package/src/live/ContactChat.ts +144 -58
- package/src/live/ContactDetails.ts +7 -0
- package/src/live/ContactNameFetch.ts +1 -1
- package/static/api/labels.json +6 -1
- package/test/NodeHelper.ts +38 -40
- package/test/nodes/split_by_llm.test.ts +43 -32
- package/test/nodes/split_by_llm_categorize.test.ts +130 -120
- package/test/nodes/split_by_random.test.ts +136 -128
- package/test/nodes/wait_for_digits.test.ts +147 -127
- package/test/nodes/wait_for_response.test.ts +657 -104
- package/test/temba-checkbox.test.ts +36 -32
- package/test/temba-contact-chat.test.ts +2 -1
- package/test/temba-dropdown.test.ts +0 -12
- package/test/temba-flow-editor-node.test.ts +11 -4
- package/test/temba-integration-markdown.test.ts +16 -17
- package/test/temba-node-editor.test.ts +5 -43
- package/test/temba-run-list.test.ts +2 -2
- package/test/utils.test.ts +2 -1
- package/test-assets/list/runs.json +8 -8
- package/web-dev-mock.mjs +86 -30
- package/web-dev-server.config.mjs +272 -31
- package/screenshots/truth/dropdown/bottom-edge-collision.png +0 -0
- package/screenshots/truth/dropdown/right-edge-collision.png +0 -0
- package/screenshots/truth/editor/send_msg.png +0 -0
- package/screenshots/truth/editor/set_contact_language.png +0 -0
- package/screenshots/truth/editor/set_contact_name.png +0 -0
- package/screenshots/truth/editor/set_run_result.png +0 -0
- package/screenshots/truth/integration/checkbox-markdown-errors.png +0 -0
|
@@ -1,9 +1,328 @@
|
|
|
1
1
|
import { COLORS } from '../types';
|
|
2
|
+
import { generateUUID } from '../../utils';
|
|
3
|
+
import { getWaitForResponseOperators, operatorsToSelectOptions, getOperatorConfig } from '../operators';
|
|
4
|
+
const TIMEOUT_OPTIONS = [
|
|
5
|
+
{ value: '60', name: '1 minute' },
|
|
6
|
+
{ value: '120', name: '2 minutes' },
|
|
7
|
+
{ value: '180', name: '3 minutes' },
|
|
8
|
+
{ value: '240', name: '4 minutes' },
|
|
9
|
+
{ value: '300', name: '5 minutes' },
|
|
10
|
+
{ value: '600', name: '10 minutes' },
|
|
11
|
+
{ value: '900', name: '15 minutes' },
|
|
12
|
+
{ value: '1800', name: '30 minutes' },
|
|
13
|
+
{ value: '3600', name: '1 hour' },
|
|
14
|
+
{ value: '7200', name: '2 hours' },
|
|
15
|
+
{ value: '10800', name: '3 hours' },
|
|
16
|
+
{ value: '21600', name: '6 hours' },
|
|
17
|
+
{ value: '43200', name: '12 hours' },
|
|
18
|
+
{ value: '64800', name: '18 hours' },
|
|
19
|
+
{ value: '86400', name: '1 day' },
|
|
20
|
+
{ value: '172800', name: '2 days' },
|
|
21
|
+
{ value: '259200', name: '3 days' },
|
|
22
|
+
{ value: '604800', name: '1 week' }
|
|
23
|
+
];
|
|
24
|
+
// Helper function to create a wait_for_response router with user rules
|
|
25
|
+
const createWaitForResponseRouter = (userRules, existingCategories = [], existingExits = [], existingCases = []) => {
|
|
26
|
+
var _a;
|
|
27
|
+
const categories = [];
|
|
28
|
+
const exits = [];
|
|
29
|
+
const cases = [];
|
|
30
|
+
// Filter existing categories to get only user-defined rules (exclude system categories)
|
|
31
|
+
const existingUserCategories = existingCategories.filter((cat) => cat.name !== 'No Response' &&
|
|
32
|
+
cat.name !== 'Other' &&
|
|
33
|
+
cat.name !== 'Timeout');
|
|
34
|
+
// Group rules by category name (case-insensitive) to merge them
|
|
35
|
+
const rulesByCategory = new Map();
|
|
36
|
+
userRules.forEach((rule) => {
|
|
37
|
+
const categoryKey = rule.category.trim().toLowerCase();
|
|
38
|
+
if (!rulesByCategory.has(categoryKey)) {
|
|
39
|
+
rulesByCategory.set(categoryKey, []);
|
|
40
|
+
}
|
|
41
|
+
rulesByCategory.get(categoryKey).push(rule);
|
|
42
|
+
});
|
|
43
|
+
// Track category creation order to preserve UUID mapping
|
|
44
|
+
const categoryOrder = [];
|
|
45
|
+
userRules.forEach((rule) => {
|
|
46
|
+
const categoryKey = rule.category.trim().toLowerCase();
|
|
47
|
+
if (!categoryOrder.includes(categoryKey)) {
|
|
48
|
+
categoryOrder.push(categoryKey);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
// Create categories, exits, and cases for each unique category
|
|
52
|
+
categoryOrder.forEach((categoryKey, categoryIndex) => {
|
|
53
|
+
const rulesForCategory = rulesByCategory.get(categoryKey);
|
|
54
|
+
const categoryName = rulesForCategory[0].category.trim(); // Use the first occurrence's casing
|
|
55
|
+
// Try to find existing category by position/index to preserve UUIDs when names change
|
|
56
|
+
const existingCategory = existingUserCategories[categoryIndex];
|
|
57
|
+
const existingExit = existingCategory
|
|
58
|
+
? existingExits.find((exit) => exit.uuid === existingCategory.exit_uuid)
|
|
59
|
+
: null;
|
|
60
|
+
const exitUuid = (existingExit === null || existingExit === void 0 ? void 0 : existingExit.uuid) || generateUUID();
|
|
61
|
+
const categoryUuid = (existingCategory === null || existingCategory === void 0 ? void 0 : existingCategory.uuid) || generateUUID();
|
|
62
|
+
// Create single category for all rules with this category name
|
|
63
|
+
categories.push({
|
|
64
|
+
uuid: categoryUuid,
|
|
65
|
+
name: categoryName,
|
|
66
|
+
exit_uuid: exitUuid
|
|
67
|
+
});
|
|
68
|
+
exits.push({
|
|
69
|
+
uuid: exitUuid,
|
|
70
|
+
destination_uuid: (existingExit === null || existingExit === void 0 ? void 0 : existingExit.destination_uuid) || null
|
|
71
|
+
});
|
|
72
|
+
// Create a case for each rule in this category
|
|
73
|
+
rulesForCategory.forEach((rule) => {
|
|
74
|
+
// Try to find existing case for this rule by looking at the original rule order
|
|
75
|
+
const originalRuleIndex = userRules.findIndex((r) => r === rule);
|
|
76
|
+
const existingCase = existingCases[originalRuleIndex];
|
|
77
|
+
const caseUuid = (existingCase === null || existingCase === void 0 ? void 0 : existingCase.uuid) || generateUUID();
|
|
78
|
+
// Parse rule value based on operator configuration
|
|
79
|
+
const operatorConfig = getOperatorConfig(rule.operator);
|
|
80
|
+
let arguments_ = [];
|
|
81
|
+
if (operatorConfig) {
|
|
82
|
+
if (operatorConfig.operands === 0) {
|
|
83
|
+
// No operands needed
|
|
84
|
+
arguments_ = [];
|
|
85
|
+
}
|
|
86
|
+
else if (operatorConfig.operands === 2) {
|
|
87
|
+
// Split value for two operands (e.g., "1 10" for between)
|
|
88
|
+
arguments_ = rule.value
|
|
89
|
+
.split(' ')
|
|
90
|
+
.filter((arg) => arg.trim());
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// Single operand - but split words for operators that expect multiple words
|
|
94
|
+
if (rule.value && rule.value.trim()) {
|
|
95
|
+
// Split on spaces and filter out empty strings
|
|
96
|
+
arguments_ = rule.value
|
|
97
|
+
.trim()
|
|
98
|
+
.split(/\s+/)
|
|
99
|
+
.filter((arg) => arg.length > 0);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
arguments_ = [];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// Fallback for unknown operators - split on spaces if value exists
|
|
108
|
+
if (rule.value && rule.value.trim()) {
|
|
109
|
+
arguments_ = rule.value
|
|
110
|
+
.trim()
|
|
111
|
+
.split(/\s+/)
|
|
112
|
+
.filter((arg) => arg.length > 0);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
arguments_ = [];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
cases.push({
|
|
119
|
+
uuid: caseUuid,
|
|
120
|
+
type: rule.operator,
|
|
121
|
+
arguments: arguments_,
|
|
122
|
+
category_uuid: categoryUuid
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
// Preserve existing timeout categories like "No Response"
|
|
127
|
+
existingCategories.forEach((category) => {
|
|
128
|
+
if (category.name === 'No Response' || category.name === 'Timeout') {
|
|
129
|
+
const existingExit = existingExits.find((exit) => exit.uuid === category.exit_uuid);
|
|
130
|
+
if (existingExit) {
|
|
131
|
+
categories.push(category);
|
|
132
|
+
exits.push(existingExit);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
// Add "Other" category (default) only if there are user rules
|
|
137
|
+
if (userRules.length > 0) {
|
|
138
|
+
const existingOtherCategory = existingCategories.find((cat) => cat.name === 'Other');
|
|
139
|
+
const existingOtherExit = existingOtherCategory
|
|
140
|
+
? existingExits.find((exit) => exit.uuid === existingOtherCategory.exit_uuid)
|
|
141
|
+
: null;
|
|
142
|
+
const otherExitUuid = (existingOtherExit === null || existingOtherExit === void 0 ? void 0 : existingOtherExit.uuid) || generateUUID();
|
|
143
|
+
const otherCategoryUuid = (existingOtherCategory === null || existingOtherCategory === void 0 ? void 0 : existingOtherCategory.uuid) || generateUUID();
|
|
144
|
+
categories.push({
|
|
145
|
+
uuid: otherCategoryUuid,
|
|
146
|
+
name: 'Other',
|
|
147
|
+
exit_uuid: otherExitUuid
|
|
148
|
+
});
|
|
149
|
+
exits.push({
|
|
150
|
+
uuid: otherExitUuid,
|
|
151
|
+
destination_uuid: (existingOtherExit === null || existingOtherExit === void 0 ? void 0 : existingOtherExit.destination_uuid) || null
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
router: {
|
|
156
|
+
type: 'switch',
|
|
157
|
+
categories: categories,
|
|
158
|
+
default_category_uuid: (_a = categories.find((cat) => cat.name === 'Other')) === null || _a === void 0 ? void 0 : _a.uuid,
|
|
159
|
+
operand: '@input.text',
|
|
160
|
+
cases: cases
|
|
161
|
+
},
|
|
162
|
+
exits: exits
|
|
163
|
+
};
|
|
164
|
+
};
|
|
2
165
|
export const wait_for_response = {
|
|
3
166
|
type: 'wait_for_response',
|
|
4
167
|
name: 'Wait for Response',
|
|
5
168
|
color: COLORS.wait,
|
|
169
|
+
dialogSize: 'large',
|
|
6
170
|
form: {
|
|
171
|
+
rules: {
|
|
172
|
+
type: 'array',
|
|
173
|
+
helpText: 'Define rules to categorize responses',
|
|
174
|
+
itemLabel: 'Rule',
|
|
175
|
+
minItems: 0,
|
|
176
|
+
maxItems: 100,
|
|
177
|
+
maintainEmptyItem: true, // Explicitly enable empty item maintenance
|
|
178
|
+
isEmptyItem: (item) => {
|
|
179
|
+
// Helper function to get operator value from various formats
|
|
180
|
+
const getOperatorValue = (operator) => {
|
|
181
|
+
if (typeof operator === 'string') {
|
|
182
|
+
return operator.trim();
|
|
183
|
+
}
|
|
184
|
+
else if (Array.isArray(operator) && operator.length > 0) {
|
|
185
|
+
// Handle array format: [{value: "has_any_word", name: "..."}]
|
|
186
|
+
const firstOperator = operator[0];
|
|
187
|
+
if (firstOperator &&
|
|
188
|
+
typeof firstOperator === 'object' &&
|
|
189
|
+
firstOperator.value) {
|
|
190
|
+
return firstOperator.value.trim();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
else if (operator &&
|
|
194
|
+
typeof operator === 'object' &&
|
|
195
|
+
operator.value) {
|
|
196
|
+
// Handle object format: {value: "has_any_word", name: "..."}
|
|
197
|
+
return operator.value.trim();
|
|
198
|
+
}
|
|
199
|
+
return '';
|
|
200
|
+
};
|
|
201
|
+
// Check if operator and category are provided
|
|
202
|
+
const operatorValue = getOperatorValue(item.operator);
|
|
203
|
+
if (!operatorValue || !item.category || item.category.trim() === '') {
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
// Check if value is required based on operator configuration
|
|
207
|
+
const operatorConfig = getOperatorConfig(operatorValue);
|
|
208
|
+
if (operatorConfig && operatorConfig.operands === 1) {
|
|
209
|
+
// value1 is required for this operator
|
|
210
|
+
return !item.value1 || item.value1.trim() === '';
|
|
211
|
+
}
|
|
212
|
+
else if (operatorConfig && operatorConfig.operands === 2) {
|
|
213
|
+
// Both value1 and value2 are required for this operator
|
|
214
|
+
return (!item.value1 ||
|
|
215
|
+
item.value1.trim() === '' ||
|
|
216
|
+
!item.value2 ||
|
|
217
|
+
item.value2.trim() === '');
|
|
218
|
+
}
|
|
219
|
+
// No value required for this operator
|
|
220
|
+
return false;
|
|
221
|
+
},
|
|
222
|
+
itemConfig: {
|
|
223
|
+
operator: {
|
|
224
|
+
type: 'select',
|
|
225
|
+
required: true,
|
|
226
|
+
multi: false, // Explicitly set as single-select
|
|
227
|
+
options: operatorsToSelectOptions(getWaitForResponseOperators()),
|
|
228
|
+
flavor: 'xsmall',
|
|
229
|
+
width: '200px'
|
|
230
|
+
},
|
|
231
|
+
value1: {
|
|
232
|
+
type: 'text',
|
|
233
|
+
flavor: 'xsmall',
|
|
234
|
+
conditions: {
|
|
235
|
+
visible: (formData) => {
|
|
236
|
+
// Helper function to get operator value from various formats
|
|
237
|
+
const getOperatorValue = (operator) => {
|
|
238
|
+
if (typeof operator === 'string') {
|
|
239
|
+
return operator.trim();
|
|
240
|
+
}
|
|
241
|
+
else if (Array.isArray(operator) && operator.length > 0) {
|
|
242
|
+
const firstOperator = operator[0];
|
|
243
|
+
if (firstOperator &&
|
|
244
|
+
typeof firstOperator === 'object' &&
|
|
245
|
+
firstOperator.value) {
|
|
246
|
+
return firstOperator.value.trim();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else if (operator &&
|
|
250
|
+
typeof operator === 'object' &&
|
|
251
|
+
operator.value) {
|
|
252
|
+
return operator.value.trim();
|
|
253
|
+
}
|
|
254
|
+
return '';
|
|
255
|
+
};
|
|
256
|
+
// Show value1 field for operators that require 1 or 2 operands
|
|
257
|
+
const operatorValue = getOperatorValue(formData.operator);
|
|
258
|
+
const operatorConfig = getOperatorConfig(operatorValue);
|
|
259
|
+
return operatorConfig ? operatorConfig.operands >= 1 : true;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
value2: {
|
|
264
|
+
type: 'text',
|
|
265
|
+
flavor: 'xsmall',
|
|
266
|
+
conditions: {
|
|
267
|
+
visible: (formData) => {
|
|
268
|
+
// Helper function to get operator value from various formats
|
|
269
|
+
const getOperatorValue = (operator) => {
|
|
270
|
+
if (typeof operator === 'string') {
|
|
271
|
+
return operator.trim();
|
|
272
|
+
}
|
|
273
|
+
else if (Array.isArray(operator) && operator.length > 0) {
|
|
274
|
+
const firstOperator = operator[0];
|
|
275
|
+
if (firstOperator &&
|
|
276
|
+
typeof firstOperator === 'object' &&
|
|
277
|
+
firstOperator.value) {
|
|
278
|
+
return firstOperator.value.trim();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
else if (operator &&
|
|
282
|
+
typeof operator === 'object' &&
|
|
283
|
+
operator.value) {
|
|
284
|
+
return operator.value.trim();
|
|
285
|
+
}
|
|
286
|
+
return '';
|
|
287
|
+
};
|
|
288
|
+
// Show value2 field only if operator requires exactly 2 operands
|
|
289
|
+
const operatorValue = getOperatorValue(formData.operator);
|
|
290
|
+
const operatorConfig = getOperatorConfig(operatorValue);
|
|
291
|
+
return operatorConfig ? operatorConfig.operands === 2 : false;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
category: {
|
|
296
|
+
type: 'text',
|
|
297
|
+
placeholder: 'Category',
|
|
298
|
+
required: true,
|
|
299
|
+
maxWidth: '120px',
|
|
300
|
+
flavor: 'xsmall'
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
timeout_enabled: {
|
|
305
|
+
type: 'checkbox',
|
|
306
|
+
label: (formData) => {
|
|
307
|
+
return formData.timeout_enabled
|
|
308
|
+
? 'Continue when there is no response for'
|
|
309
|
+
: 'Continue when there is no response..';
|
|
310
|
+
},
|
|
311
|
+
labelPadding: '4px 8px'
|
|
312
|
+
},
|
|
313
|
+
timeout_duration: {
|
|
314
|
+
type: 'select',
|
|
315
|
+
placeholder: '5 minutes',
|
|
316
|
+
multi: false,
|
|
317
|
+
maxWidth: '150px',
|
|
318
|
+
flavor: 'xsmall',
|
|
319
|
+
options: TIMEOUT_OPTIONS,
|
|
320
|
+
conditions: {
|
|
321
|
+
visible: (formData) => {
|
|
322
|
+
return formData.timeout_enabled === true;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
},
|
|
7
326
|
result_name: {
|
|
8
327
|
type: 'text',
|
|
9
328
|
label: 'Result Name',
|
|
@@ -11,22 +330,306 @@ export const wait_for_response = {
|
|
|
11
330
|
placeholder: 'response'
|
|
12
331
|
}
|
|
13
332
|
},
|
|
14
|
-
layout: ['
|
|
333
|
+
layout: ['rules', 'result_name'],
|
|
334
|
+
gutter: [
|
|
335
|
+
{
|
|
336
|
+
type: 'row',
|
|
337
|
+
items: ['timeout_enabled', 'timeout_duration'],
|
|
338
|
+
gap: '0.5rem'
|
|
339
|
+
}
|
|
340
|
+
],
|
|
341
|
+
validate: (_formData) => {
|
|
342
|
+
const errors = {};
|
|
343
|
+
// No validation needed - allow multiple rules to use same category name
|
|
344
|
+
// Rules with the same category name will be merged to use the same exit
|
|
345
|
+
return {
|
|
346
|
+
valid: Object.keys(errors).length === 0,
|
|
347
|
+
errors
|
|
348
|
+
};
|
|
349
|
+
},
|
|
15
350
|
toFormData: (node) => {
|
|
16
|
-
var _a;
|
|
351
|
+
var _a, _b, _c, _d, _e, _f;
|
|
352
|
+
// Extract rules from router cases
|
|
353
|
+
const rules = [];
|
|
354
|
+
if (((_a = node.router) === null || _a === void 0 ? void 0 : _a.cases) && ((_b = node.router) === null || _b === void 0 ? void 0 : _b.categories)) {
|
|
355
|
+
node.router.cases.forEach((case_) => {
|
|
356
|
+
// Find the category for this case
|
|
357
|
+
const category = node.router.categories.find((cat) => cat.uuid === case_.category_uuid);
|
|
358
|
+
// Skip timeout/system categories like "No Response"
|
|
359
|
+
if (category &&
|
|
360
|
+
category.name !== 'No Response' &&
|
|
361
|
+
category.name !== 'Other') {
|
|
362
|
+
// Handle different operator types
|
|
363
|
+
const operatorConfig = getOperatorConfig(case_.type);
|
|
364
|
+
const operatorDisplayName = operatorConfig
|
|
365
|
+
? operatorConfig.name
|
|
366
|
+
: case_.type;
|
|
367
|
+
let value1 = '';
|
|
368
|
+
let value2 = '';
|
|
369
|
+
if (operatorConfig && operatorConfig.operands === 0) {
|
|
370
|
+
// No value needed for operators like has_text, has_number
|
|
371
|
+
value1 = '';
|
|
372
|
+
value2 = '';
|
|
373
|
+
}
|
|
374
|
+
else if (operatorConfig && operatorConfig.operands === 1) {
|
|
375
|
+
// Single value for operators like has_number_lt - use value1
|
|
376
|
+
value1 = case_.arguments.join(' ');
|
|
377
|
+
value2 = '';
|
|
378
|
+
}
|
|
379
|
+
else if (operatorConfig && operatorConfig.operands === 2) {
|
|
380
|
+
// Two separate values for operators like has_number_between
|
|
381
|
+
value1 = case_.arguments[0] || '';
|
|
382
|
+
value2 = case_.arguments[1] || '';
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
// Fallback: use first argument for unknown operators
|
|
386
|
+
value1 = case_.arguments.join(' ');
|
|
387
|
+
value2 = '';
|
|
388
|
+
}
|
|
389
|
+
rules.push({
|
|
390
|
+
operator: { value: case_.type, name: operatorDisplayName },
|
|
391
|
+
value1: value1,
|
|
392
|
+
value2: value2,
|
|
393
|
+
category: category.name
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
// Extract timeout configuration
|
|
399
|
+
const timeoutSeconds = (_e = (_d = (_c = node.router) === null || _c === void 0 ? void 0 : _c.wait) === null || _d === void 0 ? void 0 : _d.timeout) === null || _e === void 0 ? void 0 : _e.seconds;
|
|
400
|
+
let timeoutOption = TIMEOUT_OPTIONS.find((opt) => opt.value === String(timeoutSeconds));
|
|
401
|
+
if (!timeoutOption) {
|
|
402
|
+
timeoutOption = { value: '300', name: '5 minutes' };
|
|
403
|
+
}
|
|
17
404
|
return {
|
|
18
405
|
uuid: node.uuid,
|
|
19
|
-
|
|
406
|
+
rules: rules,
|
|
407
|
+
timeout_enabled: !!timeoutSeconds,
|
|
408
|
+
timeout_duration: timeoutOption,
|
|
409
|
+
result_name: ((_f = node.router) === null || _f === void 0 ? void 0 : _f.result_name) || 'response'
|
|
20
410
|
};
|
|
21
411
|
},
|
|
22
412
|
fromFormData: (formData, originalNode) => {
|
|
23
|
-
|
|
24
|
-
|
|
413
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
414
|
+
// Helper function to get operator value from various formats
|
|
415
|
+
const getOperatorValue = (operator) => {
|
|
416
|
+
if (typeof operator === 'string') {
|
|
417
|
+
return operator.trim();
|
|
418
|
+
}
|
|
419
|
+
else if (Array.isArray(operator) && operator.length > 0) {
|
|
420
|
+
// Handle array format: [{value: "has_any_word", name: "..."}]
|
|
421
|
+
const firstOperator = operator[0];
|
|
422
|
+
if (firstOperator &&
|
|
423
|
+
typeof firstOperator === 'object' &&
|
|
424
|
+
firstOperator.value) {
|
|
425
|
+
return firstOperator.value.trim();
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
else if (operator && typeof operator === 'object' && operator.value) {
|
|
429
|
+
// Handle object format: {value: "has_any_word", name: "..."}
|
|
430
|
+
return operator.value.trim();
|
|
431
|
+
}
|
|
432
|
+
return '';
|
|
433
|
+
};
|
|
434
|
+
// Get user rules
|
|
435
|
+
const userRules = (formData.rules || [])
|
|
436
|
+
.filter((rule) => {
|
|
437
|
+
// Always need operator and category
|
|
438
|
+
const operatorValue = getOperatorValue(rule === null || rule === void 0 ? void 0 : rule.operator);
|
|
439
|
+
if (!operatorValue ||
|
|
440
|
+
!(rule === null || rule === void 0 ? void 0 : rule.category) ||
|
|
441
|
+
operatorValue === '' ||
|
|
442
|
+
rule.category.trim() === '') {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
// Check if value is required based on operator
|
|
446
|
+
const operatorConfig = getOperatorConfig(operatorValue);
|
|
447
|
+
if (operatorConfig && operatorConfig.operands === 1) {
|
|
448
|
+
// value1 is required for this operator
|
|
449
|
+
return (rule === null || rule === void 0 ? void 0 : rule.value1) && rule.value1.trim() !== '';
|
|
450
|
+
}
|
|
451
|
+
else if (operatorConfig && operatorConfig.operands === 2) {
|
|
452
|
+
// Both value1 and value2 are required for this operator
|
|
453
|
+
return ((rule === null || rule === void 0 ? void 0 : rule.value1) &&
|
|
454
|
+
rule.value1.trim() !== '' &&
|
|
455
|
+
(rule === null || rule === void 0 ? void 0 : rule.value2) &&
|
|
456
|
+
rule.value2.trim() !== '');
|
|
457
|
+
}
|
|
458
|
+
// No value required for this operator
|
|
459
|
+
return true;
|
|
460
|
+
})
|
|
461
|
+
.map((rule) => {
|
|
462
|
+
const operatorValue = getOperatorValue(rule.operator);
|
|
463
|
+
const operatorConfig = getOperatorConfig(operatorValue);
|
|
464
|
+
let value = '';
|
|
465
|
+
if (operatorConfig && operatorConfig.operands === 1) {
|
|
466
|
+
// Single value from value1
|
|
467
|
+
value = rule.value1 ? rule.value1.trim() : '';
|
|
468
|
+
}
|
|
469
|
+
else if (operatorConfig && operatorConfig.operands === 2) {
|
|
470
|
+
// Two values - combine them with space
|
|
471
|
+
const val1 = rule.value1 ? rule.value1.trim() : '';
|
|
472
|
+
const val2 = rule.value2 ? rule.value2.trim() : '';
|
|
473
|
+
value = `${val1} ${val2}`.trim();
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
// No value needed for 0-operand operators
|
|
477
|
+
value = '';
|
|
478
|
+
}
|
|
479
|
+
return {
|
|
480
|
+
operator: operatorValue,
|
|
481
|
+
value: value,
|
|
482
|
+
category: rule.category.trim()
|
|
483
|
+
};
|
|
484
|
+
});
|
|
485
|
+
// If no user rules, clear cases but preserve other router config
|
|
486
|
+
if (userRules.length === 0) {
|
|
487
|
+
const router = {
|
|
488
|
+
...originalNode.router,
|
|
489
|
+
result_name: formData.result_name || 'response'
|
|
490
|
+
};
|
|
491
|
+
// Only set cases to empty if the original node had cases
|
|
492
|
+
if (((_a = originalNode.router) === null || _a === void 0 ? void 0 : _a.cases) !== undefined) {
|
|
493
|
+
router.cases = []; // Clear all cases when no rules
|
|
494
|
+
}
|
|
495
|
+
// Build wait configuration based on form data
|
|
496
|
+
const waitConfig = {
|
|
497
|
+
type: 'msg'
|
|
498
|
+
};
|
|
499
|
+
// Add timeout if enabled
|
|
500
|
+
if (formData.timeout_enabled) {
|
|
501
|
+
// Extract timeout value (handle both string and object formats)
|
|
502
|
+
let timeoutSeconds;
|
|
503
|
+
if (formData.timeout_duration) {
|
|
504
|
+
if (Array.isArray(formData.timeout_duration) &&
|
|
505
|
+
formData.timeout_duration.length > 0) {
|
|
506
|
+
// Handle array of selected options (multi-select behavior)
|
|
507
|
+
timeoutSeconds = parseInt(formData.timeout_duration[0].value, 10);
|
|
508
|
+
}
|
|
509
|
+
else if (typeof formData.timeout_duration === 'string') {
|
|
510
|
+
timeoutSeconds = parseInt(formData.timeout_duration, 10);
|
|
511
|
+
}
|
|
512
|
+
else if (formData.timeout_duration &&
|
|
513
|
+
typeof formData.timeout_duration === 'object' &&
|
|
514
|
+
formData.timeout_duration.value) {
|
|
515
|
+
timeoutSeconds = parseInt(formData.timeout_duration.value, 10);
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
timeoutSeconds = 300; // Default to 5 minutes
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
// No duration selected, use default
|
|
523
|
+
timeoutSeconds = 300; // Default to 5 minutes
|
|
524
|
+
}
|
|
525
|
+
// Validate that we got a valid number
|
|
526
|
+
if (isNaN(timeoutSeconds) || timeoutSeconds <= 0) {
|
|
527
|
+
timeoutSeconds = 300; // Default to 5 minutes
|
|
528
|
+
}
|
|
529
|
+
// Find or create the "No Response" category
|
|
530
|
+
let noResponseCategory = (_c = (_b = originalNode.router) === null || _b === void 0 ? void 0 : _b.categories) === null || _c === void 0 ? void 0 : _c.find((cat) => cat.name === 'No Response');
|
|
531
|
+
if (!noResponseCategory) {
|
|
532
|
+
noResponseCategory = {
|
|
533
|
+
uuid: generateUUID(),
|
|
534
|
+
name: 'No Response',
|
|
535
|
+
exit_uuid: generateUUID()
|
|
536
|
+
};
|
|
537
|
+
// Add to router categories
|
|
538
|
+
router.categories = router.categories || [];
|
|
539
|
+
router.categories.push(noResponseCategory);
|
|
540
|
+
}
|
|
541
|
+
waitConfig.timeout = {
|
|
542
|
+
seconds: timeoutSeconds,
|
|
543
|
+
category_uuid: noResponseCategory.uuid
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
router.wait = waitConfig;
|
|
547
|
+
return {
|
|
548
|
+
...originalNode,
|
|
549
|
+
router
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
// Get existing router data for preservation
|
|
553
|
+
const existingCategories = ((_d = originalNode.router) === null || _d === void 0 ? void 0 : _d.categories) || [];
|
|
554
|
+
const existingExits = originalNode.exits || [];
|
|
555
|
+
const existingCases = ((_e = originalNode.router) === null || _e === void 0 ? void 0 : _e.cases) || [];
|
|
556
|
+
// Create router and exits using existing data when possible
|
|
557
|
+
const { router, exits } = createWaitForResponseRouter(userRules, existingCategories, existingExits, existingCases);
|
|
558
|
+
// Build final router with wait configuration and result_name
|
|
559
|
+
const finalRouter = {
|
|
560
|
+
...router,
|
|
25
561
|
result_name: formData.result_name || 'response'
|
|
26
562
|
};
|
|
563
|
+
// Build wait configuration based on form data
|
|
564
|
+
const waitConfig = {
|
|
565
|
+
type: 'msg'
|
|
566
|
+
};
|
|
567
|
+
try {
|
|
568
|
+
// Handle timeout configuration
|
|
569
|
+
if (formData.timeout_enabled) {
|
|
570
|
+
// Extract timeout value (handle both string and object formats)
|
|
571
|
+
let timeoutSeconds;
|
|
572
|
+
if (formData.timeout_duration) {
|
|
573
|
+
try {
|
|
574
|
+
timeoutSeconds = parseInt(formData.timeout_duration[0].value, 10);
|
|
575
|
+
}
|
|
576
|
+
catch (e) {
|
|
577
|
+
timeoutSeconds = 300; // Default to 5 minutes
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
// Find or create the "No Response" category
|
|
581
|
+
const existingNoResponseCategory = (_g = (_f = originalNode.router) === null || _f === void 0 ? void 0 : _f.categories) === null || _g === void 0 ? void 0 : _g.find((cat) => cat.name === 'No Response');
|
|
582
|
+
const noResponseCategory = existingNoResponseCategory || {
|
|
583
|
+
uuid: generateUUID(),
|
|
584
|
+
name: 'No Response',
|
|
585
|
+
exit_uuid: generateUUID()
|
|
586
|
+
};
|
|
587
|
+
waitConfig.timeout = {
|
|
588
|
+
seconds: timeoutSeconds,
|
|
589
|
+
category_uuid: noResponseCategory.uuid
|
|
590
|
+
};
|
|
591
|
+
// Ensure No Response category and exit exist
|
|
592
|
+
if (!((_h = router.categories) === null || _h === void 0 ? void 0 : _h.some((cat) => cat.name === 'No Response'))) {
|
|
593
|
+
router.categories = router.categories || [];
|
|
594
|
+
router.categories.push(noResponseCategory);
|
|
595
|
+
// Add corresponding exit if it doesn't exist
|
|
596
|
+
if (!exits.some((exit) => exit.uuid === noResponseCategory.exit_uuid)) {
|
|
597
|
+
const noResponseExit = {
|
|
598
|
+
uuid: noResponseCategory.exit_uuid,
|
|
599
|
+
destination_uuid: (existingNoResponseCategory === null || existingNoResponseCategory === void 0 ? void 0 : existingNoResponseCategory.exit_uuid)
|
|
600
|
+
? ((_k = (_j = originalNode.exits) === null || _j === void 0 ? void 0 : _j.find((exit) => exit.uuid === existingNoResponseCategory.exit_uuid)) === null || _k === void 0 ? void 0 : _k.destination_uuid) || null
|
|
601
|
+
: null
|
|
602
|
+
};
|
|
603
|
+
exits.push(noResponseExit);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
else {
|
|
608
|
+
// Remove "No Response" category if timeout is disabled
|
|
609
|
+
if (router.categories) {
|
|
610
|
+
const noResponseCategoryIndex = router.categories.findIndex((cat) => cat.name === 'No Response');
|
|
611
|
+
if (noResponseCategoryIndex !== -1) {
|
|
612
|
+
const noResponseCategory = router.categories[noResponseCategoryIndex];
|
|
613
|
+
// Remove the category
|
|
614
|
+
router.categories.splice(noResponseCategoryIndex, 1);
|
|
615
|
+
// Remove corresponding exit
|
|
616
|
+
const exitIndex = exits.findIndex((exit) => exit.uuid === noResponseCategory.exit_uuid);
|
|
617
|
+
if (exitIndex !== -1) {
|
|
618
|
+
exits.splice(exitIndex, 1);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
catch (error) {
|
|
625
|
+
console.error('Error processing timeout configuration:', error);
|
|
626
|
+
// Continue without timeout in case of error
|
|
627
|
+
}
|
|
628
|
+
finalRouter.wait = waitConfig;
|
|
27
629
|
return {
|
|
28
630
|
...originalNode,
|
|
29
|
-
router
|
|
631
|
+
router: finalRouter,
|
|
632
|
+
exits: exits
|
|
30
633
|
};
|
|
31
634
|
}
|
|
32
635
|
};
|