@nyaruka/temba-components 0.142.1 → 0.142.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 +11 -0
- package/dist/temba-components.js +825 -654
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/Icons.js +1 -0
- package/out-tsc/src/Icons.js.map +1 -1
- package/out-tsc/src/flow/CanvasMenu.js +30 -35
- package/out-tsc/src/flow/CanvasMenu.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +13 -8
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +18 -5
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +346 -10
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/NodeTypeSelector.js +2 -0
- package/out-tsc/src/flow/NodeTypeSelector.js.map +1 -1
- package/out-tsc/src/flow/Plumber.js +3 -1
- package/out-tsc/src/flow/Plumber.js.map +1 -1
- package/out-tsc/src/flow/actions/add_contact_urn.js +2 -6
- package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -1
- package/out-tsc/src/flow/actions/enter_flow.js +2 -2
- package/out-tsc/src/flow/actions/enter_flow.js.map +1 -1
- package/out-tsc/src/flow/actions/say_msg.js +2 -1
- package/out-tsc/src/flow/actions/say_msg.js.map +1 -1
- package/out-tsc/src/flow/actions/send_broadcast.js +2 -6
- package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -1
- package/out-tsc/src/flow/actions/send_email.js +2 -6
- package/out-tsc/src/flow/actions/send_email.js.map +1 -1
- package/out-tsc/src/flow/actions/send_msg.js +52 -35
- package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_field.js +4 -5
- package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_language.js +3 -3
- package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_name.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_status.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
- package/out-tsc/src/flow/actions/set_run_result.js +3 -3
- package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
- package/out-tsc/src/flow/actions/start_session.js +2 -2
- package/out-tsc/src/flow/actions/start_session.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm.js +4 -5
- package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_resthook.js +3 -8
- package/out-tsc/src/flow/nodes/split_by_resthook.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_subflow.js +2 -2
- package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_webhook.js +25 -33
- package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js +1 -0
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
- package/out-tsc/src/flow/types.js.map +1 -1
- package/out-tsc/src/flow/utils.js +68 -0
- package/out-tsc/src/flow/utils.js.map +1 -1
- package/out-tsc/src/form/FieldRenderer.js +17 -2
- package/out-tsc/src/form/FieldRenderer.js.map +1 -1
- package/out-tsc/src/interfaces.js +1 -0
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/simulator/Simulator.js +1 -1
- package/out-tsc/src/simulator/Simulator.js.map +1 -1
- package/out-tsc/test/temba-canvas-menu.test.js +13 -9
- package/out-tsc/test/temba-canvas-menu.test.js.map +1 -1
- package/out-tsc/test/temba-flow-reflow.test.js.map +1 -1
- package/out-tsc/test/temba-node-editor.test.js +9 -10
- package/out-tsc/test/temba-node-editor.test.js.map +1 -1
- package/out-tsc/test/temba-node-type-selector.test.js +3 -3
- package/out-tsc/test/temba-node-type-selector.test.js.map +1 -1
- package/out-tsc/test/temba-simulator.test.js +2 -2
- package/out-tsc/test/temba-simulator.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/actions/enter_flow/render/basic-flow.png +0 -0
- package/screenshots/truth/actions/enter_flow/render/long-flow-name.png +0 -0
- package/screenshots/truth/actions/send_email/render/long-subject.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/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/start_session/render/contact-query.png +0 -0
- package/screenshots/truth/actions/start_session/render/contacts-only.png +0 -0
- package/screenshots/truth/actions/start_session/render/create-contact.png +0 -0
- package/screenshots/truth/actions/start_session/render/groups-and-contacts.png +0 -0
- package/screenshots/truth/actions/start_session/render/groups-only.png +0 -0
- package/screenshots/truth/actions/start_session/render/many-recipients.png +0 -0
- package/screenshots/truth/canvas-menu/open.png +0 -0
- package/screenshots/truth/node-type-selector/action-mode.png +0 -0
- package/screenshots/truth/node-type-selector/split-mode.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_categorize/editor/feedback-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
- package/src/Icons.ts +1 -0
- package/src/flow/CanvasMenu.ts +38 -39
- package/src/flow/CanvasNode.ts +16 -8
- package/src/flow/Editor.ts +33 -6
- package/src/flow/NodeEditor.ts +373 -10
- package/src/flow/NodeTypeSelector.ts +2 -0
- package/src/flow/Plumber.ts +3 -1
- package/src/flow/actions/add_contact_urn.ts +5 -6
- package/src/flow/actions/enter_flow.ts +2 -2
- package/src/flow/actions/say_msg.ts +2 -1
- package/src/flow/actions/send_broadcast.ts +2 -6
- package/src/flow/actions/send_email.ts +2 -6
- package/src/flow/actions/send_msg.ts +56 -38
- package/src/flow/actions/set_contact_channel.ts +5 -1
- package/src/flow/actions/set_contact_field.ts +10 -5
- package/src/flow/actions/set_contact_language.ts +6 -3
- package/src/flow/actions/set_contact_name.ts +5 -1
- package/src/flow/actions/set_contact_status.ts +5 -1
- package/src/flow/actions/set_run_result.ts +6 -3
- package/src/flow/actions/start_session.ts +2 -2
- package/src/flow/nodes/split_by_llm.ts +5 -5
- package/src/flow/nodes/split_by_resthook.ts +3 -8
- package/src/flow/nodes/split_by_subflow.ts +2 -2
- package/src/flow/nodes/split_by_webhook.ts +26 -34
- package/src/flow/nodes/wait_for_response.ts +1 -0
- package/src/flow/types.ts +25 -2
- package/src/flow/utils.ts +81 -1
- package/src/form/FieldRenderer.ts +32 -3
- package/src/interfaces.ts +1 -0
- package/src/simulator/Simulator.ts +1 -1
- package/test/temba-canvas-menu.test.ts +13 -9
- package/test/temba-flow-reflow.test.ts +4 -2
- package/test/temba-node-editor.test.ts +9 -10
- package/test/temba-node-type-selector.test.ts +3 -3
- package/test/temba-simulator.test.ts +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wait_for_response.js","sourceRoot":"","sources":["../../../../src/flow/nodes/wait_for_response.ts"],"names":[],"mappings":"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","sourcesContent":["import { SPLIT_GROUPS, FormData, NodeConfig, FlowTypes } from '../types';\nimport { Node, Category, Exit, Case } from '../../store/flow-definition';\nimport { generateUUID, createRulesRouter } from '../../utils';\nimport {\n getWaitForResponseOperators,\n operatorsToSelectOptions,\n getOperatorConfig\n} from '../operators';\nimport {\n resultNameField,\n categoriesToLocalizationFormData,\n localizationFormDataToCategories\n} from './shared';\nimport {\n createRulesArrayConfig,\n extractUserRules,\n casesToFormRules\n} from './shared-rules';\n\nconst TIMEOUT_OPTIONS = [\n { value: '60', name: '1 minute' },\n { value: '120', name: '2 minutes' },\n { value: '180', name: '3 minutes' },\n { value: '240', name: '4 minutes' },\n { value: '300', name: '5 minutes' },\n { value: '600', name: '10 minutes' },\n { value: '900', name: '15 minutes' },\n { value: '1800', name: '30 minutes' },\n { value: '3600', name: '1 hour' },\n { value: '7200', name: '2 hours' },\n { value: '10800', name: '3 hours' },\n { value: '21600', name: '6 hours' },\n { value: '43200', name: '12 hours' },\n { value: '64800', name: '18 hours' },\n { value: '86400', name: '1 day' },\n { value: '172800', name: '2 days' },\n { value: '259200', name: '3 days' },\n { value: '604800', name: '1 week' }\n];\n\n// Helper function to create a wait_for_response router with user rules\n// This is a thin wrapper around createRulesRouter that adds the No Response category for timeouts\nconst createWaitForResponseRouter = (\n userRules: any[],\n existingCategories: Category[] = [],\n existingExits: Exit[] = [],\n existingCases: Case[] = []\n) => {\n const { router, exits } = createRulesRouter(\n '@input.text',\n userRules,\n getOperatorConfig,\n existingCategories,\n existingExits,\n existingCases\n );\n\n // Add \"No Response\" category last (if it exists in the original)\n const existingNoResponseCategory = existingCategories.find(\n (cat) => cat.name === 'No Response' || cat.name === 'Timeout'\n );\n\n if (existingNoResponseCategory) {\n const existingNoResponseExit = existingExits.find(\n (exit) => exit.uuid === existingNoResponseCategory.exit_uuid\n );\n\n if (existingNoResponseExit) {\n router.categories.push(existingNoResponseCategory);\n exits.push({\n uuid: existingNoResponseExit.uuid,\n destination_uuid: existingNoResponseExit.destination_uuid || null\n });\n }\n }\n\n return { router, exits };\n};\n\nexport const wait_for_response: NodeConfig = {\n type: 'wait_for_response',\n name: 'Wait for Response',\n group: SPLIT_GROUPS.wait,\n flowTypes: [FlowTypes.MESSAGE],\n dialogSize: 'large',\n form: {\n rules: createRulesArrayConfig(\n operatorsToSelectOptions(getWaitForResponseOperators()),\n 'If the message from the contact...'\n ),\n timeout_enabled: {\n type: 'checkbox',\n label: (formData: Record<string, any>) => {\n return formData.timeout_enabled\n ? 'Continue when there is no response for'\n : 'Continue when there is no response..';\n },\n labelPadding: '4px 8px'\n },\n timeout_duration: {\n type: 'select',\n placeholder: '5 minutes',\n multi: false,\n maxWidth: '130px',\n flavor: 'xsmall',\n options: TIMEOUT_OPTIONS,\n\n conditions: {\n visible: (formData: Record<string, any>) => {\n return formData.timeout_enabled === true;\n }\n }\n },\n result_name: resultNameField\n },\n layout: ['rules', 'result_name'],\n gutter: [\n {\n type: 'row',\n items: ['timeout_enabled', 'timeout_duration'],\n gap: '0.5rem'\n }\n ],\n validate: (_formData: FormData) => {\n const errors: { [key: string]: string } = {};\n\n // No validation needed - allow multiple rules to use same category name\n // Rules with the same category name will be merged to use the same exit\n\n return {\n valid: Object.keys(errors).length === 0,\n errors\n };\n },\n toFormData: (node: Node) => {\n // Extract rules from router cases using shared function\n const rules = casesToFormRules(node);\n\n // Extract timeout configuration\n const timeoutSeconds = node.router?.wait?.timeout?.seconds;\n let timeoutOption = TIMEOUT_OPTIONS.find(\n (opt) => opt.value === String(timeoutSeconds)\n );\n\n if (!timeoutOption) {\n timeoutOption = { value: '300', name: '5 minutes' };\n }\n\n return {\n uuid: node.uuid,\n rules: rules,\n timeout_enabled: !!timeoutSeconds,\n timeout_duration: timeoutOption,\n result_name: node.router?.result_name || ''\n };\n },\n fromFormData: (formData: FormData, originalNode: Node): Node => {\n // Get user rules using shared extraction function\n const userRules = extractUserRules(formData);\n\n // If no user rules, clear cases but preserve other router config\n if (userRules.length === 0) {\n // Get existing router data for preservation\n let existingCategories = originalNode.router?.categories || [];\n const existingExits = [...(originalNode.exits || [])]; // Create a copy to avoid extensibility issues\n\n // Handle timeout: ensure \"No Response\" category exists if timeout is enabled,\n // or remove it if timeout is disabled\n if (formData.timeout_enabled) {\n let noResponseCategory = existingCategories.find(\n (cat: any) => cat.name === 'No Response'\n );\n\n if (!noResponseCategory) {\n // Create new \"No Response\" category and exit\n const noResponseExitUuid = generateUUID();\n noResponseCategory = {\n uuid: generateUUID(),\n name: 'No Response',\n exit_uuid: noResponseExitUuid\n };\n\n // Add to existing categories for processing\n existingCategories = [...existingCategories, noResponseCategory];\n\n // Add corresponding exit if it doesn't exist\n if (!existingExits.find((exit) => exit.uuid === noResponseExitUuid)) {\n existingExits.push({\n uuid: noResponseExitUuid,\n destination_uuid: null\n });\n }\n }\n } else {\n // If timeout is disabled, remove \"No Response\" category from existing categories\n existingCategories = existingCategories.filter(\n (cat: any) => cat.name !== 'No Response'\n );\n }\n\n // Create router with \"All Responses\" as default category\n // This will now properly handle the \"No Response\" category if it exists\n const { router: noRulesRouter, exits: noRulesExits } =\n createWaitForResponseRouter(\n [], // No user rules\n existingCategories,\n existingExits,\n [] // No cases\n );\n\n const router: any = {\n ...noRulesRouter,\n cases: [] // Clear all cases when no rules\n };\n\n // Only set result_name if provided\n if (formData.result_name && formData.result_name.trim() !== '') {\n router.result_name = formData.result_name.trim();\n }\n\n // Build wait configuration based on form data\n const waitConfig: any = {\n type: 'msg'\n };\n\n // Add timeout if enabled\n if (formData.timeout_enabled) {\n // Extract timeout value (handle both string and object formats)\n let timeoutSeconds;\n\n if (formData.timeout_duration) {\n if (\n Array.isArray(formData.timeout_duration) &&\n formData.timeout_duration.length > 0\n ) {\n // Handle array of selected options (multi-select behavior)\n timeoutSeconds = parseInt(formData.timeout_duration[0].value, 10);\n } else if (typeof formData.timeout_duration === 'string') {\n timeoutSeconds = parseInt(formData.timeout_duration, 10);\n } else if (\n formData.timeout_duration &&\n typeof formData.timeout_duration === 'object' &&\n formData.timeout_duration.value\n ) {\n timeoutSeconds = parseInt(formData.timeout_duration.value, 10);\n } else {\n timeoutSeconds = 300; // Default to 5 minutes\n }\n } else {\n // No duration selected, use default\n timeoutSeconds = 300; // Default to 5 minutes\n }\n\n // Validate that we got a valid number\n if (isNaN(timeoutSeconds) || timeoutSeconds <= 0) {\n timeoutSeconds = 300; // Default to 5 minutes\n }\n\n // Find the \"No Response\" category (should exist now)\n const noResponseCategory = router.categories.find(\n (cat: any) => cat.name === 'No Response'\n );\n\n if (noResponseCategory) {\n waitConfig.timeout = {\n seconds: timeoutSeconds,\n category_uuid: noResponseCategory.uuid\n };\n }\n }\n\n router.wait = waitConfig;\n\n return {\n ...originalNode,\n router,\n exits: noRulesExits\n };\n }\n\n // Get existing router data for preservation\n const existingCategories = originalNode.router?.categories || [];\n const existingExits = originalNode.exits || [];\n const existingCases = originalNode.router?.cases || [];\n\n // Create router and exits using existing data when possible\n const { router, exits } = createWaitForResponseRouter(\n userRules,\n existingCategories,\n existingExits,\n existingCases\n );\n\n // Build final router with wait configuration and result_name\n const finalRouter: any = {\n ...router\n };\n\n // Only set result_name if provided\n if (formData.result_name && formData.result_name.trim() !== '') {\n finalRouter.result_name = formData.result_name.trim();\n }\n\n // Build wait configuration based on form data\n const waitConfig: any = {\n type: 'msg'\n };\n\n try {\n // Handle timeout configuration\n if (formData.timeout_enabled) {\n // Extract timeout value (handle both string and object formats)\n let timeoutSeconds;\n\n if (formData.timeout_duration) {\n try {\n timeoutSeconds = parseInt(formData.timeout_duration[0].value, 10);\n } catch (e) {\n timeoutSeconds = 300; // Default to 5 minutes\n }\n }\n\n // Find or create the \"No Response\" category\n const existingNoResponseCategory =\n originalNode.router?.categories?.find(\n (cat: any) => cat.name === 'No Response'\n );\n\n const noResponseCategory = existingNoResponseCategory || {\n uuid: generateUUID(),\n name: 'No Response',\n exit_uuid: generateUUID()\n };\n\n waitConfig.timeout = {\n seconds: timeoutSeconds,\n category_uuid: noResponseCategory.uuid\n };\n\n // Ensure No Response category and exit exist\n if (\n !router.categories?.some((cat: any) => cat.name === 'No Response')\n ) {\n router.categories = router.categories || [];\n router.categories.push(noResponseCategory);\n\n // Add corresponding exit if it doesn't exist\n if (\n !exits.some(\n (exit: any) => exit.uuid === noResponseCategory.exit_uuid\n )\n ) {\n const noResponseExit = {\n uuid: noResponseCategory.exit_uuid,\n destination_uuid: existingNoResponseCategory?.exit_uuid\n ? originalNode.exits?.find(\n (exit) => exit.uuid === existingNoResponseCategory.exit_uuid\n )?.destination_uuid || null\n : null\n };\n exits.push(noResponseExit);\n }\n }\n } else {\n // Remove \"No Response\" category if timeout is disabled\n if (router.categories) {\n const noResponseCategoryIndex = router.categories.findIndex(\n (cat: any) => cat.name === 'No Response'\n );\n if (noResponseCategoryIndex !== -1) {\n const noResponseCategory =\n router.categories[noResponseCategoryIndex];\n\n // Remove the category\n router.categories.splice(noResponseCategoryIndex, 1);\n\n // Remove corresponding exit\n const exitIndex = exits.findIndex(\n (exit: any) => exit.uuid === noResponseCategory.exit_uuid\n );\n if (exitIndex !== -1) {\n exits.splice(exitIndex, 1);\n }\n }\n }\n }\n } catch (error) {\n console.error('Error processing timeout configuration:', error);\n // Continue without timeout in case of error\n }\n\n finalRouter.wait = waitConfig;\n return {\n ...originalNode,\n router: finalRouter,\n exits: exits\n };\n },\n\n // Localization support for categories\n localizable: 'categories',\n toLocalizationFormData: categoriesToLocalizationFormData,\n fromLocalizationFormData: localizationFormDataToCategories\n};\n"]}
|
|
1
|
+
{"version":3,"file":"wait_for_response.js","sourceRoot":"","sources":["../../../../src/flow/nodes/wait_for_response.ts"],"names":[],"mappings":"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","sourcesContent":["import { SPLIT_GROUPS, FormData, NodeConfig, FlowTypes } from '../types';\nimport { Node, Category, Exit, Case } from '../../store/flow-definition';\nimport { generateUUID, createRulesRouter } from '../../utils';\nimport {\n getWaitForResponseOperators,\n operatorsToSelectOptions,\n getOperatorConfig\n} from '../operators';\nimport {\n resultNameField,\n categoriesToLocalizationFormData,\n localizationFormDataToCategories\n} from './shared';\nimport {\n createRulesArrayConfig,\n extractUserRules,\n casesToFormRules\n} from './shared-rules';\n\nconst TIMEOUT_OPTIONS = [\n { value: '60', name: '1 minute' },\n { value: '120', name: '2 minutes' },\n { value: '180', name: '3 minutes' },\n { value: '240', name: '4 minutes' },\n { value: '300', name: '5 minutes' },\n { value: '600', name: '10 minutes' },\n { value: '900', name: '15 minutes' },\n { value: '1800', name: '30 minutes' },\n { value: '3600', name: '1 hour' },\n { value: '7200', name: '2 hours' },\n { value: '10800', name: '3 hours' },\n { value: '21600', name: '6 hours' },\n { value: '43200', name: '12 hours' },\n { value: '64800', name: '18 hours' },\n { value: '86400', name: '1 day' },\n { value: '172800', name: '2 days' },\n { value: '259200', name: '3 days' },\n { value: '604800', name: '1 week' }\n];\n\n// Helper function to create a wait_for_response router with user rules\n// This is a thin wrapper around createRulesRouter that adds the No Response category for timeouts\nconst createWaitForResponseRouter = (\n userRules: any[],\n existingCategories: Category[] = [],\n existingExits: Exit[] = [],\n existingCases: Case[] = []\n) => {\n const { router, exits } = createRulesRouter(\n '@input.text',\n userRules,\n getOperatorConfig,\n existingCategories,\n existingExits,\n existingCases\n );\n\n // Add \"No Response\" category last (if it exists in the original)\n const existingNoResponseCategory = existingCategories.find(\n (cat) => cat.name === 'No Response' || cat.name === 'Timeout'\n );\n\n if (existingNoResponseCategory) {\n const existingNoResponseExit = existingExits.find(\n (exit) => exit.uuid === existingNoResponseCategory.exit_uuid\n );\n\n if (existingNoResponseExit) {\n router.categories.push(existingNoResponseCategory);\n exits.push({\n uuid: existingNoResponseExit.uuid,\n destination_uuid: existingNoResponseExit.destination_uuid || null\n });\n }\n }\n\n return { router, exits };\n};\n\nexport const wait_for_response: NodeConfig = {\n type: 'wait_for_response',\n name: 'Wait for Response',\n group: SPLIT_GROUPS.wait,\n flowTypes: [FlowTypes.MESSAGE],\n hideFromSplits: true,\n dialogSize: 'large',\n form: {\n rules: createRulesArrayConfig(\n operatorsToSelectOptions(getWaitForResponseOperators()),\n 'If the message from the contact...'\n ),\n timeout_enabled: {\n type: 'checkbox',\n label: (formData: Record<string, any>) => {\n return formData.timeout_enabled\n ? 'Continue when there is no response for'\n : 'Continue when there is no response..';\n },\n labelPadding: '4px 8px'\n },\n timeout_duration: {\n type: 'select',\n placeholder: '5 minutes',\n multi: false,\n maxWidth: '130px',\n flavor: 'xsmall',\n options: TIMEOUT_OPTIONS,\n\n conditions: {\n visible: (formData: Record<string, any>) => {\n return formData.timeout_enabled === true;\n }\n }\n },\n result_name: resultNameField\n },\n layout: ['rules', 'result_name'],\n gutter: [\n {\n type: 'row',\n items: ['timeout_enabled', 'timeout_duration'],\n gap: '0.5rem'\n }\n ],\n validate: (_formData: FormData) => {\n const errors: { [key: string]: string } = {};\n\n // No validation needed - allow multiple rules to use same category name\n // Rules with the same category name will be merged to use the same exit\n\n return {\n valid: Object.keys(errors).length === 0,\n errors\n };\n },\n toFormData: (node: Node) => {\n // Extract rules from router cases using shared function\n const rules = casesToFormRules(node);\n\n // Extract timeout configuration\n const timeoutSeconds = node.router?.wait?.timeout?.seconds;\n let timeoutOption = TIMEOUT_OPTIONS.find(\n (opt) => opt.value === String(timeoutSeconds)\n );\n\n if (!timeoutOption) {\n timeoutOption = { value: '300', name: '5 minutes' };\n }\n\n return {\n uuid: node.uuid,\n rules: rules,\n timeout_enabled: !!timeoutSeconds,\n timeout_duration: timeoutOption,\n result_name: node.router?.result_name || ''\n };\n },\n fromFormData: (formData: FormData, originalNode: Node): Node => {\n // Get user rules using shared extraction function\n const userRules = extractUserRules(formData);\n\n // If no user rules, clear cases but preserve other router config\n if (userRules.length === 0) {\n // Get existing router data for preservation\n let existingCategories = originalNode.router?.categories || [];\n const existingExits = [...(originalNode.exits || [])]; // Create a copy to avoid extensibility issues\n\n // Handle timeout: ensure \"No Response\" category exists if timeout is enabled,\n // or remove it if timeout is disabled\n if (formData.timeout_enabled) {\n let noResponseCategory = existingCategories.find(\n (cat: any) => cat.name === 'No Response'\n );\n\n if (!noResponseCategory) {\n // Create new \"No Response\" category and exit\n const noResponseExitUuid = generateUUID();\n noResponseCategory = {\n uuid: generateUUID(),\n name: 'No Response',\n exit_uuid: noResponseExitUuid\n };\n\n // Add to existing categories for processing\n existingCategories = [...existingCategories, noResponseCategory];\n\n // Add corresponding exit if it doesn't exist\n if (!existingExits.find((exit) => exit.uuid === noResponseExitUuid)) {\n existingExits.push({\n uuid: noResponseExitUuid,\n destination_uuid: null\n });\n }\n }\n } else {\n // If timeout is disabled, remove \"No Response\" category from existing categories\n existingCategories = existingCategories.filter(\n (cat: any) => cat.name !== 'No Response'\n );\n }\n\n // Create router with \"All Responses\" as default category\n // This will now properly handle the \"No Response\" category if it exists\n const { router: noRulesRouter, exits: noRulesExits } =\n createWaitForResponseRouter(\n [], // No user rules\n existingCategories,\n existingExits,\n [] // No cases\n );\n\n const router: any = {\n ...noRulesRouter,\n cases: [] // Clear all cases when no rules\n };\n\n // Only set result_name if provided\n if (formData.result_name && formData.result_name.trim() !== '') {\n router.result_name = formData.result_name.trim();\n }\n\n // Build wait configuration based on form data\n const waitConfig: any = {\n type: 'msg'\n };\n\n // Add timeout if enabled\n if (formData.timeout_enabled) {\n // Extract timeout value (handle both string and object formats)\n let timeoutSeconds;\n\n if (formData.timeout_duration) {\n if (\n Array.isArray(formData.timeout_duration) &&\n formData.timeout_duration.length > 0\n ) {\n // Handle array of selected options (multi-select behavior)\n timeoutSeconds = parseInt(formData.timeout_duration[0].value, 10);\n } else if (typeof formData.timeout_duration === 'string') {\n timeoutSeconds = parseInt(formData.timeout_duration, 10);\n } else if (\n formData.timeout_duration &&\n typeof formData.timeout_duration === 'object' &&\n formData.timeout_duration.value\n ) {\n timeoutSeconds = parseInt(formData.timeout_duration.value, 10);\n } else {\n timeoutSeconds = 300; // Default to 5 minutes\n }\n } else {\n // No duration selected, use default\n timeoutSeconds = 300; // Default to 5 minutes\n }\n\n // Validate that we got a valid number\n if (isNaN(timeoutSeconds) || timeoutSeconds <= 0) {\n timeoutSeconds = 300; // Default to 5 minutes\n }\n\n // Find the \"No Response\" category (should exist now)\n const noResponseCategory = router.categories.find(\n (cat: any) => cat.name === 'No Response'\n );\n\n if (noResponseCategory) {\n waitConfig.timeout = {\n seconds: timeoutSeconds,\n category_uuid: noResponseCategory.uuid\n };\n }\n }\n\n router.wait = waitConfig;\n\n return {\n ...originalNode,\n router,\n exits: noRulesExits\n };\n }\n\n // Get existing router data for preservation\n const existingCategories = originalNode.router?.categories || [];\n const existingExits = originalNode.exits || [];\n const existingCases = originalNode.router?.cases || [];\n\n // Create router and exits using existing data when possible\n const { router, exits } = createWaitForResponseRouter(\n userRules,\n existingCategories,\n existingExits,\n existingCases\n );\n\n // Build final router with wait configuration and result_name\n const finalRouter: any = {\n ...router\n };\n\n // Only set result_name if provided\n if (formData.result_name && formData.result_name.trim() !== '') {\n finalRouter.result_name = formData.result_name.trim();\n }\n\n // Build wait configuration based on form data\n const waitConfig: any = {\n type: 'msg'\n };\n\n try {\n // Handle timeout configuration\n if (formData.timeout_enabled) {\n // Extract timeout value (handle both string and object formats)\n let timeoutSeconds;\n\n if (formData.timeout_duration) {\n try {\n timeoutSeconds = parseInt(formData.timeout_duration[0].value, 10);\n } catch (e) {\n timeoutSeconds = 300; // Default to 5 minutes\n }\n }\n\n // Find or create the \"No Response\" category\n const existingNoResponseCategory =\n originalNode.router?.categories?.find(\n (cat: any) => cat.name === 'No Response'\n );\n\n const noResponseCategory = existingNoResponseCategory || {\n uuid: generateUUID(),\n name: 'No Response',\n exit_uuid: generateUUID()\n };\n\n waitConfig.timeout = {\n seconds: timeoutSeconds,\n category_uuid: noResponseCategory.uuid\n };\n\n // Ensure No Response category and exit exist\n if (\n !router.categories?.some((cat: any) => cat.name === 'No Response')\n ) {\n router.categories = router.categories || [];\n router.categories.push(noResponseCategory);\n\n // Add corresponding exit if it doesn't exist\n if (\n !exits.some(\n (exit: any) => exit.uuid === noResponseCategory.exit_uuid\n )\n ) {\n const noResponseExit = {\n uuid: noResponseCategory.exit_uuid,\n destination_uuid: existingNoResponseCategory?.exit_uuid\n ? originalNode.exits?.find(\n (exit) => exit.uuid === existingNoResponseCategory.exit_uuid\n )?.destination_uuid || null\n : null\n };\n exits.push(noResponseExit);\n }\n }\n } else {\n // Remove \"No Response\" category if timeout is disabled\n if (router.categories) {\n const noResponseCategoryIndex = router.categories.findIndex(\n (cat: any) => cat.name === 'No Response'\n );\n if (noResponseCategoryIndex !== -1) {\n const noResponseCategory =\n router.categories[noResponseCategoryIndex];\n\n // Remove the category\n router.categories.splice(noResponseCategoryIndex, 1);\n\n // Remove corresponding exit\n const exitIndex = exits.findIndex(\n (exit: any) => exit.uuid === noResponseCategory.exit_uuid\n );\n if (exitIndex !== -1) {\n exits.splice(exitIndex, 1);\n }\n }\n }\n }\n } catch (error) {\n console.error('Error processing timeout configuration:', error);\n // Continue without timeout in case of error\n }\n\n finalRouter.wait = waitConfig;\n return {\n ...originalNode,\n router: finalRouter,\n exits: exits\n };\n },\n\n // Localization support for categories\n localizable: 'categories',\n toLocalizationFormData: categoriesToLocalizationFormData,\n fromLocalizationFormData: localizationFormDataToCategories\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/flow/types.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,UAAU,EAAE,YAAY;CAChB,CAAC;AAIX;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,EAAE,EAAE,IAAI;IACR,OAAO,EAAE,SAAS;CACV,CAAC;AAsSX;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,UAAU;IACpB,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;IACtB,OAAO,EAAE,SAAS;CACV,CAAC;AAEX;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;CACN,CAAC;AAeX;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAuC;IACvE,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE;QACpB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,MAAM;QACb,WAAW,EAAE,mDAAmD;KACjE;IACD,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE;QACxB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,SAAS;QAChB,WAAW,EAAE,yCAAyC;KACvD;IACD,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE;QACpB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,MAAM;QACb,WAAW,EAAE,iCAAiC;KAC/C;IACD,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE;QACxB,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,iCAAiC;KAC/C;IACD,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE;QACzB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,qDAAqD;KACnE;IACD,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE;QACvB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,SAAS;QAChB,WAAW,EAAE,qCAAqC;KACnD;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAsC;IACrE,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE;QACnB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,MAAM;QACb,WAAW,EAAE,2CAA2C;KACzD;IACD,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE;QACpB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,OAAO;QACd,WAAW,EAAE,oCAAoC;KAClD;CACF,CAAC","sourcesContent":["import { TemplateResult } from 'lit-html';\nimport { Action, Node, NodeUI } from '../store/flow-definition';\n\nexport interface ValidationResult {\n valid: boolean;\n errors: { [key: string]: string };\n}\n\n/**\n * Flow types - defines the type of flow being edited\n */\nexport const FlowTypes = {\n MESSAGE: 'message',\n VOICE: 'voice',\n BACKGROUND: 'background'\n} as const;\n\nexport type FlowType = (typeof FlowTypes)[keyof typeof FlowTypes];\n\n/**\n * Features - defines the features available in the account\n */\nexport const Features = {\n AI: 'ai',\n AIRTIME: 'airtime'\n} as const;\n\nexport type Feature = (typeof Features)[keyof typeof Features];\n\n// Component attribute interfaces - these define what's allowed for each component type\nexport interface TextInputAttributes {\n type?: 'text' | 'email' | 'number' | 'url' | 'tel';\n placeholder?: string;\n clearable?: boolean;\n maxlength?: number;\n gsm?: boolean;\n autogrow?: boolean;\n textarea?: boolean;\n submitOnEnter?: boolean;\n}\n\nexport interface CompletionAttributes {\n placeholder?: string;\n clearable?: boolean;\n maxlength?: number;\n gsm?: boolean;\n autogrow?: boolean;\n textarea?: boolean;\n expressions?: string;\n counter?: string;\n minHeight?: number;\n}\n\nexport interface SelectAttributes {\n placeholder?: string;\n multi?: boolean;\n searchable?: boolean;\n tags?: boolean;\n emails?: boolean;\n clearable?: boolean;\n endpoint?: string;\n valueKey?: string;\n nameKey?: string;\n queryParam?: string;\n maxItems?: number;\n maxItemsText?: string;\n expressions?: string;\n options?: Array<{ name: string; value: any }>;\n sorted?: boolean;\n allowCreate?: boolean;\n jsonValue?: boolean;\n spaceSelect?: boolean;\n infoText?: string;\n}\n\nexport interface CheckboxAttributes {\n label?: string;\n size?: number;\n disabled?: boolean;\n animateChange?: string;\n}\n\nexport interface SliderAttributes {\n min?: number;\n max?: number;\n range?: boolean;\n}\n\nexport interface FormData extends Record<string, any> {}\n\nexport interface FormConfig {\n form?: Record<string, FieldConfig>;\n layout?: LayoutItem[];\n gutter?: LayoutItem[];\n sanitize?: (formData: FormData) => void;\n validate?: (formData: FormData) => ValidationResult;\n}\n\nexport interface NodeConfig extends FormConfig {\n type: string;\n name?: string;\n aliases?: string[]; // alternate type names for backwards compatibility (won't show in selector)\n group?: ActionGroup | SplitGroup; // Nodes can use either when showAsAction is true\n dialogSize?: 'small' | 'medium' | 'large' | 'xlarge';\n action?: ActionConfig;\n showAsAction?: boolean; // if true, show in action dialog instead of splits (default: false - nodes show in splits)\n flowTypes?: FlowType[]; // which flow types this node is available for (defaults to all if not specified)\n features?: Feature[]; // which features are required for this node (all must be present)\n router?: {\n type: 'switch' | 'random';\n defaultCategory?: string;\n operand?: string;\n configurable?: boolean; // can the rules be configured in the UI\n rules?: {\n type:\n | 'has_number_between'\n | 'has_number_eq'\n | 'has_only_text'\n | 'has_string'\n | 'has_value'\n | 'has_not_value'\n | 'has_text';\n arguments: string[];\n categoryName: string;\n }[];\n };\n\n toFormData?: (node: Node, nodeUI?: any) => FormData;\n fromFormData?: (formData: FormData, originalNode: Node) => Node;\n toUIConfig?: (formData: FormData) => Record<string, any>;\n render?: (node: Node, nodeUI?: any) => TemplateResult;\n renderTitle?: (node: Node, nodeUI?: NodeUI) => TemplateResult;\n\n // Localization support for router categories\n localizable?: 'categories'; // Only categories are localizable for routers\n toLocalizationFormData?: (\n node: Node,\n localization: Record<string, any>\n ) => FormData;\n fromLocalizationFormData?: (\n formData: FormData,\n node: Node\n ) => Record<string, any>;\n}\n\n// New field configuration system for generic form generation\nexport interface BaseFieldConfig {\n label?: string | ((formData: Record<string, any>) => string);\n required?: boolean;\n evaluated?: boolean;\n dependsOn?: string[];\n computeValue?: (\n values: Record<string, any>,\n currentValue: any,\n originalValues?: Record<string, any>\n ) => any;\n\n // Validation properties\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n helpText?: string;\n\n // Layout properties\n maxWidth?: string;\n width?: string;\n\n // Conditional rendering\n conditions?: {\n visible?: (formData: Record<string, any>) => boolean;\n disabled?: (formData: Record<string, any>) => boolean;\n };\n\n // Optional field with reveal link\n // When set, the field is hidden by default and a link with this text is shown\n // Clicking the link reveals the field permanently (can't be hidden again)\n optionalLink?: string;\n}\n\nexport interface TextFieldConfig extends BaseFieldConfig {\n type: 'text';\n placeholder?: string;\n flavor?: 'xsmall' | 'small' | 'large';\n}\n\nexport interface TextareaFieldConfig extends BaseFieldConfig {\n type: 'textarea';\n placeholder?: string;\n rows?: number;\n minHeight?: number;\n}\n\nexport interface SelectFieldConfig extends BaseFieldConfig {\n type: 'select';\n options?: string[] | { value: string; name: string }[];\n multi?: boolean;\n clearable?: boolean;\n searchable?: boolean;\n tags?: boolean;\n placeholder?: string;\n maxItems?: number;\n valueKey?: string;\n nameKey?: string;\n endpoint?: string;\n emails?: boolean;\n getName?: (item: any) => string;\n flavor?: 'xsmall' | 'small' | 'large';\n createArbitraryOption?: (input: string, options: any[]) => any;\n allowCreate?: boolean;\n getDynamicOptions?: () => Array<{ value: string; name: string }>;\n}\n\nexport interface KeyValueFieldConfig extends BaseFieldConfig {\n type: 'key-value';\n sortable?: boolean;\n keyPlaceholder?: string;\n valuePlaceholder?: string;\n minRows?: number;\n}\n\nexport interface ArrayFieldConfig extends BaseFieldConfig {\n type: 'array';\n itemConfig: Record<string, FieldConfig>;\n sortable?: boolean;\n minItems?: number;\n maxItems?: number;\n itemLabel?: string;\n maintainEmptyItem?: boolean;\n onItemChange?: (\n itemIndex: number,\n field: string,\n value: any,\n allItems: any[]\n ) => any[];\n isEmptyItem?: (item: any) => boolean;\n}\n\nexport interface CheckboxFieldConfig extends BaseFieldConfig {\n type: 'checkbox';\n size?: number;\n animateChange?: string;\n labelPadding?: string;\n}\n\nexport interface MessageEditorFieldConfig extends BaseFieldConfig {\n type: 'message-editor';\n placeholder?: string;\n minHeight?: number;\n maxAttachments?: number;\n accept?: string;\n endpoint?: string;\n counter?: string;\n gsm?: boolean;\n autogrow?: boolean;\n disableCompletion?: boolean;\n}\n\nexport interface MediaFieldConfig extends BaseFieldConfig {\n type: 'media';\n accept?: string; // MIME filter, e.g. 'audio/*'\n endpoint?: string; // upload endpoint, defaults to DEFAULT_MEDIA_ENDPOINT\n}\n\nexport type FieldConfig =\n | TextFieldConfig\n | TextareaFieldConfig\n | SelectFieldConfig\n | KeyValueFieldConfig\n | ArrayFieldConfig\n | CheckboxFieldConfig\n | MessageEditorFieldConfig\n | MediaFieldConfig;\n\n// Layout configurations for better form organization\n// Recursive layout system - any layout item can contain other layout items\n\nexport interface FieldItemConfig {\n type: 'field';\n field: string; // field name to render\n}\n\nexport interface RowLayoutConfig {\n type: 'row';\n items: LayoutItem[]; // can contain fields, groups, or other rows\n gap?: string; // CSS gap value, defaults to '1rem'\n label?: string; // optional label for the entire row\n helpText?: string; // optional help text for the entire row\n inlineLabels?: Record<string, string>; // map of field name to inline label text\n marginBottom?: string; // CSS margin-bottom for spacing below the row\n}\n\nexport interface GroupLayoutConfig {\n type: 'group';\n label: string;\n items: LayoutItem[]; // can contain fields, rows, or other groups\n collapsible?: boolean;\n collapsed?: boolean | ((formData: FormData) => boolean); // initial state if collapsible - can be a function\n helpText?: string;\n contentPadding?: string; // CSS padding for group content area\n getGroupValueCount?: (formData: FormData) => number; // optional function to get count for bubble display\n}\n\nexport interface SpacerLayoutConfig {\n type: 'spacer';\n}\n\nexport interface TextLayoutConfig {\n type: 'text';\n text: string;\n}\n\nexport type LayoutItem =\n | FieldItemConfig\n | RowLayoutConfig\n | GroupLayoutConfig\n | SpacerLayoutConfig\n | TextLayoutConfig\n | string; // string is shorthand for field\n\n/**\n * Action group constants - single source of truth for action categorization\n * Use as const for compile-time type checking\n */\nexport const ACTION_GROUPS = {\n send: 'send',\n contacts: 'contacts',\n save: 'save',\n services: 'services',\n broadcast: 'broadcast',\n trigger: 'trigger'\n} as const;\n\n/**\n * Split group constants - single source of truth for split categorization\n * Use as const for compile-time type checking\n */\nexport const SPLIT_GROUPS = {\n wait: 'wait',\n split: 'split'\n} as const;\n\n// Extract types from const objects for compile-time checking\nexport type ActionGroup = (typeof ACTION_GROUPS)[keyof typeof ACTION_GROUPS];\nexport type SplitGroup = (typeof SPLIT_GROUPS)[keyof typeof SPLIT_GROUPS];\n\n/**\n * Metadata for group display\n */\nexport interface GroupMetadata {\n color: string;\n title: string;\n description: string;\n}\n\n/**\n * Action group metadata - defines display properties for each action group\n * Order in this object determines display order in action selector (top to bottom)\n */\nexport const ACTION_GROUP_METADATA: Record<ActionGroup, GroupMetadata> = {\n [ACTION_GROUPS.send]: {\n color: '#3498db',\n title: 'Send',\n description: 'Actions that send messages or content to contacts'\n },\n [ACTION_GROUPS.contacts]: {\n color: '#01c1af',\n title: 'Contact',\n description: 'Actions that update contact information'\n },\n [ACTION_GROUPS.save]: {\n color: '#1a777c',\n title: 'Save',\n description: 'Actions that save or store data'\n },\n [ACTION_GROUPS.services]: {\n color: '#f79035ff',\n title: 'Services',\n description: 'Call external services and APIs'\n },\n [ACTION_GROUPS.broadcast]: {\n color: '#8e5ea7',\n title: 'Other People',\n description: 'Actions that apply to others instead of the contact'\n },\n [ACTION_GROUPS.trigger]: {\n color: '#df419f',\n title: 'Trigger',\n description: 'Actions that trigger other behavior'\n }\n};\n\n/**\n * Split group metadata - defines display properties for each split group\n * Order in this object determines display order in split selector (top to bottom)\n */\nexport const SPLIT_GROUP_METADATA: Record<SplitGroup, GroupMetadata> = {\n [SPLIT_GROUPS.wait]: {\n color: '#4d7dad',\n title: 'Wait',\n description: 'Wait for user and split on their response'\n },\n [SPLIT_GROUPS.split]: {\n color: '#aaaaaa',\n title: 'Split',\n description: 'Split the flow based on conditions'\n }\n};\n\nexport interface ActionConfig extends FormConfig {\n name: string;\n aliases?: string[]; // alternate type names for backwards compatibility (won't show in selector)\n group: ActionGroup;\n dialogSize?: 'small' | 'medium' | 'large' | 'xlarge';\n evaluated?: string[];\n hideFromActions?: boolean; // if true, don't show in action dialog (default: false - actions show in actions)\n flowTypes?: FlowType[]; // which flow types this action is available for (defaults to all if not specified)\n features?: Feature[]; // which features are required for this action (all must be present)\n render?: (node: any, action: any) => TemplateResult;\n\n form?: Record<string, FieldConfig>;\n layout?: LayoutItem[]; // optional layout configuration - array of layout items\n gutter?: LayoutItem[]; // fields to render in the dialog gutter (left side of buttons)\n\n toFormData?: (action: Action) => FormData;\n fromFormData?: (formData: FormData) => Action;\n\n // Localization support\n localizable?: string[]; // array of field names that can be localized\n toLocalizationFormData?: (\n action: Action,\n localization: Record<string, any>\n ) => FormData;\n fromLocalizationFormData?: (\n formData: FormData,\n action: Action\n ) => Record<string, any>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/flow/types.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,UAAU,EAAE,YAAY;CAChB,CAAC;AAIX;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,EAAE,EAAE,IAAI;IACR,OAAO,EAAE,SAAS;CACV,CAAC;AA6TX;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,UAAU;IACpB,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;IACtB,OAAO,EAAE,SAAS;CACV,CAAC;AAEX;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;CACN,CAAC;AAeX;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAuC;IACvE,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE;QACpB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,MAAM;QACb,WAAW,EAAE,mDAAmD;KACjE;IACD,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE;QACxB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,SAAS;QAChB,WAAW,EAAE,yCAAyC;KACvD;IACD,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE;QACpB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,MAAM;QACb,WAAW,EAAE,iCAAiC;KAC/C;IACD,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE;QACxB,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,iCAAiC;KAC/C;IACD,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE;QACzB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,qDAAqD;KACnE;IACD,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE;QACvB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,SAAS;QAChB,WAAW,EAAE,qCAAqC;KACnD;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAsC;IACrE,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE;QACnB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,MAAM;QACb,WAAW,EAAE,2CAA2C;KACzD;IACD,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE;QACpB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,OAAO;QACd,WAAW,EAAE,oCAAoC;KAClD;CACF,CAAC","sourcesContent":["import { TemplateResult } from 'lit-html';\nimport { Action, Node, NodeUI } from '../store/flow-definition';\n\nexport interface ValidationResult {\n valid: boolean;\n errors: { [key: string]: string };\n}\n\n/**\n * Flow types - defines the type of flow being edited\n */\nexport const FlowTypes = {\n MESSAGE: 'message',\n VOICE: 'voice',\n BACKGROUND: 'background'\n} as const;\n\nexport type FlowType = (typeof FlowTypes)[keyof typeof FlowTypes];\n\n/**\n * Features - defines the features available in the account\n */\nexport const Features = {\n AI: 'ai',\n AIRTIME: 'airtime'\n} as const;\n\nexport type Feature = (typeof Features)[keyof typeof Features];\n\n// Component attribute interfaces - these define what's allowed for each component type\nexport interface TextInputAttributes {\n type?: 'text' | 'email' | 'number' | 'url' | 'tel';\n placeholder?: string;\n clearable?: boolean;\n maxlength?: number;\n gsm?: boolean;\n autogrow?: boolean;\n textarea?: boolean;\n submitOnEnter?: boolean;\n}\n\nexport interface CompletionAttributes {\n placeholder?: string;\n clearable?: boolean;\n maxlength?: number;\n gsm?: boolean;\n autogrow?: boolean;\n textarea?: boolean;\n expressions?: string;\n counter?: string;\n minHeight?: number;\n}\n\nexport interface SelectAttributes {\n placeholder?: string;\n multi?: boolean;\n searchable?: boolean;\n tags?: boolean;\n emails?: boolean;\n clearable?: boolean;\n endpoint?: string;\n valueKey?: string;\n nameKey?: string;\n queryParam?: string;\n maxItems?: number;\n maxItemsText?: string;\n expressions?: string;\n options?: Array<{ name: string; value: any }>;\n sorted?: boolean;\n allowCreate?: boolean;\n jsonValue?: boolean;\n spaceSelect?: boolean;\n infoText?: string;\n}\n\nexport interface CheckboxAttributes {\n label?: string;\n size?: number;\n disabled?: boolean;\n animateChange?: string;\n}\n\nexport interface SliderAttributes {\n min?: number;\n max?: number;\n range?: boolean;\n}\n\nexport interface FormData extends Record<string, any> {}\n\nexport interface FormConfig {\n form?: Record<string, FieldConfig>;\n layout?: LayoutItem[];\n gutter?: LayoutItem[];\n sanitize?: (formData: FormData) => void;\n validate?: (formData: FormData) => ValidationResult;\n}\n\nexport interface NodeConfig extends FormConfig {\n type: string;\n name?: string;\n aliases?: string[]; // alternate type names for backwards compatibility (won't show in selector)\n group?: ActionGroup | SplitGroup; // Nodes can use either when showAsAction is true\n dialogSize?: 'small' | 'medium' | 'large' | 'xlarge';\n action?: ActionConfig;\n showAsAction?: boolean; // if true, show in action dialog instead of splits (default: false - nodes show in splits)\n hideFromSplits?: boolean; // if true, don't show in split dialog (e.g. promoted to context menu)\n flowTypes?: FlowType[]; // which flow types this node is available for (defaults to all if not specified)\n features?: Feature[]; // which features are required for this node (all must be present)\n router?: {\n type: 'switch' | 'random';\n defaultCategory?: string;\n operand?: string;\n configurable?: boolean; // can the rules be configured in the UI\n rules?: {\n type:\n | 'has_number_between'\n | 'has_number_eq'\n | 'has_only_text'\n | 'has_string'\n | 'has_value'\n | 'has_not_value'\n | 'has_text';\n arguments: string[];\n categoryName: string;\n }[];\n };\n\n toFormData?: (node: Node, nodeUI?: any) => FormData;\n fromFormData?: (formData: FormData, originalNode: Node) => Node;\n toUIConfig?: (formData: FormData) => Record<string, any>;\n render?: (node: Node, nodeUI?: any) => TemplateResult;\n renderTitle?: (node: Node, nodeUI?: NodeUI) => TemplateResult;\n\n // Localization support for router categories\n localizable?: 'categories'; // Only categories are localizable for routers\n toLocalizationFormData?: (\n node: Node,\n localization: Record<string, any>\n ) => FormData;\n fromLocalizationFormData?: (\n formData: FormData,\n node: Node\n ) => Record<string, any>;\n}\n\n// New field configuration system for generic form generation\nexport interface BaseFieldConfig {\n label?: string | ((formData: Record<string, any>) => string);\n required?: boolean;\n evaluated?: boolean;\n dependsOn?: string[];\n computeValue?: (\n values: Record<string, any>,\n currentValue: any,\n originalValues?: Record<string, any>\n ) => any;\n\n // Validation properties\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n helpText?: string;\n\n // Layout properties\n maxWidth?: string;\n width?: string;\n\n // Conditional rendering\n conditions?: {\n visible?: (formData: Record<string, any>) => boolean;\n disabled?: (formData: Record<string, any>) => boolean;\n };\n\n // Optional field with reveal link\n // When set, the field is hidden by default and a link with this text is shown\n // Clicking the link reveals the field permanently (can't be hidden again)\n optionalLink?: string;\n}\n\nexport interface TextFieldConfig extends BaseFieldConfig {\n type: 'text';\n placeholder?: string;\n flavor?: 'xsmall' | 'small' | 'large';\n}\n\nexport interface TextareaFieldConfig extends BaseFieldConfig {\n type: 'textarea';\n placeholder?: string;\n rows?: number;\n minHeight?: number;\n}\n\nexport interface SelectFieldConfig extends BaseFieldConfig {\n type: 'select';\n options?: string[] | { value: string; name: string }[];\n multi?: boolean;\n clearable?: boolean;\n searchable?: boolean;\n tags?: boolean;\n placeholder?: string;\n maxItems?: number;\n valueKey?: string;\n nameKey?: string;\n endpoint?: string;\n emails?: boolean;\n getName?: (item: any) => string;\n flavor?: 'xsmall' | 'small' | 'large';\n createArbitraryOption?: (input: string, options: any[]) => any;\n allowCreate?: boolean;\n getDynamicOptions?: () => Array<{ value: string; name: string }>;\n}\n\nexport interface KeyValueFieldConfig extends BaseFieldConfig {\n type: 'key-value';\n sortable?: boolean;\n keyPlaceholder?: string;\n valuePlaceholder?: string;\n minRows?: number;\n}\n\nexport interface ArrayFieldConfig extends BaseFieldConfig {\n type: 'array';\n itemConfig: Record<string, FieldConfig>;\n sortable?: boolean;\n minItems?: number;\n maxItems?: number;\n itemLabel?: string;\n maintainEmptyItem?: boolean;\n onItemChange?: (\n itemIndex: number,\n field: string,\n value: any,\n allItems: any[]\n ) => any[];\n isEmptyItem?: (item: any) => boolean;\n}\n\nexport interface CheckboxFieldConfig extends BaseFieldConfig {\n type: 'checkbox';\n size?: number;\n animateChange?: string;\n labelPadding?: string;\n}\n\nexport interface MessageEditorFieldConfig extends BaseFieldConfig {\n type: 'message-editor';\n placeholder?: string;\n minHeight?: number;\n maxAttachments?: number;\n accept?: string;\n endpoint?: string;\n counter?: string;\n gsm?: boolean;\n autogrow?: boolean;\n disableCompletion?: boolean;\n}\n\nexport interface MediaFieldConfig extends BaseFieldConfig {\n type: 'media';\n accept?: string; // MIME filter, e.g. 'audio/*'\n endpoint?: string; // upload endpoint, defaults to DEFAULT_MEDIA_ENDPOINT\n}\n\nexport interface TemplateEditorFieldConfig extends BaseFieldConfig {\n type: 'template-editor';\n endpoint?: string; // endpoint for fetching templates\n}\n\nexport type FieldConfig =\n | TextFieldConfig\n | TextareaFieldConfig\n | SelectFieldConfig\n | KeyValueFieldConfig\n | ArrayFieldConfig\n | CheckboxFieldConfig\n | MessageEditorFieldConfig\n | MediaFieldConfig\n | TemplateEditorFieldConfig;\n\n// Layout configurations for better form organization\n// Recursive layout system - any layout item can contain other layout items\n\nexport interface FieldItemConfig {\n type: 'field';\n field: string; // field name to render\n}\n\nexport interface RowLayoutConfig {\n type: 'row';\n items: LayoutItem[]; // can contain fields, groups, or other rows\n gap?: string; // CSS gap value, defaults to '1rem'\n label?: string; // optional label for the entire row\n helpText?: string; // optional help text for the entire row\n inlineLabels?: Record<string, string>; // map of field name to inline label text\n marginBottom?: string; // CSS margin-bottom for spacing below the row\n}\n\nexport interface GroupLayoutConfig {\n type: 'group';\n label: string;\n items: LayoutItem[]; // can contain fields, rows, or other groups\n collapsible?: boolean;\n collapsed?: boolean | ((formData: FormData) => boolean); // initial state if collapsible - can be a function\n helpText?: string;\n contentPadding?: string; // CSS padding for group content area\n bordered?: boolean; // whether to show border around the group (default: true)\n reveal?: boolean; // one-way expand: once clicked, header disappears and items show directly\n getGroupValueCount?: (formData: FormData) => number | boolean; // optional function to get count for bubble display\n}\n\nexport interface SpacerLayoutConfig {\n type: 'spacer';\n}\n\nexport interface TextLayoutConfig {\n type: 'text';\n text: string;\n}\n\nexport interface AccordionSection {\n label: string;\n items: LayoutItem[];\n collapsed?: boolean | ((formData: FormData) => boolean);\n getValueCount?: (formData: FormData) => number | boolean;\n}\n\nexport interface AccordionLayoutConfig {\n type: 'accordion';\n sections: AccordionSection[];\n multi?: boolean; // allow multiple sections open at once (default: false)\n}\n\nexport type LayoutItem =\n | FieldItemConfig\n | RowLayoutConfig\n | GroupLayoutConfig\n | AccordionLayoutConfig\n | SpacerLayoutConfig\n | TextLayoutConfig\n | string; // string is shorthand for field\n\n/**\n * Action group constants - single source of truth for action categorization\n * Use as const for compile-time type checking\n */\nexport const ACTION_GROUPS = {\n send: 'send',\n contacts: 'contacts',\n save: 'save',\n services: 'services',\n broadcast: 'broadcast',\n trigger: 'trigger'\n} as const;\n\n/**\n * Split group constants - single source of truth for split categorization\n * Use as const for compile-time type checking\n */\nexport const SPLIT_GROUPS = {\n wait: 'wait',\n split: 'split'\n} as const;\n\n// Extract types from const objects for compile-time checking\nexport type ActionGroup = (typeof ACTION_GROUPS)[keyof typeof ACTION_GROUPS];\nexport type SplitGroup = (typeof SPLIT_GROUPS)[keyof typeof SPLIT_GROUPS];\n\n/**\n * Metadata for group display\n */\nexport interface GroupMetadata {\n color: string;\n title: string;\n description: string;\n}\n\n/**\n * Action group metadata - defines display properties for each action group\n * Order in this object determines display order in action selector (top to bottom)\n */\nexport const ACTION_GROUP_METADATA: Record<ActionGroup, GroupMetadata> = {\n [ACTION_GROUPS.send]: {\n color: '#3498db',\n title: 'Send',\n description: 'Actions that send messages or content to contacts'\n },\n [ACTION_GROUPS.contacts]: {\n color: '#01c1af',\n title: 'Contact',\n description: 'Actions that update contact information'\n },\n [ACTION_GROUPS.save]: {\n color: '#1a777c',\n title: 'Save',\n description: 'Actions that save or store data'\n },\n [ACTION_GROUPS.services]: {\n color: '#f79035ff',\n title: 'Services',\n description: 'Call external services and APIs'\n },\n [ACTION_GROUPS.broadcast]: {\n color: '#8e5ea7',\n title: 'Other People',\n description: 'Actions that apply to others instead of the contact'\n },\n [ACTION_GROUPS.trigger]: {\n color: '#df419f',\n title: 'Trigger',\n description: 'Actions that trigger other behavior'\n }\n};\n\n/**\n * Split group metadata - defines display properties for each split group\n * Order in this object determines display order in split selector (top to bottom)\n */\nexport const SPLIT_GROUP_METADATA: Record<SplitGroup, GroupMetadata> = {\n [SPLIT_GROUPS.wait]: {\n color: '#4d7dad',\n title: 'Wait',\n description: 'Wait for user and split on their response'\n },\n [SPLIT_GROUPS.split]: {\n color: '#aaaaaa',\n title: 'Split',\n description: 'Split the flow based on conditions'\n }\n};\n\nexport interface ActionConfig extends FormConfig {\n name: string;\n aliases?: string[]; // alternate type names for backwards compatibility (won't show in selector)\n group: ActionGroup;\n dialogSize?: 'small' | 'medium' | 'large' | 'xlarge';\n evaluated?: string[];\n hideFromActions?: boolean; // if true, don't show in action dialog (default: false - actions show in actions)\n flowTypes?: FlowType[]; // which flow types this action is available for (defaults to all if not specified)\n features?: Feature[]; // which features are required for this action (all must be present)\n render?: (node: any, action: any) => TemplateResult;\n\n form?: Record<string, FieldConfig>;\n layout?: LayoutItem[]; // optional layout configuration - array of layout items\n gutter?: LayoutItem[]; // fields to render in the dialog gutter (left side of buttons)\n\n toFormData?: (action: Action) => FormData;\n fromFormData?: (formData: FormData) => Action;\n\n // Localization support\n localizable?: string[]; // array of field names that can be localized\n toLocalizationFormData?: (\n action: Action,\n localization: Record<string, any>\n ) => FormData;\n fromLocalizationFormData?: (\n formData: FormData,\n action: Action\n ) => Record<string, any>;\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { html } from 'lit-html';
|
|
2
|
+
import { CustomEventType } from '../interfaces';
|
|
2
3
|
const IS_MAC = typeof navigator !== 'undefined' &&
|
|
3
4
|
/Mac|iPod|iPhone|iPad/.test(navigator.platform);
|
|
4
5
|
/**
|
|
@@ -25,6 +26,18 @@ export function snapToGrid(value) {
|
|
|
25
26
|
const snapped = Math.round(value / GRID_SIZE) * GRID_SIZE;
|
|
26
27
|
return Math.max(snapped, 0);
|
|
27
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Renders content clamped to a maximum number of lines with ellipsis.
|
|
31
|
+
* Hovering shows the full text in a tooltip.
|
|
32
|
+
*/
|
|
33
|
+
export const renderClamped = (content, titleText, maxLines = 3) => {
|
|
34
|
+
return html `<div
|
|
35
|
+
style="display: -webkit-box; -webkit-line-clamp: ${maxLines}; -webkit-box-orient: vertical; overflow: hidden; word-wrap: break-word; overflow-wrap: break-word; hyphens: auto;"
|
|
36
|
+
title="${titleText}"
|
|
37
|
+
>
|
|
38
|
+
${content}
|
|
39
|
+
</div>`;
|
|
40
|
+
};
|
|
28
41
|
/**
|
|
29
42
|
* Renders a single line item with optional icon
|
|
30
43
|
*/
|
|
@@ -35,6 +48,7 @@ export const renderLineItem = (name, icon) => {
|
|
|
35
48
|
: null}
|
|
36
49
|
<div
|
|
37
50
|
style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 250px;"
|
|
51
|
+
title="${name}"
|
|
38
52
|
>
|
|
39
53
|
${name}
|
|
40
54
|
</div>
|
|
@@ -74,6 +88,60 @@ export const renderStringList = (items, icon) => {
|
|
|
74
88
|
}
|
|
75
89
|
return itemElements;
|
|
76
90
|
};
|
|
91
|
+
/**
|
|
92
|
+
* Renders a single flow as a clickable link that fires a temba-flow-clicked event
|
|
93
|
+
*/
|
|
94
|
+
const renderFlowLink = (flow, icon) => {
|
|
95
|
+
const handleClick = (e) => {
|
|
96
|
+
e.stopPropagation();
|
|
97
|
+
e.preventDefault();
|
|
98
|
+
const target = e.currentTarget;
|
|
99
|
+
const editor = target.closest('temba-flow-editor');
|
|
100
|
+
if (editor) {
|
|
101
|
+
editor.fireCustomEvent(CustomEventType.FlowClicked, {
|
|
102
|
+
uuid: flow.uuid,
|
|
103
|
+
name: flow.name,
|
|
104
|
+
metaKey: e.metaKey,
|
|
105
|
+
ctrlKey: e.ctrlKey
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
return html `<div class="linked-name" style="display:flex;items-align:center;">
|
|
110
|
+
${icon
|
|
111
|
+
? html `<temba-icon name=${icon} style="margin-right:0.5em"></temba-icon>`
|
|
112
|
+
: null}
|
|
113
|
+
<div
|
|
114
|
+
@click=${handleClick}
|
|
115
|
+
style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 250px; text-decoration: underline; cursor: pointer;"
|
|
116
|
+
>
|
|
117
|
+
${flow.name}
|
|
118
|
+
</div>
|
|
119
|
+
</div>`;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Renders a list of flows as clickable links, showing up to 3 items
|
|
123
|
+
* with a "+X more" indicator if there are more items
|
|
124
|
+
*/
|
|
125
|
+
export const renderFlowLinks = (flows, icon) => {
|
|
126
|
+
const itemElements = [];
|
|
127
|
+
const maxDisplay = 3;
|
|
128
|
+
const displayCount = flows.length === 4 ? 4 : Math.min(maxDisplay, flows.length);
|
|
129
|
+
for (let i = 0; i < displayCount; i++) {
|
|
130
|
+
itemElements.push(renderFlowLink(flows[i], icon));
|
|
131
|
+
}
|
|
132
|
+
if (flows.length > maxDisplay && flows.length !== 4) {
|
|
133
|
+
const remainingCount = flows.length - maxDisplay;
|
|
134
|
+
itemElements.push(html `<div
|
|
135
|
+
style="display:flex;items-align:center;margin-top:0.2em;"
|
|
136
|
+
>
|
|
137
|
+
${icon
|
|
138
|
+
? html `<div style="margin-right:0.4em; width: 1em;"></div>`
|
|
139
|
+
: null}
|
|
140
|
+
<div style="font-size:0.8em">+${remainingCount} more</div>
|
|
141
|
+
</div>`);
|
|
142
|
+
}
|
|
143
|
+
return itemElements;
|
|
144
|
+
};
|
|
77
145
|
export const SCHEMES = [
|
|
78
146
|
{
|
|
79
147
|
scheme: 'tel',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/flow/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { html } from 'lit-html';\nimport { NamedObject, FlowPosition } from '../store/flow-definition';\nimport { FlowIssue } from '../store/AppState';\n\nconst IS_MAC =\n typeof navigator !== 'undefined' &&\n /Mac|iPod|iPhone|iPad/.test(navigator.platform);\n\n/**\n * Returns true if the mouse event is a right-click or equivalent:\n * - button !== 0 (actual right-click or middle-click on any platform)\n * - ctrl+click on macOS (emulates right-click / context menu)\n */\nexport function isRightClick(event: MouseEvent): boolean {\n if (event.button !== 0) return true;\n if (IS_MAC && event.ctrlKey) return true;\n return false;\n}\n\nexport function formatIssueMessage(issue: FlowIssue): string {\n if (issue.dependency) {\n const name = issue.dependency.name || issue.dependency.key;\n return `Cannot find a ${issue.dependency.type} for ${name}`;\n }\n return issue.description;\n}\n\nconst GRID_SIZE = 20;\n\nexport function snapToGrid(value: number): number {\n const snapped = Math.round(value / GRID_SIZE) * GRID_SIZE;\n return Math.max(snapped, 0);\n}\n\n/**\n * Renders a single line item with optional icon\n */\nexport const renderLineItem = (name: string, icon?: string) => {\n return html`<div style=\"display:flex;items-align:center;\">\n ${icon\n ? html`<temba-icon name=${icon} style=\"margin-right:0.5em\"></temba-icon>`\n : null}\n <div\n style=\"white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 250px;\"\n >\n ${name}\n </div>\n </div>`;\n};\n\n/**\n * Renders a list of named objects with optional icon, showing up to 3 items\n * with a \"+X more\" indicator if there are more items\n */\nexport const renderNamedObjects = (assets: NamedObject[], icon?: string) => {\n return renderStringList(\n assets.map((asset) => asset.name),\n icon\n );\n};\n\n/**\n * Renders a list of strings with optional icon, showing up to 3 items\n * with a \"+X more\" indicator if there are more items\n */\nexport const renderStringList = (items: string[], icon?: string) => {\n const itemElements = [];\n const maxDisplay = 3;\n\n // Show up to 3 items, or all 4 if exactly 4 items\n const displayCount =\n items.length === 4 ? 4 : Math.min(maxDisplay, items.length);\n\n for (let i = 0; i < displayCount; i++) {\n const item = items[i];\n itemElements.push(renderLineItem(item, icon));\n }\n\n // Add \"+X more\" if there are more than 3 items (and not exactly 4)\n if (items.length > maxDisplay && items.length !== 4) {\n const remainingCount = items.length - maxDisplay;\n itemElements.push(html`<div\n style=\"display:flex;items-align:center;margin-top:0.2em;\"\n >\n ${icon\n ? html`<div style=\"margin-right:0.4em; width: 1em;\"></div>` // spacing placeholder\n : null}\n <div style=\"font-size:0.8em\">+${remainingCount} more</div>\n </div>`);\n }\n return itemElements;\n};\n\nexport interface Scheme {\n scheme: string;\n name: string;\n path: string;\n excludeFromSplit?: boolean;\n}\n\nexport const SCHEMES: Scheme[] = [\n {\n scheme: 'tel',\n name: 'SMS',\n path: 'Phone Number'\n },\n {\n scheme: 'whatsapp',\n name: 'WhatsApp',\n path: 'WhatsApp Number'\n },\n {\n scheme: 'facebook',\n name: 'Facebook',\n path: 'Facebook ID'\n },\n {\n scheme: 'instagram',\n name: 'Instagram',\n path: 'Instagram ID'\n },\n {\n scheme: 'twitterid',\n name: 'Twitter',\n path: 'Twitter ID',\n excludeFromSplit: true\n },\n {\n scheme: 'telegram',\n name: 'Telegram',\n path: 'Telegram ID'\n },\n {\n scheme: 'viber',\n name: 'Viber',\n path: 'Viber ID'\n },\n {\n scheme: 'line',\n name: 'Line',\n path: 'Line ID'\n },\n {\n scheme: 'wechat',\n name: 'WeChat',\n path: 'WeChat ID'\n },\n {\n scheme: 'fcm',\n name: 'Firebase',\n path: 'Firebase ID'\n },\n {\n scheme: 'jiochat',\n name: 'JioChat',\n path: 'JioChat ID'\n },\n {\n scheme: 'freshchat',\n name: 'Freshchat',\n path: 'Freshchat ID'\n },\n {\n scheme: 'mailto',\n name: 'Email',\n path: 'Email Address',\n excludeFromSplit: true\n },\n {\n scheme: 'twitter',\n name: 'Twitter',\n path: 'Twitter Handle',\n excludeFromSplit: true\n },\n {\n scheme: 'vk',\n name: 'VK',\n path: 'VK ID'\n },\n {\n scheme: 'discord',\n name: 'Discord',\n path: 'Discord ID'\n },\n {\n scheme: 'webchat',\n name: 'Webchat',\n path: 'Webchat ID',\n excludeFromSplit: true\n },\n {\n scheme: 'rocketchat',\n name: 'RocketChat',\n path: 'RocketChat ID'\n },\n {\n scheme: 'ext',\n name: 'External',\n path: 'External ID'\n }\n];\n\n/**\n * Represents the bounding box of a node on the canvas\n */\nexport interface NodeBounds {\n uuid: string;\n left: number;\n top: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n}\n\n/**\n * Minimum vertical spacing between nodes (in pixels)\n */\nconst MIN_NODE_SPACING = 30;\n\n/**\n * Small buffer to avoid floating point precision issues in overlap detection (in pixels)\n * This prevents false positives when nodes are exactly adjacent (e.g., bottom of one node\n * at exactly the same position as top of another)\n */\nconst OVERLAP_BUFFER = 10;\n\n/**\n * Gets the bounding box for a node from the DOM\n *\n * @param nodeUuid - The UUID of the node\n * @param position - The current position of the node\n * @param element - Optional pre-fetched DOM element (recommended for performance when checking multiple nodes)\n * @returns NodeBounds object or null if element not found\n *\n * Note: When element is not provided, performs a DOM query which may impact performance\n * during bulk collision detection. Consider fetching elements beforehand when possible.\n */\nexport const getNodeBounds = (\n nodeUuid: string,\n position: FlowPosition,\n element?: HTMLElement\n): NodeBounds | null => {\n // If element is provided, use it; otherwise try to find it in DOM\n const nodeElement =\n element || (document.querySelector(`[id=\"${nodeUuid}\"]`) as HTMLElement);\n\n if (!nodeElement) {\n return null;\n }\n\n // Use offsetWidth/offsetHeight instead of getBoundingClientRect() so\n // dimensions are in CSS-layout space and unaffected by ancestor transforms (zoom).\n const width = nodeElement.offsetWidth;\n const height = nodeElement.offsetHeight;\n\n return {\n uuid: nodeUuid,\n left: position.left,\n top: position.top,\n right: position.left + width,\n bottom: position.top + height,\n width,\n height\n };\n};\n\n/**\n * Checks if two node bounding boxes overlap\n */\nexport const nodesOverlap = (\n bounds1: NodeBounds,\n bounds2: NodeBounds\n): boolean => {\n // Use a small buffer to avoid floating point precision issues\n const buffer = OVERLAP_BUFFER;\n\n return !(\n bounds1.right <= bounds2.left - buffer ||\n bounds1.left >= bounds2.right + buffer ||\n bounds1.bottom <= bounds2.top - buffer ||\n bounds1.top >= bounds2.bottom + buffer\n );\n};\n\n/**\n * Detects all collisions between a node and other nodes\n */\nexport const detectCollisions = (\n targetBounds: NodeBounds,\n allBounds: NodeBounds[]\n): NodeBounds[] => {\n return allBounds.filter(\n (bounds) =>\n bounds.uuid !== targetBounds.uuid && nodesOverlap(targetBounds, bounds)\n );\n};\n\ntype Direction = 'down' | 'up' | 'right' | 'left';\n\nconst DIRECTIONS: Direction[] = ['down', 'up', 'right', 'left'];\n\n/**\n * Creates a new NodeBounds at a different position\n */\nconst makeBoundsAt = (\n original: NodeBounds,\n left: number,\n top: number\n): NodeBounds => ({\n ...original,\n left,\n top,\n right: left + original.width,\n bottom: top + original.height\n});\n\n/**\n * Computes the minimum position needed to clear all fixed nodes in a given direction.\n * Returns null if the direction is not viable (e.g., would require negative coordinates\n * and still overlap).\n */\nconst computeDirectionalClearance = (\n collider: NodeBounds,\n fixedNodes: NodeBounds[],\n direction: Direction\n): { left: number; top: number } | null => {\n switch (direction) {\n case 'down': {\n const maxBottom = Math.max(...fixedNodes.map((f) => f.bottom));\n const newTop = snapToGrid(maxBottom + MIN_NODE_SPACING);\n return { left: collider.left, top: newTop };\n }\n case 'up': {\n const minTop = Math.min(...fixedNodes.map((f) => f.top));\n const newTop = snapToGrid(minTop - collider.height - MIN_NODE_SPACING);\n if (newTop < 0) return { left: collider.left, top: 0 };\n return { left: collider.left, top: newTop };\n }\n case 'right': {\n const maxRight = Math.max(...fixedNodes.map((f) => f.right));\n const newLeft = snapToGrid(maxRight + MIN_NODE_SPACING);\n return { left: newLeft, top: collider.top };\n }\n case 'left': {\n const minLeft = Math.min(...fixedNodes.map((f) => f.left));\n const newLeft = snapToGrid(minLeft - collider.width - MIN_NODE_SPACING);\n if (newLeft < 0) return { left: 0, top: collider.top };\n return { left: newLeft, top: collider.top };\n }\n }\n};\n\n/**\n * Calculates new positions to resolve all collisions using multi-directional reflow.\n *\n * Sacred nodes (the ones just dropped/created) keep their positions. All other\n * colliding nodes are moved in whichever direction requires the least displacement\n * and causes the fewest cascading collisions.\n */\nexport const calculateReflowPositions = (\n sacredNodeUuids: string[],\n allBounds: NodeBounds[]\n): Map<string, FlowPosition> => {\n const newPositions = new Map<string, FlowPosition>();\n const sacredSet = new Set(sacredNodeUuids);\n\n // Mutable map of current bounds, updated as collisions are resolved\n const currentBounds = new Map<string, NodeBounds>();\n for (const b of allBounds) {\n currentBounds.set(b.uuid, { ...b });\n }\n\n // A sacred node yields to an existing node at the top of the canvas when\n // the sacred wasn't dropped above it. The existing node keeps its top\n // position and the sacred node moves below instead.\n for (const sacredUuid of [...sacredSet]) {\n const sacred = currentBounds.get(sacredUuid);\n if (!sacred) continue;\n\n for (const [uuid, bounds] of currentBounds) {\n if (uuid === sacredUuid || sacredSet.has(uuid)) continue;\n if (!nodesOverlap(sacred, bounds)) continue;\n\n if (sacred.top > bounds.top && bounds.top < MIN_NODE_SPACING) {\n sacredSet.delete(sacredUuid);\n sacredSet.add(uuid);\n break;\n }\n }\n }\n\n // Seed the queue with non-sacred nodes that overlap any sacred node\n const queue: string[] = [];\n const inQueue = new Set<string>();\n\n for (const sacredUuid of sacredSet) {\n const sacred = currentBounds.get(sacredUuid);\n if (!sacred) continue;\n for (const [uuid, bounds] of currentBounds) {\n if (sacredSet.has(uuid) || inQueue.has(uuid)) continue;\n if (nodesOverlap(sacred, bounds)) {\n queue.push(uuid);\n inQueue.add(uuid);\n }\n }\n }\n\n const resolved = new Set<string>();\n let iterations = 0;\n const maxIterations = 200;\n\n while (queue.length > 0 && iterations < maxIterations) {\n iterations++;\n const uuid = queue.shift()!;\n\n if (resolved.has(uuid)) continue;\n\n const collider = currentBounds.get(uuid)!;\n\n // Find all fixed nodes (sacred + already-resolved) that overlap this node\n const fixedOverlaps: NodeBounds[] = [];\n for (const [otherUuid, otherBounds] of currentBounds) {\n if (otherUuid === uuid) continue;\n if (sacredSet.has(otherUuid) || resolved.has(otherUuid)) {\n if (nodesOverlap(collider, otherBounds)) {\n fixedOverlaps.push(otherBounds);\n }\n }\n }\n\n if (fixedOverlaps.length === 0) continue;\n\n // Determine direction constraints and axis bias from sacred node overlaps\n const sacredOverlaps = fixedOverlaps.filter((f) => sacredSet.has(f.uuid));\n const allowedDirections: Direction[] = [...DIRECTIONS];\n let axisBias: 'vertical' | 'horizontal' | null = null;\n\n if (sacredOverlaps.length > 0) {\n // Rule 1: don't move a lower node above the sacred node\n // Rule 2: don't move a right-of node to the left of the sacred node\n for (const sacred of sacredOverlaps) {\n if (collider.top > sacred.top) {\n const idx = allowedDirections.indexOf('up');\n if (idx !== -1) allowedDirections.splice(idx, 1);\n }\n if (collider.left > sacred.left) {\n const idx = allowedDirections.indexOf('left');\n if (idx !== -1) allowedDirections.splice(idx, 1);\n }\n }\n\n // Rule 3: bias direction based on overlap shape\n let totalOverlapWidth = 0;\n let totalOverlapHeight = 0;\n for (const sacred of sacredOverlaps) {\n totalOverlapWidth +=\n Math.min(collider.right, sacred.right) -\n Math.max(collider.left, sacred.left);\n totalOverlapHeight +=\n Math.min(collider.bottom, sacred.bottom) -\n Math.max(collider.top, sacred.top);\n }\n if (totalOverlapWidth > totalOverlapHeight) {\n axisBias = 'vertical'; // wide overlap = nodes stacked = prefer up/down\n } else if (totalOverlapHeight > totalOverlapWidth) {\n axisBias = 'horizontal'; // tall overlap = nodes side-by-side = prefer left/right\n }\n }\n\n // Try each allowed direction, pick the one with least disruption\n let bestPos: { left: number; top: number } | null = null;\n let bestScore = Infinity;\n\n for (const dir of allowedDirections) {\n const candidate = computeDirectionalClearance(\n collider,\n fixedOverlaps,\n dir\n );\n if (!candidate) continue;\n\n const candidateBounds = makeBoundsAt(\n collider,\n candidate.left,\n candidate.top\n );\n\n // Verify no overlap with any sacred or resolved node\n let stillOverlaps = false;\n let cascadeCount = 0;\n for (const [otherUuid, otherBounds] of currentBounds) {\n if (otherUuid === uuid) continue;\n if (!nodesOverlap(candidateBounds, otherBounds)) continue;\n\n if (sacredSet.has(otherUuid) || resolved.has(otherUuid)) {\n stillOverlaps = true;\n break;\n }\n cascadeCount++;\n }\n if (stillOverlaps) continue;\n\n const distance =\n Math.abs(candidate.left - collider.left) +\n Math.abs(candidate.top - collider.top);\n\n // When colliding with sacred nodes, use axis bias scoring;\n // for cascading collisions (no sacred overlap), use original scoring\n let score: number;\n if (sacredOverlaps.length > 0) {\n const isVerticalDir = dir === 'up' || dir === 'down';\n const axisMatch =\n axisBias === null ||\n (axisBias === 'vertical' && isVerticalDir) ||\n (axisBias === 'horizontal' && !isVerticalDir);\n const axisPenalty = axisMatch ? 0 : 5000;\n score = cascadeCount * 2000 + axisPenalty + distance;\n } else {\n score = cascadeCount * 10000 + distance;\n }\n\n if (score < bestScore) {\n bestScore = score;\n bestPos = candidate;\n }\n }\n\n if (bestPos) {\n newPositions.set(uuid, { left: bestPos.left, top: bestPos.top });\n const newBounds = makeBoundsAt(collider, bestPos.left, bestPos.top);\n currentBounds.set(uuid, newBounds);\n resolved.add(uuid);\n\n // Enqueue any new cascading collisions\n for (const [otherUuid, otherBounds] of currentBounds) {\n if (otherUuid === uuid) continue;\n if (sacredSet.has(otherUuid) || resolved.has(otherUuid)) continue;\n if (inQueue.has(otherUuid)) continue;\n if (nodesOverlap(newBounds, otherBounds)) {\n queue.push(otherUuid);\n inQueue.add(otherUuid);\n }\n }\n }\n }\n\n return newPositions;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/flow/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, TemplateResult } from 'lit-html';\nimport { NamedObject, FlowPosition } from '../store/flow-definition';\nimport { FlowIssue } from '../store/AppState';\nimport { CustomEventType } from '../interfaces';\n\nconst IS_MAC =\n typeof navigator !== 'undefined' &&\n /Mac|iPod|iPhone|iPad/.test(navigator.platform);\n\n/**\n * Returns true if the mouse event is a right-click or equivalent:\n * - button !== 0 (actual right-click or middle-click on any platform)\n * - ctrl+click on macOS (emulates right-click / context menu)\n */\nexport function isRightClick(event: MouseEvent): boolean {\n if (event.button !== 0) return true;\n if (IS_MAC && event.ctrlKey) return true;\n return false;\n}\n\nexport function formatIssueMessage(issue: FlowIssue): string {\n if (issue.dependency) {\n const name = issue.dependency.name || issue.dependency.key;\n return `Cannot find a ${issue.dependency.type} for ${name}`;\n }\n return issue.description;\n}\n\nconst GRID_SIZE = 20;\n\nexport function snapToGrid(value: number): number {\n const snapped = Math.round(value / GRID_SIZE) * GRID_SIZE;\n return Math.max(snapped, 0);\n}\n\n/**\n * Renders content clamped to a maximum number of lines with ellipsis.\n * Hovering shows the full text in a tooltip.\n */\nexport const renderClamped = (\n content: TemplateResult | string,\n titleText: string,\n maxLines: number = 3\n) => {\n return html`<div\n style=\"display: -webkit-box; -webkit-line-clamp: ${maxLines}; -webkit-box-orient: vertical; overflow: hidden; word-wrap: break-word; overflow-wrap: break-word; hyphens: auto;\"\n title=\"${titleText}\"\n >\n ${content}\n </div>`;\n};\n\n/**\n * Renders a single line item with optional icon\n */\nexport const renderLineItem = (name: string, icon?: string) => {\n return html`<div style=\"display:flex;items-align:center;\">\n ${icon\n ? html`<temba-icon name=${icon} style=\"margin-right:0.5em\"></temba-icon>`\n : null}\n <div\n style=\"white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 250px;\"\n title=\"${name}\"\n >\n ${name}\n </div>\n </div>`;\n};\n\n/**\n * Renders a list of named objects with optional icon, showing up to 3 items\n * with a \"+X more\" indicator if there are more items\n */\nexport const renderNamedObjects = (assets: NamedObject[], icon?: string) => {\n return renderStringList(\n assets.map((asset) => asset.name),\n icon\n );\n};\n\n/**\n * Renders a list of strings with optional icon, showing up to 3 items\n * with a \"+X more\" indicator if there are more items\n */\nexport const renderStringList = (items: string[], icon?: string) => {\n const itemElements = [];\n const maxDisplay = 3;\n\n // Show up to 3 items, or all 4 if exactly 4 items\n const displayCount =\n items.length === 4 ? 4 : Math.min(maxDisplay, items.length);\n\n for (let i = 0; i < displayCount; i++) {\n const item = items[i];\n itemElements.push(renderLineItem(item, icon));\n }\n\n // Add \"+X more\" if there are more than 3 items (and not exactly 4)\n if (items.length > maxDisplay && items.length !== 4) {\n const remainingCount = items.length - maxDisplay;\n itemElements.push(html`<div\n style=\"display:flex;items-align:center;margin-top:0.2em;\"\n >\n ${icon\n ? html`<div style=\"margin-right:0.4em; width: 1em;\"></div>` // spacing placeholder\n : null}\n <div style=\"font-size:0.8em\">+${remainingCount} more</div>\n </div>`);\n }\n return itemElements;\n};\n\n/**\n * Renders a single flow as a clickable link that fires a temba-flow-clicked event\n */\nconst renderFlowLink = (flow: NamedObject, icon?: string) => {\n const handleClick = (e: MouseEvent) => {\n e.stopPropagation();\n e.preventDefault();\n const target = e.currentTarget as HTMLElement;\n const editor = target.closest('temba-flow-editor') as any;\n if (editor) {\n editor.fireCustomEvent(CustomEventType.FlowClicked, {\n uuid: flow.uuid,\n name: flow.name,\n metaKey: e.metaKey,\n ctrlKey: e.ctrlKey\n });\n }\n };\n\n return html`<div class=\"linked-name\" style=\"display:flex;items-align:center;\">\n ${icon\n ? html`<temba-icon name=${icon} style=\"margin-right:0.5em\"></temba-icon>`\n : null}\n <div\n @click=${handleClick}\n style=\"white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 250px; text-decoration: underline; cursor: pointer;\"\n >\n ${flow.name}\n </div>\n </div>`;\n};\n\n/**\n * Renders a list of flows as clickable links, showing up to 3 items\n * with a \"+X more\" indicator if there are more items\n */\nexport const renderFlowLinks = (flows: NamedObject[], icon?: string) => {\n const itemElements = [];\n const maxDisplay = 3;\n\n const displayCount =\n flows.length === 4 ? 4 : Math.min(maxDisplay, flows.length);\n\n for (let i = 0; i < displayCount; i++) {\n itemElements.push(renderFlowLink(flows[i], icon));\n }\n\n if (flows.length > maxDisplay && flows.length !== 4) {\n const remainingCount = flows.length - maxDisplay;\n itemElements.push(html`<div\n style=\"display:flex;items-align:center;margin-top:0.2em;\"\n >\n ${icon\n ? html`<div style=\"margin-right:0.4em; width: 1em;\"></div>`\n : null}\n <div style=\"font-size:0.8em\">+${remainingCount} more</div>\n </div>`);\n }\n return itemElements;\n};\n\nexport interface Scheme {\n scheme: string;\n name: string;\n path: string;\n excludeFromSplit?: boolean;\n}\n\nexport const SCHEMES: Scheme[] = [\n {\n scheme: 'tel',\n name: 'SMS',\n path: 'Phone Number'\n },\n {\n scheme: 'whatsapp',\n name: 'WhatsApp',\n path: 'WhatsApp Number'\n },\n {\n scheme: 'facebook',\n name: 'Facebook',\n path: 'Facebook ID'\n },\n {\n scheme: 'instagram',\n name: 'Instagram',\n path: 'Instagram ID'\n },\n {\n scheme: 'twitterid',\n name: 'Twitter',\n path: 'Twitter ID',\n excludeFromSplit: true\n },\n {\n scheme: 'telegram',\n name: 'Telegram',\n path: 'Telegram ID'\n },\n {\n scheme: 'viber',\n name: 'Viber',\n path: 'Viber ID'\n },\n {\n scheme: 'line',\n name: 'Line',\n path: 'Line ID'\n },\n {\n scheme: 'wechat',\n name: 'WeChat',\n path: 'WeChat ID'\n },\n {\n scheme: 'fcm',\n name: 'Firebase',\n path: 'Firebase ID'\n },\n {\n scheme: 'jiochat',\n name: 'JioChat',\n path: 'JioChat ID'\n },\n {\n scheme: 'freshchat',\n name: 'Freshchat',\n path: 'Freshchat ID'\n },\n {\n scheme: 'mailto',\n name: 'Email',\n path: 'Email Address',\n excludeFromSplit: true\n },\n {\n scheme: 'twitter',\n name: 'Twitter',\n path: 'Twitter Handle',\n excludeFromSplit: true\n },\n {\n scheme: 'vk',\n name: 'VK',\n path: 'VK ID'\n },\n {\n scheme: 'discord',\n name: 'Discord',\n path: 'Discord ID'\n },\n {\n scheme: 'webchat',\n name: 'Webchat',\n path: 'Webchat ID',\n excludeFromSplit: true\n },\n {\n scheme: 'rocketchat',\n name: 'RocketChat',\n path: 'RocketChat ID'\n },\n {\n scheme: 'ext',\n name: 'External',\n path: 'External ID'\n }\n];\n\n/**\n * Represents the bounding box of a node on the canvas\n */\nexport interface NodeBounds {\n uuid: string;\n left: number;\n top: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n}\n\n/**\n * Minimum vertical spacing between nodes (in pixels)\n */\nconst MIN_NODE_SPACING = 30;\n\n/**\n * Small buffer to avoid floating point precision issues in overlap detection (in pixels)\n * This prevents false positives when nodes are exactly adjacent (e.g., bottom of one node\n * at exactly the same position as top of another)\n */\nconst OVERLAP_BUFFER = 10;\n\n/**\n * Gets the bounding box for a node from the DOM\n *\n * @param nodeUuid - The UUID of the node\n * @param position - The current position of the node\n * @param element - Optional pre-fetched DOM element (recommended for performance when checking multiple nodes)\n * @returns NodeBounds object or null if element not found\n *\n * Note: When element is not provided, performs a DOM query which may impact performance\n * during bulk collision detection. Consider fetching elements beforehand when possible.\n */\nexport const getNodeBounds = (\n nodeUuid: string,\n position: FlowPosition,\n element?: HTMLElement\n): NodeBounds | null => {\n // If element is provided, use it; otherwise try to find it in DOM\n const nodeElement =\n element || (document.querySelector(`[id=\"${nodeUuid}\"]`) as HTMLElement);\n\n if (!nodeElement) {\n return null;\n }\n\n // Use offsetWidth/offsetHeight instead of getBoundingClientRect() so\n // dimensions are in CSS-layout space and unaffected by ancestor transforms (zoom).\n const width = nodeElement.offsetWidth;\n const height = nodeElement.offsetHeight;\n\n return {\n uuid: nodeUuid,\n left: position.left,\n top: position.top,\n right: position.left + width,\n bottom: position.top + height,\n width,\n height\n };\n};\n\n/**\n * Checks if two node bounding boxes overlap\n */\nexport const nodesOverlap = (\n bounds1: NodeBounds,\n bounds2: NodeBounds\n): boolean => {\n // Use a small buffer to avoid floating point precision issues\n const buffer = OVERLAP_BUFFER;\n\n return !(\n bounds1.right <= bounds2.left - buffer ||\n bounds1.left >= bounds2.right + buffer ||\n bounds1.bottom <= bounds2.top - buffer ||\n bounds1.top >= bounds2.bottom + buffer\n );\n};\n\n/**\n * Detects all collisions between a node and other nodes\n */\nexport const detectCollisions = (\n targetBounds: NodeBounds,\n allBounds: NodeBounds[]\n): NodeBounds[] => {\n return allBounds.filter(\n (bounds) =>\n bounds.uuid !== targetBounds.uuid && nodesOverlap(targetBounds, bounds)\n );\n};\n\ntype Direction = 'down' | 'up' | 'right' | 'left';\n\nconst DIRECTIONS: Direction[] = ['down', 'up', 'right', 'left'];\n\n/**\n * Creates a new NodeBounds at a different position\n */\nconst makeBoundsAt = (\n original: NodeBounds,\n left: number,\n top: number\n): NodeBounds => ({\n ...original,\n left,\n top,\n right: left + original.width,\n bottom: top + original.height\n});\n\n/**\n * Computes the minimum position needed to clear all fixed nodes in a given direction.\n * Returns null if the direction is not viable (e.g., would require negative coordinates\n * and still overlap).\n */\nconst computeDirectionalClearance = (\n collider: NodeBounds,\n fixedNodes: NodeBounds[],\n direction: Direction\n): { left: number; top: number } | null => {\n switch (direction) {\n case 'down': {\n const maxBottom = Math.max(...fixedNodes.map((f) => f.bottom));\n const newTop = snapToGrid(maxBottom + MIN_NODE_SPACING);\n return { left: collider.left, top: newTop };\n }\n case 'up': {\n const minTop = Math.min(...fixedNodes.map((f) => f.top));\n const newTop = snapToGrid(minTop - collider.height - MIN_NODE_SPACING);\n if (newTop < 0) return { left: collider.left, top: 0 };\n return { left: collider.left, top: newTop };\n }\n case 'right': {\n const maxRight = Math.max(...fixedNodes.map((f) => f.right));\n const newLeft = snapToGrid(maxRight + MIN_NODE_SPACING);\n return { left: newLeft, top: collider.top };\n }\n case 'left': {\n const minLeft = Math.min(...fixedNodes.map((f) => f.left));\n const newLeft = snapToGrid(minLeft - collider.width - MIN_NODE_SPACING);\n if (newLeft < 0) return { left: 0, top: collider.top };\n return { left: newLeft, top: collider.top };\n }\n }\n};\n\n/**\n * Calculates new positions to resolve all collisions using multi-directional reflow.\n *\n * Sacred nodes (the ones just dropped/created) keep their positions. All other\n * colliding nodes are moved in whichever direction requires the least displacement\n * and causes the fewest cascading collisions.\n */\nexport const calculateReflowPositions = (\n sacredNodeUuids: string[],\n allBounds: NodeBounds[]\n): Map<string, FlowPosition> => {\n const newPositions = new Map<string, FlowPosition>();\n const sacredSet = new Set(sacredNodeUuids);\n\n // Mutable map of current bounds, updated as collisions are resolved\n const currentBounds = new Map<string, NodeBounds>();\n for (const b of allBounds) {\n currentBounds.set(b.uuid, { ...b });\n }\n\n // A sacred node yields to an existing node at the top of the canvas when\n // the sacred wasn't dropped above it. The existing node keeps its top\n // position and the sacred node moves below instead.\n for (const sacredUuid of [...sacredSet]) {\n const sacred = currentBounds.get(sacredUuid);\n if (!sacred) continue;\n\n for (const [uuid, bounds] of currentBounds) {\n if (uuid === sacredUuid || sacredSet.has(uuid)) continue;\n if (!nodesOverlap(sacred, bounds)) continue;\n\n if (sacred.top > bounds.top && bounds.top < MIN_NODE_SPACING) {\n sacredSet.delete(sacredUuid);\n sacredSet.add(uuid);\n break;\n }\n }\n }\n\n // Seed the queue with non-sacred nodes that overlap any sacred node\n const queue: string[] = [];\n const inQueue = new Set<string>();\n\n for (const sacredUuid of sacredSet) {\n const sacred = currentBounds.get(sacredUuid);\n if (!sacred) continue;\n for (const [uuid, bounds] of currentBounds) {\n if (sacredSet.has(uuid) || inQueue.has(uuid)) continue;\n if (nodesOverlap(sacred, bounds)) {\n queue.push(uuid);\n inQueue.add(uuid);\n }\n }\n }\n\n const resolved = new Set<string>();\n let iterations = 0;\n const maxIterations = 200;\n\n while (queue.length > 0 && iterations < maxIterations) {\n iterations++;\n const uuid = queue.shift()!;\n\n if (resolved.has(uuid)) continue;\n\n const collider = currentBounds.get(uuid)!;\n\n // Find all fixed nodes (sacred + already-resolved) that overlap this node\n const fixedOverlaps: NodeBounds[] = [];\n for (const [otherUuid, otherBounds] of currentBounds) {\n if (otherUuid === uuid) continue;\n if (sacredSet.has(otherUuid) || resolved.has(otherUuid)) {\n if (nodesOverlap(collider, otherBounds)) {\n fixedOverlaps.push(otherBounds);\n }\n }\n }\n\n if (fixedOverlaps.length === 0) continue;\n\n // Determine direction constraints and axis bias from sacred node overlaps\n const sacredOverlaps = fixedOverlaps.filter((f) => sacredSet.has(f.uuid));\n const allowedDirections: Direction[] = [...DIRECTIONS];\n let axisBias: 'vertical' | 'horizontal' | null = null;\n\n if (sacredOverlaps.length > 0) {\n // Rule 1: don't move a lower node above the sacred node\n // Rule 2: don't move a right-of node to the left of the sacred node\n for (const sacred of sacredOverlaps) {\n if (collider.top > sacred.top) {\n const idx = allowedDirections.indexOf('up');\n if (idx !== -1) allowedDirections.splice(idx, 1);\n }\n if (collider.left > sacred.left) {\n const idx = allowedDirections.indexOf('left');\n if (idx !== -1) allowedDirections.splice(idx, 1);\n }\n }\n\n // Rule 3: bias direction based on overlap shape\n let totalOverlapWidth = 0;\n let totalOverlapHeight = 0;\n for (const sacred of sacredOverlaps) {\n totalOverlapWidth +=\n Math.min(collider.right, sacred.right) -\n Math.max(collider.left, sacred.left);\n totalOverlapHeight +=\n Math.min(collider.bottom, sacred.bottom) -\n Math.max(collider.top, sacred.top);\n }\n if (totalOverlapWidth > totalOverlapHeight) {\n axisBias = 'vertical'; // wide overlap = nodes stacked = prefer up/down\n } else if (totalOverlapHeight > totalOverlapWidth) {\n axisBias = 'horizontal'; // tall overlap = nodes side-by-side = prefer left/right\n }\n }\n\n // Try each allowed direction, pick the one with least disruption\n let bestPos: { left: number; top: number } | null = null;\n let bestScore = Infinity;\n\n for (const dir of allowedDirections) {\n const candidate = computeDirectionalClearance(\n collider,\n fixedOverlaps,\n dir\n );\n if (!candidate) continue;\n\n const candidateBounds = makeBoundsAt(\n collider,\n candidate.left,\n candidate.top\n );\n\n // Verify no overlap with any sacred or resolved node\n let stillOverlaps = false;\n let cascadeCount = 0;\n for (const [otherUuid, otherBounds] of currentBounds) {\n if (otherUuid === uuid) continue;\n if (!nodesOverlap(candidateBounds, otherBounds)) continue;\n\n if (sacredSet.has(otherUuid) || resolved.has(otherUuid)) {\n stillOverlaps = true;\n break;\n }\n cascadeCount++;\n }\n if (stillOverlaps) continue;\n\n const distance =\n Math.abs(candidate.left - collider.left) +\n Math.abs(candidate.top - collider.top);\n\n // When colliding with sacred nodes, use axis bias scoring;\n // for cascading collisions (no sacred overlap), use original scoring\n let score: number;\n if (sacredOverlaps.length > 0) {\n const isVerticalDir = dir === 'up' || dir === 'down';\n const axisMatch =\n axisBias === null ||\n (axisBias === 'vertical' && isVerticalDir) ||\n (axisBias === 'horizontal' && !isVerticalDir);\n const axisPenalty = axisMatch ? 0 : 5000;\n score = cascadeCount * 2000 + axisPenalty + distance;\n } else {\n score = cascadeCount * 10000 + distance;\n }\n\n if (score < bestScore) {\n bestScore = score;\n bestPos = candidate;\n }\n }\n\n if (bestPos) {\n newPositions.set(uuid, { left: bestPos.left, top: bestPos.top });\n const newBounds = makeBoundsAt(collider, bestPos.left, bestPos.top);\n currentBounds.set(uuid, newBounds);\n resolved.add(uuid);\n\n // Enqueue any new cascading collisions\n for (const [otherUuid, otherBounds] of currentBounds) {\n if (otherUuid === uuid) continue;\n if (sacredSet.has(otherUuid) || resolved.has(otherUuid)) continue;\n if (inQueue.has(otherUuid)) continue;\n if (nodesOverlap(newBounds, otherBounds)) {\n queue.push(otherUuid);\n inQueue.add(otherUuid);\n }\n }\n }\n }\n\n return newPositions;\n};\n"]}
|
|
@@ -40,6 +40,8 @@ export class FieldRenderer {
|
|
|
40
40
|
return FieldRenderer.renderMessageEditor(fieldName, config, value, context);
|
|
41
41
|
case 'media':
|
|
42
42
|
return FieldRenderer.renderMedia(fieldName, config, value, context);
|
|
43
|
+
case 'template-editor':
|
|
44
|
+
return FieldRenderer.renderTemplateEditor(fieldName, config, value, context);
|
|
43
45
|
default:
|
|
44
46
|
return html `<div>Unsupported field type: ${config.type}</div>`;
|
|
45
47
|
}
|
|
@@ -55,7 +57,7 @@ export class FieldRenderer {
|
|
|
55
57
|
.errors="${errors}"
|
|
56
58
|
.value="${value || ''}"
|
|
57
59
|
placeholder="${config.placeholder || ''}"
|
|
58
|
-
|
|
60
|
+
session
|
|
59
61
|
.helpText="${config.helpText || ''}"
|
|
60
62
|
class="${extraClasses}"
|
|
61
63
|
style="${style}"
|
|
@@ -92,7 +94,7 @@ export class FieldRenderer {
|
|
|
92
94
|
.value="${value || ''}"
|
|
93
95
|
placeholder="${config.placeholder || ''}"
|
|
94
96
|
textarea
|
|
95
|
-
|
|
97
|
+
session
|
|
96
98
|
.helpText="${config.helpText || ''}"
|
|
97
99
|
class="${extraClasses}"
|
|
98
100
|
style="${combinedStyle}"
|
|
@@ -296,6 +298,7 @@ export class FieldRenderer {
|
|
|
296
298
|
?autogrow="${config.autogrow}"
|
|
297
299
|
?gsm="${config.gsm}"
|
|
298
300
|
?disableCompletion="${config.disableCompletion}"
|
|
301
|
+
session
|
|
299
302
|
counter="${config.counter || ''}"
|
|
300
303
|
accept="${config.accept || ''}"
|
|
301
304
|
endpoint="${config.endpoint || ''}"
|
|
@@ -306,5 +309,17 @@ export class FieldRenderer {
|
|
|
306
309
|
@change="${onChange || (() => { })}"
|
|
307
310
|
></temba-message-editor>`;
|
|
308
311
|
}
|
|
312
|
+
static renderTemplateEditor(_fieldName, config, value, context) {
|
|
313
|
+
const { onChange, additionalData = {} } = context;
|
|
314
|
+
const templateUuid = (value === null || value === void 0 ? void 0 : value.uuid) || '';
|
|
315
|
+
const variables = JSON.stringify(additionalData.template_variables || []);
|
|
316
|
+
return html `<temba-template-editor
|
|
317
|
+
url="${config.endpoint || '/api/internal/templates.json'}"
|
|
318
|
+
template="${templateUuid}"
|
|
319
|
+
variables="${variables}"
|
|
320
|
+
@temba-context-changed="${onChange || (() => { })}"
|
|
321
|
+
@temba-content-changed="${onChange || (() => { })}"
|
|
322
|
+
></temba-template-editor>`;
|
|
323
|
+
}
|
|
309
324
|
}
|
|
310
325
|
//# sourceMappingURL=FieldRenderer.js.map
|