@nyaruka/temba-components 0.129.6 → 0.129.8
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/.devcontainer/Dockerfile +11 -4
- package/.devcontainer/devcontainer.json +3 -2
- package/.github/workflows/build.yml +4 -14
- package/CHANGELOG.md +25 -1
- package/demo/components/flow/example.html +9 -2
- package/demo/components/flow/index.html +206 -0
- package/demo/components/message-editor/example.html +125 -0
- package/demo/components/textinput/completion.html +1 -0
- package/demo/data/flows/food-order.json +132 -0
- package/demo/data/flows/sample-flow.json +40 -24
- package/demo/index.html +1 -1
- package/dist/temba-components.js +518 -220
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/display/Thumbnail.js +2 -1
- package/out-tsc/src/display/Thumbnail.js.map +1 -1
- package/out-tsc/src/events.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +10 -2
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +245 -22
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/StickyNote.js +1 -1
- package/out-tsc/src/flow/StickyNote.js.map +1 -1
- package/out-tsc/src/flow/actions/call_webhook.js +26 -17
- package/out-tsc/src/flow/actions/call_webhook.js.map +1 -1
- package/out-tsc/src/flow/actions/send_email.js +1 -2
- package/out-tsc/src/flow/actions/send_email.js.map +1 -1
- package/out-tsc/src/flow/actions/send_msg.js +155 -7
- package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
- package/out-tsc/src/flow/types.js.map +1 -1
- package/out-tsc/src/form/ArrayEditor.js +111 -38
- package/out-tsc/src/form/ArrayEditor.js.map +1 -1
- package/out-tsc/src/form/BaseListEditor.js +19 -4
- package/out-tsc/src/form/BaseListEditor.js.map +1 -1
- package/out-tsc/src/form/FormField.js +1 -1
- package/out-tsc/src/form/FormField.js.map +1 -1
- package/out-tsc/src/form/KeyValueEditor.js +1 -1
- package/out-tsc/src/form/KeyValueEditor.js.map +1 -1
- package/out-tsc/src/form/MediaPicker.js +13 -1
- package/out-tsc/src/form/MediaPicker.js.map +1 -1
- package/out-tsc/src/form/MessageEditor.js +422 -0
- package/out-tsc/src/form/MessageEditor.js.map +1 -0
- package/out-tsc/src/form/TextInput.js +12 -5
- package/out-tsc/src/form/TextInput.js.map +1 -1
- package/out-tsc/src/form/select/Select.js +4 -4
- package/out-tsc/src/form/select/Select.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +29 -4
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/temba-modules.js +2 -0
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/test/temba-field-config.test.js +4 -2
- package/out-tsc/test/temba-field-config.test.js.map +1 -1
- package/out-tsc/test/temba-message-editor.test.js +194 -0
- package/out-tsc/test/temba-message-editor.test.js.map +1 -0
- package/out-tsc/test/temba-node-editor.test.js +71 -0
- package/out-tsc/test/temba-node-editor.test.js.map +1 -1
- package/out-tsc/test/temba-select.test.js +1 -1
- package/out-tsc/test/temba-select.test.js.map +1 -1
- package/out-tsc/test/temba-textinput.test.js +16 -0
- package/out-tsc/test/temba-textinput.test.js.map +1 -1
- package/out-tsc/test/temba-webchat.test.js +4 -0
- package/out-tsc/test/temba-webchat.test.js.map +1 -1
- package/out-tsc/test/utils.test.js +2 -8
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +7 -4
- 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/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/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/formfield/markdown-errors.png +0 -0
- package/screenshots/truth/formfield/no-errors.png +0 -0
- package/screenshots/truth/formfield/plain-text-errors.png +0 -0
- package/screenshots/truth/message-editor/autogrow-initial-content.png +0 -0
- package/screenshots/truth/message-editor/default.png +0 -0
- package/screenshots/truth/message-editor/drag-highlight.png +0 -0
- package/screenshots/truth/message-editor/filtered-attachments.png +0 -0
- package/screenshots/truth/message-editor/with-completion.png +0 -0
- package/screenshots/truth/message-editor/with-properties.png +0 -0
- package/screenshots/truth/sticky-note/blue-color.png +0 -0
- package/screenshots/truth/sticky-note/blue.png +0 -0
- package/screenshots/truth/sticky-note/color-picker-expanded.png +0 -0
- package/screenshots/truth/sticky-note/default.png +0 -0
- package/screenshots/truth/sticky-note/gray-color.png +0 -0
- package/screenshots/truth/sticky-note/gray.png +0 -0
- package/screenshots/truth/sticky-note/green-color.png +0 -0
- package/screenshots/truth/sticky-note/green.png +0 -0
- package/screenshots/truth/sticky-note/pink-color.png +0 -0
- package/screenshots/truth/sticky-note/pink.png +0 -0
- package/screenshots/truth/sticky-note/yellow-color.png +0 -0
- package/screenshots/truth/sticky-note/yellow.png +0 -0
- package/screenshots/truth/textinput/autogrow-initial.png +0 -0
- package/screenshots/truth/textinput/input-form.png +0 -0
- package/src/display/Thumbnail.ts +2 -1
- package/src/events.ts +6 -2
- package/src/flow/CanvasNode.ts +10 -2
- package/src/flow/NodeEditor.ts +269 -23
- package/src/flow/StickyNote.ts +1 -1
- package/src/flow/actions/call_webhook.ts +28 -18
- package/src/flow/actions/send_email.ts +1 -2
- package/src/flow/actions/send_msg.ts +178 -7
- package/src/flow/types.ts +21 -2
- package/src/form/ArrayEditor.ts +120 -42
- package/src/form/BaseListEditor.ts +22 -6
- package/src/form/FormField.ts +1 -1
- package/src/form/KeyValueEditor.ts +1 -1
- package/src/form/MediaPicker.ts +13 -1
- package/src/form/MessageEditor.ts +449 -0
- package/src/form/TextInput.ts +15 -7
- package/src/form/select/Select.ts +4 -4
- package/src/live/ContactChat.ts +32 -6
- package/src/store/flow-definition.d.ts +25 -4
- package/static/css/temba-components.css +2 -0
- package/static/mr/docs/en-us/editor.json +2588 -0
- package/stress-test.js +138 -0
- package/temba-modules.ts +2 -0
- package/test/temba-field-config.test.ts +4 -2
- package/test/temba-message-editor.test.ts +300 -0
- package/test/temba-node-editor.test.ts +94 -0
- package/test/temba-select.test.ts +1 -1
- package/test/temba-textinput.test.ts +26 -0
- package/test/temba-webchat.test.ts +5 -0
- package/test/utils.test.ts +2 -13
- package/test-assets/contacts/history.json +20 -2
- package/test-assets/style.css +2 -0
- package/web-dev-mock.mjs +433 -0
- package/web-dev-server.config.mjs +71 -6
- package/web-test-runner.config.mjs +9 -4
package/.devcontainer/Dockerfile
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
FROM "mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye"
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
&& apt-get install chromium fonts-noto-color-emoji -y --no-install-recommends -qq
|
|
5
|
-
|
|
6
|
-
# The rest of our environment
|
|
3
|
+
# The rest of our environment
|
|
7
4
|
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
|
|
8
5
|
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
|
9
6
|
ENV CHROME_PATH=/usr/bin/chromium
|
|
10
7
|
ENV DEBIAN_FRONTEND=noninteractive
|
|
11
8
|
|
|
9
|
+
# Add minio configuration
|
|
10
|
+
ENV MINIO_ENDPOINT=http://minio:9000
|
|
11
|
+
ENV MINIO_PUBLIC_ENDPOINT=http://localhost:9000
|
|
12
|
+
ENV MINIO_ACCESS_KEY=root
|
|
13
|
+
ENV MINIO_SECRET_KEY=tembatemba
|
|
14
|
+
ENV MINIO_BUCKET=temba-attachments
|
|
15
|
+
|
|
16
|
+
RUN apt-get update \
|
|
17
|
+
&& apt-get install chromium fonts-noto-color-emoji dnsutils curl -y --no-install-recommends -qq
|
|
18
|
+
|
|
12
19
|
WORKDIR /workspaces/temba-components
|
|
13
20
|
RUN yarn install
|
|
14
21
|
USER node
|
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
"runArgs": [
|
|
11
11
|
"--name=dev-components",
|
|
12
12
|
"--network=textit_default",
|
|
13
|
-
"--hostname=temba-components"
|
|
13
|
+
"--hostname=temba-components",
|
|
14
|
+
"--add-host=minio:host-gateway"
|
|
14
15
|
],
|
|
15
16
|
"remoteUser": "node",
|
|
16
|
-
"postCreateCommand": "sudo chown -R node /workspaces/temba-components/static/svg && sudo chown node /workspaces/temba-components && sudo chown node /workspaces/temba-components/screenshots && yarn install",
|
|
17
|
+
"postCreateCommand": "sudo chown -R node /workspaces/temba-components/static/svg && sudo chown node /workspaces/temba-components && sudo chown node /workspaces/temba-components/screenshots && yarn install && echo 'Testing minio connection:' && curl -f http://minio:9000/minio/health/live || echo 'Minio connection failed - this is expected if minio is not running'",
|
|
17
18
|
"customizations": {
|
|
18
19
|
"vscode": {
|
|
19
20
|
"extensions": [
|
|
@@ -23,7 +23,6 @@ jobs:
|
|
|
23
23
|
- name: Build and run dev container task
|
|
24
24
|
id: validate
|
|
25
25
|
uses: devcontainers/ci@v0.3
|
|
26
|
-
continue-on-error: true
|
|
27
26
|
with:
|
|
28
27
|
runCmd: |
|
|
29
28
|
yarn validate 2>&1 | tee validate_output.log
|
|
@@ -33,7 +32,7 @@ jobs:
|
|
|
33
32
|
CI=true
|
|
34
33
|
|
|
35
34
|
- name: Extract coverage stats
|
|
36
|
-
if:
|
|
35
|
+
if: success() || failure()
|
|
37
36
|
run: |
|
|
38
37
|
if [ -f validate_output.log ]; then
|
|
39
38
|
echo "Extracting coverage information from validate output..."
|
|
@@ -69,7 +68,7 @@ jobs:
|
|
|
69
68
|
fi
|
|
70
69
|
|
|
71
70
|
- name: Comment coverage on PR
|
|
72
|
-
if: github.event_name == 'pull_request' &&
|
|
71
|
+
if: github.event_name == 'pull_request' && (success() || failure())
|
|
73
72
|
uses: actions/github-script@v7
|
|
74
73
|
with:
|
|
75
74
|
script: |
|
|
@@ -123,7 +122,7 @@ jobs:
|
|
|
123
122
|
}
|
|
124
123
|
|
|
125
124
|
- name: Configure AWS credentials
|
|
126
|
-
if:
|
|
125
|
+
if: success() || failure()
|
|
127
126
|
uses: aws-actions/configure-aws-credentials@v4
|
|
128
127
|
with:
|
|
129
128
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
@@ -131,7 +130,7 @@ jobs:
|
|
|
131
130
|
aws-region: us-east-1
|
|
132
131
|
|
|
133
132
|
- name: Upload coverage report to S3
|
|
134
|
-
if:
|
|
133
|
+
if: success() || failure()
|
|
135
134
|
run: |
|
|
136
135
|
# Check if coverage directory exists
|
|
137
136
|
if [ -d "coverage/lcov-report" ]; then
|
|
@@ -151,15 +150,6 @@ jobs:
|
|
|
151
150
|
echo "No coverage report found to upload"
|
|
152
151
|
fi
|
|
153
152
|
|
|
154
|
-
- name: Check validation result
|
|
155
|
-
run: |
|
|
156
|
-
if [ "${{ steps.validate.outcome }}" != "success" ]; then
|
|
157
|
-
echo "❌ Validation failed"
|
|
158
|
-
exit 1
|
|
159
|
-
else
|
|
160
|
-
echo "✅ Validation passed"
|
|
161
|
-
fi
|
|
162
|
-
|
|
163
153
|
- name: Upload artifacts
|
|
164
154
|
if: failure()
|
|
165
155
|
uses: actions/upload-artifact@v4
|
package/CHANGELOG.md
CHANGED
|
@@ -4,15 +4,39 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
#### [v0.129.8](https://github.com/nyaruka/temba-components/compare/v0.129.6...v0.129.8)
|
|
8
|
+
|
|
9
|
+
- Add support for `run_started` and `run_ended` events in chat history [`#660`](https://github.com/nyaruka/temba-components/pull/660)
|
|
10
|
+
- Fix completion in dev environment [`#659`](https://github.com/nyaruka/temba-components/pull/659)
|
|
11
|
+
- Roll our own flow info generator for dev env [`#658`](https://github.com/nyaruka/temba-components/pull/658)
|
|
12
|
+
- Group updates [`#657`](https://github.com/nyaruka/temba-components/pull/657)
|
|
13
|
+
- Integrate MessageEditor component with flow editor for send_msg action [`#654`](https://github.com/nyaruka/temba-components/pull/654)
|
|
14
|
+
- Fix rendering of airtime transfer events [`#656`](https://github.com/nyaruka/temba-components/pull/656)
|
|
15
|
+
- Update some flow def, show wa templates, fix exit clicks [`#652`](https://github.com/nyaruka/temba-components/pull/652)
|
|
16
|
+
- Flow example list page [`#651`](https://github.com/nyaruka/temba-components/pull/651)
|
|
17
|
+
- Add minio dev support, finish attachment work [`8b1a930`](https://github.com/nyaruka/temba-components/commit/8b1a930ba6f2c87b46cfe7c79af949fe27fa43c8)
|
|
18
|
+
- Add MessageEditor component with tests [`0994c7f`](https://github.com/nyaruka/temba-components/commit/0994c7fa58d8e77741925049934ccca96c85653a)
|
|
19
|
+
- Support multiple flow examples [`932de08`](https://github.com/nyaruka/temba-components/commit/932de08987089145781dd9756ef9a8752f630ccb)
|
|
20
|
+
|
|
7
21
|
#### [v0.129.6](https://github.com/nyaruka/temba-components/compare/v0.129.5...v0.129.6)
|
|
8
22
|
|
|
23
|
+
> 12 August 2025
|
|
24
|
+
|
|
9
25
|
- Fix message event to use ID for chatevent [`#650`](https://github.com/nyaruka/temba-components/pull/650)
|
|
10
26
|
|
|
11
|
-
#### [v0.129.5](https://github.com/nyaruka/temba-components/compare/v0.129.
|
|
27
|
+
#### [v0.129.5](https://github.com/nyaruka/temba-components/compare/v0.129.4...v0.129.5)
|
|
12
28
|
|
|
13
29
|
> 12 August 2025
|
|
14
30
|
|
|
15
31
|
- Don't trigger ref change on internal values change for Select [`#648`](https://github.com/nyaruka/temba-components/pull/648)
|
|
32
|
+
- Fixes for select change events [`cbb301f`](https://github.com/nyaruka/temba-components/commit/cbb301f372e5b7a17193365c2fc9392f4b0c7bf9)
|
|
33
|
+
- Remove unneccessary change [`7ab2e16`](https://github.com/nyaruka/temba-components/commit/7ab2e16686f805592c96f686ef67cbf31882fe3f)
|
|
34
|
+
- Update sample flow formatting [`c5b7554`](https://github.com/nyaruka/temba-components/commit/c5b75540e26b0ea0d775793af4259563af501f82)
|
|
35
|
+
|
|
36
|
+
#### [v0.129.4](https://github.com/nyaruka/temba-components/compare/v0.129.3...v0.129.4)
|
|
37
|
+
|
|
38
|
+
> 11 August 2025
|
|
39
|
+
|
|
16
40
|
- Cleanup unused chat event types and remove some unused properties on other types [`#647`](https://github.com/nyaruka/temba-components/pull/647)
|
|
17
41
|
- Nestable form layouts [`#644`](https://github.com/nyaruka/temba-components/pull/644)
|
|
18
42
|
- Add KeyValueEditor and field config abstraction [`#643`](https://github.com/nyaruka/temba-components/pull/643)
|
|
@@ -36,11 +36,18 @@
|
|
|
36
36
|
</style>
|
|
37
37
|
</head>
|
|
38
38
|
<body>
|
|
39
|
-
<temba-store></temba-store>
|
|
40
|
-
<temba-flow-editor
|
|
39
|
+
<temba-store completion="/api/v2/completion.json"></temba-store>
|
|
40
|
+
<temba-flow-editor id="flow-editor"></temba-flow-editor>
|
|
41
41
|
|
|
42
42
|
<script type="module">
|
|
43
43
|
import '/out-tsc/temba-modules.js';
|
|
44
|
+
|
|
45
|
+
// Get flow parameter from URL, default to 'sample-flow'
|
|
46
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
47
|
+
const flowName = urlParams.get('flow') || 'sample-flow';
|
|
48
|
+
|
|
49
|
+
// Set the flow attribute on the editor
|
|
50
|
+
document.getElementById('flow-editor').setAttribute('flow', flowName);
|
|
44
51
|
</script>
|
|
45
52
|
</body>
|
|
46
53
|
</html>
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en-GB">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<title>Flow Editor Examples</title>
|
|
6
|
+
<link
|
|
7
|
+
href="/static/css/temba-components.css"
|
|
8
|
+
rel="stylesheet"
|
|
9
|
+
type="text/css"
|
|
10
|
+
/>
|
|
11
|
+
<link
|
|
12
|
+
href="https://fonts.googleapis.com/css?family=Roboto+Mono:300|Roboto:300,400,500"
|
|
13
|
+
rel="stylesheet"
|
|
14
|
+
/>
|
|
15
|
+
<link href="../../styles.css" rel="stylesheet" type="text/css" />
|
|
16
|
+
<style>
|
|
17
|
+
.flow-list {
|
|
18
|
+
max-width: 800px;
|
|
19
|
+
margin: 0 auto;
|
|
20
|
+
padding: 40px 20px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.flow-card {
|
|
24
|
+
background: white;
|
|
25
|
+
border: 1px solid #e1e5e9;
|
|
26
|
+
border-radius: 8px;
|
|
27
|
+
padding: 24px;
|
|
28
|
+
margin-bottom: 16px;
|
|
29
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
30
|
+
transition: box-shadow 0.2s ease;
|
|
31
|
+
display: flex;
|
|
32
|
+
justify-content: space-between;
|
|
33
|
+
align-items: center;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.flow-card:hover {
|
|
37
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.flow-title {
|
|
41
|
+
font-size: 1.5em;
|
|
42
|
+
font-weight: 500;
|
|
43
|
+
color: #2c3e50;
|
|
44
|
+
margin: 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.flow-link {
|
|
48
|
+
display: inline-block;
|
|
49
|
+
background: #3498db;
|
|
50
|
+
color: white;
|
|
51
|
+
padding: 12px 24px;
|
|
52
|
+
text-decoration: none;
|
|
53
|
+
border-radius: 4px;
|
|
54
|
+
font-weight: 500;
|
|
55
|
+
transition: background-color 0.2s ease;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.flow-link:hover {
|
|
59
|
+
background: #2980b9;
|
|
60
|
+
color: white;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.back-link {
|
|
64
|
+
display: inline-block;
|
|
65
|
+
margin-bottom: 24px;
|
|
66
|
+
color: #3498db;
|
|
67
|
+
text-decoration: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.back-link:hover {
|
|
71
|
+
text-decoration: underline;
|
|
72
|
+
}
|
|
73
|
+
</style>
|
|
74
|
+
</head>
|
|
75
|
+
<body>
|
|
76
|
+
<div class="flow-list">
|
|
77
|
+
<a href="../../index.html" class="back-link">← Back to Component Demos</a>
|
|
78
|
+
|
|
79
|
+
<h1>Flow Editor Examples</h1>
|
|
80
|
+
<p>
|
|
81
|
+
Choose a flow to open in the Flow Editor. Each flow demonstrates
|
|
82
|
+
different features and capabilities.
|
|
83
|
+
</p>
|
|
84
|
+
|
|
85
|
+
<div id="flow-cards">
|
|
86
|
+
<div class="flow-card">
|
|
87
|
+
<div class="flow-title">Loading flows...</div>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<script type="module">
|
|
93
|
+
// Function to load and display flows dynamically
|
|
94
|
+
async function loadFlows() {
|
|
95
|
+
const flowCardsContainer = document.getElementById('flow-cards');
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
// Get list of flow files from the flows directory API
|
|
99
|
+
const response = await fetch('/api/flows-list');
|
|
100
|
+
const files = await response.json();
|
|
101
|
+
|
|
102
|
+
if (!Array.isArray(files) || files.length === 0) {
|
|
103
|
+
// Fallback: try known flows if directory listing doesn't work
|
|
104
|
+
await loadKnownFlows(flowCardsContainer);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const flows = [];
|
|
109
|
+
|
|
110
|
+
// Load each flow file to get its definition
|
|
111
|
+
for (const fileName of files) {
|
|
112
|
+
const flowId = fileName.replace('.json', '');
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const flowResponse = await fetch(`/demo/data/flows/${fileName}`);
|
|
116
|
+
const flowData = await flowResponse.json();
|
|
117
|
+
const flowName = flowData.definition?.name || flowId;
|
|
118
|
+
|
|
119
|
+
flows.push({
|
|
120
|
+
id: flowId,
|
|
121
|
+
name: flowName
|
|
122
|
+
});
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.warn(`Failed to load flow ${fileName}:`, error);
|
|
125
|
+
// Add with fallback name
|
|
126
|
+
flows.push({
|
|
127
|
+
id: flowId,
|
|
128
|
+
name: flowId
|
|
129
|
+
.replace('-', ' ')
|
|
130
|
+
.replace(/\b\w/g, (l) => l.toUpperCase())
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
displayFlows(flows, flowCardsContainer);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.warn(
|
|
138
|
+
'Failed to load flows from directory, using fallback:',
|
|
139
|
+
error
|
|
140
|
+
);
|
|
141
|
+
// await loadKnownFlows(flowCardsContainer);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Fallback function for known flows
|
|
146
|
+
async function loadKnownFlows(container) {
|
|
147
|
+
const knownFlows = ['sample-flow', 'food-order'];
|
|
148
|
+
const flows = [];
|
|
149
|
+
|
|
150
|
+
for (const flowId of knownFlows) {
|
|
151
|
+
try {
|
|
152
|
+
const response = await fetch(`/demo/data/flows/${flowId}.json`);
|
|
153
|
+
const flowData = await response.json();
|
|
154
|
+
const flowName = flowData.definition?.name || flowId;
|
|
155
|
+
|
|
156
|
+
flows.push({
|
|
157
|
+
id: flowId,
|
|
158
|
+
name: flowName
|
|
159
|
+
});
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.warn(`Failed to load flow ${flowId}:`, error);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
displayFlows(flows, container);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Function to display flows in the UI
|
|
169
|
+
function displayFlows(flows, container) {
|
|
170
|
+
if (flows.length === 0) {
|
|
171
|
+
container.innerHTML = `
|
|
172
|
+
<div class="flow-card">
|
|
173
|
+
<div class="flow-title">No flows found</div>
|
|
174
|
+
</div>
|
|
175
|
+
`;
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
container.innerHTML = flows
|
|
180
|
+
.map(
|
|
181
|
+
(flow) => `
|
|
182
|
+
<div class="flow-card">
|
|
183
|
+
<div class="flow-title">${escapeHtml(flow.name)}</div>
|
|
184
|
+
<a href="example.html?flow=${encodeURIComponent(
|
|
185
|
+
flow.id
|
|
186
|
+
)}" class="flow-link">
|
|
187
|
+
Open Flow
|
|
188
|
+
</a>
|
|
189
|
+
</div>
|
|
190
|
+
`
|
|
191
|
+
)
|
|
192
|
+
.join('');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Helper function to escape HTML
|
|
196
|
+
function escapeHtml(text) {
|
|
197
|
+
const div = document.createElement('div');
|
|
198
|
+
div.textContent = text;
|
|
199
|
+
return div.innerHTML;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Load flows when the page loads
|
|
203
|
+
loadFlows();
|
|
204
|
+
</script>
|
|
205
|
+
</body>
|
|
206
|
+
</html>
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en-GB">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<title>Message Editor Examples</title>
|
|
6
|
+
<link
|
|
7
|
+
href="/static/css/temba-components.css"
|
|
8
|
+
rel="stylesheet"
|
|
9
|
+
type="text/css"
|
|
10
|
+
/>
|
|
11
|
+
<link
|
|
12
|
+
href="https://fonts.googleapis.com/css?family=Roboto+Mono:300|Roboto:300,400,500"
|
|
13
|
+
rel="stylesheet"
|
|
14
|
+
/>
|
|
15
|
+
<link href="/demo/static/css/styles.css" rel="stylesheet" type="text/css" />
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<h1>Message Editor Examples</h1>
|
|
19
|
+
|
|
20
|
+
<p>
|
|
21
|
+
<a href="/demo/index.html">← Back to main demo</a>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
<div class="example">
|
|
25
|
+
<h3>Basic Message Editor</h3>
|
|
26
|
+
<p>A composed component that combines text completion and media picker</p>
|
|
27
|
+
<temba-message-editor
|
|
28
|
+
name="message"
|
|
29
|
+
placeholder="Type your message here..."
|
|
30
|
+
label="Message"
|
|
31
|
+
></temba-message-editor>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<div class="example">
|
|
35
|
+
<h3>Message Editor with Value</h3>
|
|
36
|
+
<p>Pre-populated with a message</p>
|
|
37
|
+
<temba-message-editor
|
|
38
|
+
name="message2"
|
|
39
|
+
value="Hello @contact.name, your order is ready!"
|
|
40
|
+
placeholder="Type your message here..."
|
|
41
|
+
label="Message with Completion"
|
|
42
|
+
></temba-message-editor>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div class="example">
|
|
46
|
+
<h3>Message Editor with Attachments</h3>
|
|
47
|
+
<p>Pre-populated with mixed attachment types (static and runtime)</p>
|
|
48
|
+
<temba-message-editor
|
|
49
|
+
name="message3"
|
|
50
|
+
value="Check out this document and image"
|
|
51
|
+
placeholder="Type your message here..."
|
|
52
|
+
label="Message with Attachments"
|
|
53
|
+
attachments='["image/jpeg:http://example.com/photo.jpg", "application/pdf:http://example.com/doc.pdf", "image:@fields.profile_pic", "video:@fields.intro_video"]'
|
|
54
|
+
></temba-message-editor>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<div class="example">
|
|
58
|
+
<h3>Message Editor with File Type Restrictions</h3>
|
|
59
|
+
<p>Only accepts image files</p>
|
|
60
|
+
<temba-message-editor
|
|
61
|
+
name="message4"
|
|
62
|
+
placeholder="Type your message and attach images..."
|
|
63
|
+
label="Images Only"
|
|
64
|
+
accept="image/*"
|
|
65
|
+
max-attachments="5"
|
|
66
|
+
></temba-message-editor>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div class="example">
|
|
70
|
+
<h3>Message Editor with Counter</h3>
|
|
71
|
+
<p>With GSM character counter</p>
|
|
72
|
+
<temba-message-editor
|
|
73
|
+
name="message5"
|
|
74
|
+
value="This message has a GSM character counter"
|
|
75
|
+
placeholder="Type your message..."
|
|
76
|
+
label="Message with Counter"
|
|
77
|
+
counter="temba-charcount"
|
|
78
|
+
gsm
|
|
79
|
+
></temba-message-editor>
|
|
80
|
+
<temba-charcount text="count this text"></temba-charcount>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<div class="example">
|
|
84
|
+
<h3>Compact Message Editor</h3>
|
|
85
|
+
<p>Smaller minimum height</p>
|
|
86
|
+
<temba-message-editor
|
|
87
|
+
name="message6"
|
|
88
|
+
placeholder="Quick message..."
|
|
89
|
+
label="Compact Editor"
|
|
90
|
+
min-height="40"
|
|
91
|
+
></temba-message-editor>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<div class="example">
|
|
95
|
+
<h3>Widget Only (No Label)</h3>
|
|
96
|
+
<p>Just the widget without field wrapper</p>
|
|
97
|
+
<temba-message-editor
|
|
98
|
+
name="message7"
|
|
99
|
+
placeholder="Widget only mode..."
|
|
100
|
+
widget-only
|
|
101
|
+
></temba-message-editor>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<script type="module">
|
|
105
|
+
import '/out-tsc/temba-modules.js';
|
|
106
|
+
|
|
107
|
+
// Add some event listeners to show how the component works
|
|
108
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
109
|
+
const editors = document.querySelectorAll('temba-message-editor');
|
|
110
|
+
editors.forEach(editor => {
|
|
111
|
+
editor.addEventListener('change', (e) => {
|
|
112
|
+
console.log(`Message Editor "${editor.name}" changed:`, {
|
|
113
|
+
value: editor.value,
|
|
114
|
+
attachments: editor.attachments
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
editor.addEventListener('loading', (e) => {
|
|
119
|
+
console.log(`Message Editor "${editor.name}" loading:`, e.detail.loading);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
</script>
|
|
124
|
+
</body>
|
|
125
|
+
</html>
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
{
|
|
2
|
+
"definition": {
|
|
3
|
+
"_ui": {
|
|
4
|
+
"nodes": {
|
|
5
|
+
"b01610c8-d6dc-4bdb-9439-5713cdcf9afa": {
|
|
6
|
+
"position": {
|
|
7
|
+
"left": 60,
|
|
8
|
+
"top": 20
|
|
9
|
+
},
|
|
10
|
+
"type": "execute_actions"
|
|
11
|
+
},
|
|
12
|
+
"3b28a90f-27be-4753-b0c0-3e98b83f0627": {
|
|
13
|
+
"type": "wait_for_response",
|
|
14
|
+
"position": {
|
|
15
|
+
"left": 80,
|
|
16
|
+
"top": 240
|
|
17
|
+
},
|
|
18
|
+
"config": {
|
|
19
|
+
"cases": {}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"stickies": {
|
|
24
|
+
"b1cb8cfa-8432-444c-bd48-3fd2cb3a014f": {
|
|
25
|
+
"position": {
|
|
26
|
+
"left": 340,
|
|
27
|
+
"top": 120
|
|
28
|
+
},
|
|
29
|
+
"title": "Long awaited note",
|
|
30
|
+
"body": "This is the body of a note that I have been waiting to write for a very long time. Now I am able to add it to my flow and that makes me very happy.",
|
|
31
|
+
"color": "blue"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"expire_after_minutes": 10080,
|
|
36
|
+
"language": "eng",
|
|
37
|
+
"localization": {},
|
|
38
|
+
"name": "Food Order",
|
|
39
|
+
"nodes": [
|
|
40
|
+
{
|
|
41
|
+
"uuid": "b01610c8-d6dc-4bdb-9439-5713cdcf9afa",
|
|
42
|
+
"actions": [
|
|
43
|
+
{
|
|
44
|
+
"uuid": "90957b4e-05a4-4d00-8163-47046f81246d",
|
|
45
|
+
"type": "send_msg",
|
|
46
|
+
"text": "Would you like chicken or fish?",
|
|
47
|
+
"attachments": [
|
|
48
|
+
"image/jpeg:http://localhost:9000/temba-attachments/816f8797-c929-47a8-a1ad-9a33f0123406-IMG_0917.jpeg",
|
|
49
|
+
"image/jpeg:http://localhost:9000/temba-attachments/de0f23fc-2d71-4a93-90d3-729b1ad65cd2-IMG_3208.jpeg"
|
|
50
|
+
],
|
|
51
|
+
"quick_replies": [
|
|
52
|
+
"Fish",
|
|
53
|
+
"Chicken",
|
|
54
|
+
"arst"
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"exits": [
|
|
59
|
+
{
|
|
60
|
+
"uuid": "87e6cd04-4dd7-44e7-b517-3f3fa63e837e",
|
|
61
|
+
"destination_uuid": "3b28a90f-27be-4753-b0c0-3e98b83f0627"
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"uuid": "3b28a90f-27be-4753-b0c0-3e98b83f0627",
|
|
67
|
+
"actions": [],
|
|
68
|
+
"router": {
|
|
69
|
+
"type": "switch",
|
|
70
|
+
"default_category_uuid": "706df9a8-9f55-446f-9212-2493da1b42c2",
|
|
71
|
+
"cases": [
|
|
72
|
+
{
|
|
73
|
+
"arguments": [
|
|
74
|
+
"chicken 🐔"
|
|
75
|
+
],
|
|
76
|
+
"type": "has_any_word",
|
|
77
|
+
"uuid": "a0046472-2a86-4c1f-b02d-a63a98abb5e3",
|
|
78
|
+
"category_uuid": "6f4689dd-6a8b-454c-a1db-192de1c283ee"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"arguments": [
|
|
82
|
+
"fish 🐟"
|
|
83
|
+
],
|
|
84
|
+
"type": "has_any_word",
|
|
85
|
+
"uuid": "2f8fbf02-80cd-4b26-b7d7-709e8681d2ce",
|
|
86
|
+
"category_uuid": "390bbb17-49fd-4253-ac7f-6a27ef240b56"
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
"categories": [
|
|
90
|
+
{
|
|
91
|
+
"uuid": "6f4689dd-6a8b-454c-a1db-192de1c283ee",
|
|
92
|
+
"name": "🐔",
|
|
93
|
+
"exit_uuid": "9e84e680-a710-4894-a838-dd22a8dcc341"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"uuid": "390bbb17-49fd-4253-ac7f-6a27ef240b56",
|
|
97
|
+
"name": "🐟",
|
|
98
|
+
"exit_uuid": "12043e9e-7aa0-41fd-8f04-e0d42a0c2099"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"uuid": "706df9a8-9f55-446f-9212-2493da1b42c2",
|
|
102
|
+
"name": "Other",
|
|
103
|
+
"exit_uuid": "79b6a4e6-1a00-44cc-9fd4-2d9ba2a394e0"
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"operand": "@input.text",
|
|
107
|
+
"wait": {
|
|
108
|
+
"type": "msg"
|
|
109
|
+
},
|
|
110
|
+
"result_name": "Order"
|
|
111
|
+
},
|
|
112
|
+
"exits": [
|
|
113
|
+
{
|
|
114
|
+
"uuid": "9e84e680-a710-4894-a838-dd22a8dcc341"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"uuid": "12043e9e-7aa0-41fd-8f04-e0d42a0c2099",
|
|
118
|
+
"destination_uuid": null
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"uuid": "79b6a4e6-1a00-44cc-9fd4-2d9ba2a394e0",
|
|
122
|
+
"destination_uuid": null
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
"spec_version": "14.3.0",
|
|
128
|
+
"type": "messaging",
|
|
129
|
+
"uuid": "8f1fa2e3-740a-4f06-b67b-d521643eb52b",
|
|
130
|
+
"revision": 50
|
|
131
|
+
}
|
|
132
|
+
}
|