@nyaruka/temba-components 0.130.1 → 0.130.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -4
- package/DEV_DATA.md +89 -0
- package/demo/data/flows/food-order.json +4 -4
- package/demo/data/flows/sample-flow.json +132 -147
- package/dist/temba-components.js +787 -659
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/display/Chat.js +5 -3
- package/out-tsc/src/display/Chat.js.map +1 -1
- package/out-tsc/src/events.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +83 -78
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +1 -0
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +47 -3
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/actions/add_contact_urn.js +1 -1
- package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_field.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_language.js +3 -1
- package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_name.js +1 -1
- package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_status.js +17 -14
- package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
- package/out-tsc/src/flow/actions/set_run_result.js +1 -1
- package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm.js +12 -12
- package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js +609 -6
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
- package/out-tsc/src/flow/operators.js +194 -0
- package/out-tsc/src/flow/operators.js.map +1 -0
- package/out-tsc/src/flow/types.js.map +1 -1
- package/out-tsc/src/form/ArrayEditor.js +84 -19
- package/out-tsc/src/form/ArrayEditor.js.map +1 -1
- package/out-tsc/src/form/Checkbox.js +12 -0
- package/out-tsc/src/form/Checkbox.js.map +1 -1
- package/out-tsc/src/form/FieldRenderer.js +13 -3
- package/out-tsc/src/form/FieldRenderer.js.map +1 -1
- package/out-tsc/src/form/TextInput.js +20 -1
- package/out-tsc/src/form/TextInput.js.map +1 -1
- package/out-tsc/src/form/select/Select.js +7 -0
- package/out-tsc/src/form/select/Select.js.map +1 -1
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/layout/Dialog.js +3 -4
- package/out-tsc/src/layout/Dialog.js.map +1 -1
- package/out-tsc/src/list/RunList.js +2 -2
- package/out-tsc/src/list/RunList.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +101 -44
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/live/ContactDetails.js +7 -0
- package/out-tsc/src/live/ContactDetails.js.map +1 -1
- package/out-tsc/src/live/ContactNameFetch.js +1 -1
- package/out-tsc/src/live/ContactNameFetch.js.map +1 -1
- package/out-tsc/src/webchat/index.js +0 -11
- package/out-tsc/src/webchat/index.js.map +1 -1
- package/out-tsc/test/NodeHelper.js +25 -27
- package/out-tsc/test/NodeHelper.js.map +1 -1
- package/out-tsc/test/nodes/split_by_llm.test.js +12 -4
- package/out-tsc/test/nodes/split_by_llm.test.js.map +1 -1
- package/out-tsc/test/nodes/split_by_llm_categorize.test.js +101 -91
- package/out-tsc/test/nodes/split_by_llm_categorize.test.js.map +1 -1
- package/out-tsc/test/nodes/split_by_random.test.js +120 -112
- package/out-tsc/test/nodes/split_by_random.test.js.map +1 -1
- package/out-tsc/test/nodes/wait_for_digits.test.js +131 -111
- package/out-tsc/test/nodes/wait_for_digits.test.js.map +1 -1
- package/out-tsc/test/nodes/wait_for_response.test.js +549 -85
- package/out-tsc/test/nodes/wait_for_response.test.js.map +1 -1
- package/out-tsc/test/temba-checkbox.test.js +32 -32
- package/out-tsc/test/temba-checkbox.test.js.map +1 -1
- package/out-tsc/test/temba-contact-chat.test.js +2 -1
- package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
- package/out-tsc/test/temba-dropdown.test.js +0 -4
- package/out-tsc/test/temba-dropdown.test.js.map +1 -1
- package/out-tsc/test/temba-flow-editor-node.test.js +9 -4
- package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
- package/out-tsc/test/temba-integration-markdown.test.js +13 -15
- package/out-tsc/test/temba-integration-markdown.test.js.map +1 -1
- package/out-tsc/test/temba-node-editor.test.js +5 -38
- package/out-tsc/test/temba-node-editor.test.js.map +1 -1
- package/out-tsc/test/temba-run-list.test.js +2 -2
- package/out-tsc/test/temba-run-list.test.js.map +1 -1
- package/out-tsc/test/utils.test.js +2 -1
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +6 -2
- package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
- package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
- package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
- package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
- package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
- package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
- package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
- package/screenshots/truth/actions/send_email/render/complex-business-email.png +0 -0
- package/screenshots/truth/actions/send_email/render/empty-body.png +0 -0
- package/screenshots/truth/actions/send_email/render/empty-subject.png +0 -0
- package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
- package/screenshots/truth/actions/send_email/render/multiline-body.png +0 -0
- package/screenshots/truth/actions/send_email/render/multiple-recipients.png +0 -0
- package/screenshots/truth/actions/send_email/render/simple-email.png +0 -0
- package/screenshots/truth/actions/send_email/render/with-expressions.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-without-quick-replies.png +0 -0
- package/screenshots/truth/checkbox/checkbox-label-background-hover.png +0 -0
- package/screenshots/truth/checkbox/checkbox-whitespace-label-no-background-hover.png +0 -0
- package/screenshots/truth/checkbox/checkbox-with-help-text.png +0 -0
- package/screenshots/truth/checkbox/checked.png +0 -0
- package/screenshots/truth/checkbox/default.png +0 -0
- package/screenshots/truth/editor/wait.png +0 -0
- package/screenshots/truth/integration/textinput-markdown-errors.png +0 -0
- package/screenshots/truth/lightbox/img-zoomed.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/information-extraction.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/sentiment-analysis.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/summarization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/translation-task.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/summarization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/translation-task.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/basic-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/custom-input-and-result-name.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/many-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/minimal-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/ab-test-multiple-variants.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/sampling-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/three-way-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/two-bucket-split.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/verification-code.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/basic-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/custom-result-name.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/no-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/short-timeout.png +0 -0
- package/screenshots/truth/run-list/basic.png +0 -0
- package/screenshots/truth/templates/default.png +0 -0
- package/screenshots/truth/wait-for-response/rules-editor.png +0 -0
- package/screenshots/truth/wait-for-response/timeout-editor-unchecked.png +0 -0
- package/screenshots/truth/wait-for-response/timeout-editor.png +0 -0
- package/scripts/dev-data-sync.mjs +182 -0
- package/src/display/Chat.ts +6 -4
- package/src/events.ts +6 -6
- package/src/flow/CanvasNode.ts +89 -79
- package/src/flow/Editor.ts +1 -0
- package/src/flow/NodeEditor.ts +55 -3
- package/src/flow/actions/add_contact_urn.ts +1 -1
- package/src/flow/actions/set_contact_channel.ts +1 -1
- package/src/flow/actions/set_contact_field.ts +2 -1
- package/src/flow/actions/set_contact_language.ts +3 -1
- package/src/flow/actions/set_contact_name.ts +1 -1
- package/src/flow/actions/set_contact_status.ts +18 -18
- package/src/flow/actions/set_run_result.ts +1 -1
- package/src/flow/nodes/split_by_llm.ts +14 -13
- package/src/flow/nodes/wait_for_response.ts +717 -5
- package/src/flow/operators.ts +215 -0
- package/src/flow/types.ts +10 -2
- package/src/form/ArrayEditor.ts +117 -37
- package/src/form/Checkbox.ts +12 -0
- package/src/form/FieldRenderer.ts +24 -3
- package/src/form/TextInput.ts +19 -1
- package/src/form/select/Select.ts +7 -0
- package/src/interfaces.ts +1 -1
- package/src/layout/Dialog.ts +4 -4
- package/src/list/RunList.ts +2 -2
- package/src/live/ContactChat.ts +128 -67
- package/src/live/ContactDetails.ts +7 -0
- package/src/live/ContactNameFetch.ts +1 -1
- package/src/webchat/index.ts +0 -16
- package/static/api/labels.json +6 -1
- package/test/NodeHelper.ts +38 -40
- package/test/nodes/split_by_llm.test.ts +43 -32
- package/test/nodes/split_by_llm_categorize.test.ts +130 -120
- package/test/nodes/split_by_random.test.ts +136 -128
- package/test/nodes/wait_for_digits.test.ts +147 -127
- package/test/nodes/wait_for_response.test.ts +657 -104
- package/test/temba-checkbox.test.ts +36 -32
- package/test/temba-contact-chat.test.ts +2 -1
- package/test/temba-dropdown.test.ts +0 -12
- package/test/temba-flow-editor-node.test.ts +11 -4
- package/test/temba-integration-markdown.test.ts +16 -17
- package/test/temba-node-editor.test.ts +5 -43
- package/test/temba-run-list.test.ts +2 -2
- package/test/utils.test.ts +2 -1
- package/test-assets/contacts/history.json +4 -7
- package/test-assets/list/runs.json +8 -8
- package/web-dev-mock.mjs +86 -30
- package/web-dev-server.config.mjs +272 -31
- package/screenshots/truth/dropdown/bottom-edge-collision.png +0 -0
- package/screenshots/truth/dropdown/right-edge-collision.png +0 -0
- package/screenshots/truth/editor/send_msg.png +0 -0
- package/screenshots/truth/editor/set_contact_language.png +0 -0
- package/screenshots/truth/editor/set_contact_name.png +0 -0
- package/screenshots/truth/editor/set_run_result.png +0 -0
- package/screenshots/truth/integration/checkbox-markdown-errors.png +0 -0
|
@@ -2,12 +2,219 @@ import replace from '@rollup/plugin-replace';
|
|
|
2
2
|
import { fromRollup } from '@web/dev-server-rollup';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import path from 'path';
|
|
5
|
+
import crypto from 'crypto';
|
|
5
6
|
|
|
6
7
|
// Import the shared flow info generator and Minio functionality
|
|
7
|
-
import { generateFlowInfo, handleMinioUpload,
|
|
8
|
+
import { generateFlowInfo, handleMinioUpload, handleEntityCreation } from './web-dev-mock.mjs';
|
|
9
|
+
|
|
10
|
+
// Development data directory outside project structure
|
|
11
|
+
const DEV_DATA_DIR = '/tmp/temba-dev-data';
|
|
12
|
+
const DEV_FLOWS_DIR = path.join(DEV_DATA_DIR, 'flows');
|
|
13
|
+
const DEV_API_DIR = path.join(DEV_DATA_DIR, 'api');
|
|
14
|
+
|
|
15
|
+
// Setup development data directories and copy defaults if needed
|
|
16
|
+
function setupDevData() {
|
|
17
|
+
// Ensure directories exist
|
|
18
|
+
if (!fs.existsSync(DEV_DATA_DIR)) {
|
|
19
|
+
fs.mkdirSync(DEV_DATA_DIR, { recursive: true });
|
|
20
|
+
}
|
|
21
|
+
if (!fs.existsSync(DEV_FLOWS_DIR)) {
|
|
22
|
+
fs.mkdirSync(DEV_FLOWS_DIR, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
if (!fs.existsSync(DEV_API_DIR)) {
|
|
25
|
+
fs.mkdirSync(DEV_API_DIR, { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Copy default flows if dev flows directory is empty
|
|
29
|
+
const defaultFlowsDir = path.resolve('./demo/data/flows');
|
|
30
|
+
if (fs.existsSync(defaultFlowsDir)) {
|
|
31
|
+
const devFlowFiles = fs.readdirSync(DEV_FLOWS_DIR).filter(f => f.endsWith('.json'));
|
|
32
|
+
if (devFlowFiles.length === 0) {
|
|
33
|
+
const defaultFlowFiles = fs.readdirSync(defaultFlowsDir).filter(f => f.endsWith('.json'));
|
|
34
|
+
console.log(`Copying ${defaultFlowFiles.length} default flow files to development directory...`);
|
|
35
|
+
defaultFlowFiles.forEach(file => {
|
|
36
|
+
fs.copyFileSync(
|
|
37
|
+
path.join(defaultFlowsDir, file),
|
|
38
|
+
path.join(DEV_FLOWS_DIR, file)
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Copy default API files if dev API directory is empty
|
|
45
|
+
const defaultApiDir = path.resolve('./static/api');
|
|
46
|
+
if (fs.existsSync(defaultApiDir)) {
|
|
47
|
+
const devApiFiles = fs.readdirSync(DEV_API_DIR).filter(f => f.endsWith('.json'));
|
|
48
|
+
if (devApiFiles.length === 0) {
|
|
49
|
+
const defaultApiFiles = fs.readdirSync(defaultApiDir).filter(f => f.endsWith('.json'));
|
|
50
|
+
console.log(`Copying ${defaultApiFiles.length} default API files to development directory...`);
|
|
51
|
+
defaultApiFiles.forEach(file => {
|
|
52
|
+
fs.copyFileSync(
|
|
53
|
+
path.join(defaultApiDir, file),
|
|
54
|
+
path.join(DEV_API_DIR, file)
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Get the appropriate file path, preferring dev directory over defaults
|
|
62
|
+
function getDataFilePath(type, filename) {
|
|
63
|
+
const devPath = type === 'flows'
|
|
64
|
+
? path.join(DEV_FLOWS_DIR, filename)
|
|
65
|
+
: path.join(DEV_API_DIR, filename);
|
|
66
|
+
|
|
67
|
+
const defaultPath = type === 'flows'
|
|
68
|
+
? path.resolve(`./demo/data/flows/${filename}`)
|
|
69
|
+
: path.resolve(`./static/api/${filename}`);
|
|
70
|
+
|
|
71
|
+
// Use dev file if it exists, otherwise fall back to default
|
|
72
|
+
return fs.existsSync(devPath) ? devPath : defaultPath;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Handle entity creation using development directory
|
|
76
|
+
function handleDevEntityCreation(entityType, context) {
|
|
77
|
+
const entityConfigs = {
|
|
78
|
+
labels: {
|
|
79
|
+
filename: 'labels.json',
|
|
80
|
+
createEntity: (name) => ({
|
|
81
|
+
uuid: crypto.randomUUID(),
|
|
82
|
+
name: name.trim(),
|
|
83
|
+
count: 0
|
|
84
|
+
}),
|
|
85
|
+
nameField: 'name',
|
|
86
|
+
entityType: 'Label'
|
|
87
|
+
},
|
|
88
|
+
fields: {
|
|
89
|
+
filename: 'fields.json',
|
|
90
|
+
createEntity: (name) => ({
|
|
91
|
+
key: name.trim().toLowerCase().replace(/\s+/g, '_'),
|
|
92
|
+
name: name.trim(),
|
|
93
|
+
type: 'text',
|
|
94
|
+
featured: false,
|
|
95
|
+
priority: 0,
|
|
96
|
+
usages: {
|
|
97
|
+
flows: 0,
|
|
98
|
+
groups: 0,
|
|
99
|
+
campaign_events: 0
|
|
100
|
+
},
|
|
101
|
+
agent_access: 'view',
|
|
102
|
+
label: name.trim(),
|
|
103
|
+
value_type: 'text'
|
|
104
|
+
}),
|
|
105
|
+
nameField: 'name',
|
|
106
|
+
uniqueField: 'key',
|
|
107
|
+
entityType: 'Field'
|
|
108
|
+
},
|
|
109
|
+
groups: {
|
|
110
|
+
filename: 'groups.json',
|
|
111
|
+
createEntity: (name) => ({
|
|
112
|
+
uuid: crypto.randomUUID(),
|
|
113
|
+
name: name.trim(),
|
|
114
|
+
query: null,
|
|
115
|
+
status: 'ready',
|
|
116
|
+
count: 0
|
|
117
|
+
}),
|
|
118
|
+
nameField: 'name',
|
|
119
|
+
entityType: 'Group'
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const config = entityConfigs[entityType];
|
|
124
|
+
|
|
125
|
+
if (!config) {
|
|
126
|
+
context.status = 400;
|
|
127
|
+
context.body = JSON.stringify({ error: `Unsupported entity type: ${entityType}` });
|
|
128
|
+
return Promise.resolve();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return new Promise((resolve) => {
|
|
132
|
+
let body = '';
|
|
133
|
+
|
|
134
|
+
context.req.on('data', chunk => {
|
|
135
|
+
body += chunk.toString();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
context.req.on('end', () => {
|
|
139
|
+
try {
|
|
140
|
+
const requestData = JSON.parse(body);
|
|
141
|
+
const entityName = requestData[config.nameField] || '';
|
|
142
|
+
|
|
143
|
+
if (!entityName.trim()) {
|
|
144
|
+
context.status = 400;
|
|
145
|
+
context.body = JSON.stringify({ error: `${config.entityType} name is required` });
|
|
146
|
+
resolve();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Get the correct file path (dev directory preferred)
|
|
151
|
+
const filePath = getDataFilePath('api', config.filename);
|
|
152
|
+
|
|
153
|
+
// Read existing data file
|
|
154
|
+
let entityData;
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
entityData = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
158
|
+
} catch (error) {
|
|
159
|
+
// If file doesn't exist, create basic structure
|
|
160
|
+
entityData = {
|
|
161
|
+
next: null,
|
|
162
|
+
previous: null,
|
|
163
|
+
results: []
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Check if entity already exists
|
|
168
|
+
const uniqueField = config.uniqueField || config.nameField;
|
|
169
|
+
const checkValue = uniqueField === 'key'
|
|
170
|
+
? entityName.trim().toLowerCase().replace(/\s+/g, '_')
|
|
171
|
+
: entityName.trim().toLowerCase();
|
|
172
|
+
|
|
173
|
+
const existingEntity = entityData.results.find(
|
|
174
|
+
entity => entity[uniqueField].toLowerCase() === checkValue
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
if (existingEntity) {
|
|
178
|
+
// Return existing entity
|
|
179
|
+
context.contentType = 'application/json';
|
|
180
|
+
context.body = JSON.stringify(existingEntity);
|
|
181
|
+
resolve();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Create new entity
|
|
186
|
+
const newEntity = config.createEntity(entityName);
|
|
187
|
+
|
|
188
|
+
// Add to entity data
|
|
189
|
+
entityData.results.push(newEntity);
|
|
190
|
+
|
|
191
|
+
// Write back to the dev directory file
|
|
192
|
+
const devFilePath = path.join(DEV_API_DIR, config.filename);
|
|
193
|
+
fs.writeFileSync(devFilePath, JSON.stringify(entityData, null, 2));
|
|
194
|
+
|
|
195
|
+
// Return the new entity
|
|
196
|
+
context.contentType = 'application/json';
|
|
197
|
+
context.body = JSON.stringify(newEntity);
|
|
198
|
+
context.status = 201;
|
|
199
|
+
|
|
200
|
+
console.log(`📝 ${config.entityType} created:`, newEntity);
|
|
201
|
+
resolve();
|
|
202
|
+
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.error(`Error creating ${entityType}:`, error);
|
|
205
|
+
context.status = 500;
|
|
206
|
+
context.body = JSON.stringify({ error: 'Internal server error' });
|
|
207
|
+
resolve();
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
}
|
|
8
212
|
|
|
9
213
|
const replacePlugin = fromRollup(replace);
|
|
10
214
|
|
|
215
|
+
// Initialize development data on server startup
|
|
216
|
+
setupDevData();
|
|
217
|
+
|
|
11
218
|
// Simple wrapper function to use the shared flow info generator
|
|
12
219
|
function generateFlowMetadata(flowDefinition) {
|
|
13
220
|
return generateFlowInfo(flowDefinition);
|
|
@@ -31,37 +238,51 @@ export default {
|
|
|
31
238
|
if (context.request.method === 'GET' && context.path.startsWith('/api/')) {
|
|
32
239
|
// Map API endpoints to static files
|
|
33
240
|
const apiMappings = {
|
|
34
|
-
'/api/v2/groups.json': '
|
|
35
|
-
'/api/v2/labels.json': '
|
|
36
|
-
'/api/v2/fields.json': '
|
|
37
|
-
'/api/v2/globals.json': '
|
|
38
|
-
'/api/v2/completion.json': '
|
|
39
|
-
'/api/v2/functions.json': '
|
|
40
|
-
'/api/internal/templates.json': '
|
|
41
|
-
'/api/v2/media.json': '
|
|
42
|
-
'/api/v2/users.json': '
|
|
43
|
-
'/api/v2/contacts.json': '
|
|
44
|
-
'/api/v2/optins.json': '
|
|
45
|
-
'/api/v2/topics.json': '
|
|
46
|
-
'/api/v2/languages.json': '
|
|
47
|
-
'/api/v2/workspace.json': '
|
|
48
|
-
'/api/internal/locations.json': '
|
|
49
|
-
'/api/internal/orgs.json': '
|
|
241
|
+
'/api/v2/groups.json': 'groups.json',
|
|
242
|
+
'/api/v2/labels.json': 'labels.json',
|
|
243
|
+
'/api/v2/fields.json': 'fields.json',
|
|
244
|
+
'/api/v2/globals.json': 'globals.json',
|
|
245
|
+
'/api/v2/completion.json': '../mr/docs/en-us/editor.json', // Special case
|
|
246
|
+
'/api/v2/functions.json': 'functions.json',
|
|
247
|
+
'/api/internal/templates.json': 'templates.json',
|
|
248
|
+
'/api/v2/media.json': 'media.json',
|
|
249
|
+
'/api/v2/users.json': 'users.json',
|
|
250
|
+
'/api/v2/contacts.json': 'contacts.json',
|
|
251
|
+
'/api/v2/optins.json': 'optins.json',
|
|
252
|
+
'/api/v2/topics.json': 'topics.json',
|
|
253
|
+
'/api/v2/languages.json': 'languages.json',
|
|
254
|
+
'/api/v2/workspace.json': 'workspace.json',
|
|
255
|
+
'/api/internal/locations.json': 'locations.json',
|
|
256
|
+
'/api/internal/orgs.json': 'orgs.json'
|
|
50
257
|
};
|
|
51
258
|
|
|
52
259
|
// Handle base path without query parameters
|
|
53
260
|
const basePath = context.path.split('?')[0];
|
|
54
|
-
const
|
|
261
|
+
const filename = apiMappings[basePath];
|
|
55
262
|
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
263
|
+
if (filename) {
|
|
264
|
+
let filePath;
|
|
265
|
+
if (filename === '../mr/docs/en-us/editor.json') {
|
|
266
|
+
// Special case for completion endpoint
|
|
267
|
+
filePath = path.resolve('./static/mr/docs/en-us/editor.json');
|
|
268
|
+
} else {
|
|
269
|
+
filePath = getDataFilePath('api', filename);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (fs.existsSync(filePath)) {
|
|
273
|
+
context.contentType = 'application/json';
|
|
274
|
+
context.body = fs.readFileSync(filePath, 'utf-8');
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
60
277
|
}
|
|
61
278
|
|
|
62
279
|
// Handle dynamic flows endpoint
|
|
63
280
|
if (basePath === '/api/v2/flows.json') {
|
|
64
|
-
|
|
281
|
+
// Check dev flows directory first, then fall back to default
|
|
282
|
+
let flowsDir = DEV_FLOWS_DIR;
|
|
283
|
+
if (!fs.existsSync(flowsDir) || fs.readdirSync(flowsDir).filter(f => f.endsWith('.json')).length === 0) {
|
|
284
|
+
flowsDir = path.resolve('./demo/data/flows');
|
|
285
|
+
}
|
|
65
286
|
|
|
66
287
|
if (fs.existsSync(flowsDir)) {
|
|
67
288
|
const files = fs.readdirSync(flowsDir).filter(file => file.endsWith('.json'));
|
|
@@ -93,7 +314,17 @@ export default {
|
|
|
93
314
|
|
|
94
315
|
// Handle label creation
|
|
95
316
|
if (context.request.method === 'POST' && context.path === '/api/v2/labels.json') {
|
|
96
|
-
return
|
|
317
|
+
return handleDevEntityCreation('labels', context);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Handle field creation
|
|
321
|
+
if (context.request.method === 'POST' && context.path === '/api/v2/fields.json') {
|
|
322
|
+
return handleDevEntityCreation('fields', context);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Handle group creation
|
|
326
|
+
if (context.request.method === 'POST' && context.path === '/api/v2/groups.json') {
|
|
327
|
+
return handleDevEntityCreation('groups', context);
|
|
97
328
|
}
|
|
98
329
|
}
|
|
99
330
|
},
|
|
@@ -104,7 +335,11 @@ export default {
|
|
|
104
335
|
|
|
105
336
|
if (context.request.method === 'GET' && context.path === '/api/flows-list') {
|
|
106
337
|
|
|
107
|
-
|
|
338
|
+
// Check dev flows directory first, then fall back to default
|
|
339
|
+
let flowsDir = DEV_FLOWS_DIR;
|
|
340
|
+
if (!fs.existsSync(flowsDir) || fs.readdirSync(flowsDir).filter(f => f.endsWith('.json')).length === 0) {
|
|
341
|
+
flowsDir = path.resolve('./demo/data/flows');
|
|
342
|
+
}
|
|
108
343
|
|
|
109
344
|
if (fs.existsSync(flowsDir)) {
|
|
110
345
|
const files = fs.readdirSync(flowsDir).filter(file => file.endsWith('.json'));
|
|
@@ -132,8 +367,9 @@ export default {
|
|
|
132
367
|
context.contentType = 'application/json';
|
|
133
368
|
if (body) {
|
|
134
369
|
const flowDefinition = JSON.parse(body);
|
|
370
|
+
const flowPath = path.join(DEV_FLOWS_DIR, `${uuid}.json`);
|
|
135
371
|
fs.writeFileSync(
|
|
136
|
-
|
|
372
|
+
flowPath,
|
|
137
373
|
JSON.stringify({ definition: flowDefinition }, null, 2)
|
|
138
374
|
);
|
|
139
375
|
|
|
@@ -192,11 +428,16 @@ export default {
|
|
|
192
428
|
const uuid = parts[3];
|
|
193
429
|
context.contentType = 'application/json';
|
|
194
430
|
|
|
195
|
-
// Read the flow definition from file
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
431
|
+
// Read the flow definition from file (try dev directory first)
|
|
432
|
+
const flowPath = getDataFilePath('flows', `${uuid}.json`);
|
|
433
|
+
|
|
434
|
+
if (!fs.existsSync(flowPath)) {
|
|
435
|
+
context.status = 404;
|
|
436
|
+
context.body = JSON.stringify({ error: 'Flow not found' });
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const flowFileContent = fs.readFileSync(flowPath, 'utf-8');
|
|
200
441
|
|
|
201
442
|
const flowData = JSON.parse(flowFileContent);
|
|
202
443
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|