@nyaruka/temba-components 0.129.8 → 0.129.9
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 +27 -3
- package/demo/data/flows/sample-flow.json +186 -96
- package/dist/temba-components.js +414 -351
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/events.js.map +1 -1
- package/out-tsc/src/excellent/helpers.js +2 -2
- package/out-tsc/src/excellent/helpers.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +25 -7
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +11 -1
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +133 -290
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/actions/add_input_labels.js +40 -0
- package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
- package/out-tsc/src/flow/actions/call_llm.js +56 -3
- package/out-tsc/src/flow/actions/call_llm.js.map +1 -1
- package/out-tsc/src/flow/actions/call_webhook.js +1 -1
- package/out-tsc/src/flow/actions/call_webhook.js.map +1 -1
- package/out-tsc/src/flow/actions/open_ticket.js +65 -3
- package/out-tsc/src/flow/actions/open_ticket.js.map +1 -1
- package/out-tsc/src/flow/actions/set_run_result.js +75 -0
- package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
- package/out-tsc/src/flow/config.js +4 -0
- package/out-tsc/src/flow/config.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +227 -0
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_ticket.js +18 -0
- package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_response.js +27 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
- package/out-tsc/src/flow/types.js +0 -65
- package/out-tsc/src/flow/types.js.map +1 -1
- package/out-tsc/src/form/ArrayEditor.js +18 -61
- package/out-tsc/src/form/ArrayEditor.js.map +1 -1
- package/out-tsc/src/form/FieldRenderer.js +305 -0
- package/out-tsc/src/form/FieldRenderer.js.map +1 -0
- package/out-tsc/src/form/FormField.js +3 -3
- package/out-tsc/src/form/FormField.js.map +1 -1
- package/out-tsc/src/form/TextInput.js +1 -1
- package/out-tsc/src/form/TextInput.js.map +1 -1
- package/out-tsc/src/form/select/Select.js +48 -20
- package/out-tsc/src/form/select/Select.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +39 -13
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/markdown.js +13 -11
- package/out-tsc/src/markdown.js.map +1 -1
- package/out-tsc/test/ActionHelper.js +2 -0
- package/out-tsc/test/ActionHelper.js.map +1 -1
- package/out-tsc/test/NodeHelper.js +148 -0
- package/out-tsc/test/NodeHelper.js.map +1 -0
- package/out-tsc/test/actions/call_llm.test.js +103 -0
- package/out-tsc/test/actions/call_llm.test.js.map +1 -0
- package/out-tsc/test/nodes/split_by_llm_categorize.test.js +532 -0
- package/out-tsc/test/nodes/split_by_llm_categorize.test.js.map +1 -0
- package/out-tsc/test/nodes/split_by_random.test.js +150 -0
- package/out-tsc/test/nodes/split_by_random.test.js.map +1 -0
- package/out-tsc/test/nodes/wait_for_digits.test.js +150 -0
- package/out-tsc/test/nodes/wait_for_digits.test.js.map +1 -0
- package/out-tsc/test/nodes/wait_for_response.test.js +171 -0
- package/out-tsc/test/nodes/wait_for_response.test.js.map +1 -0
- package/out-tsc/test/temba-add-input-labels.test.js +70 -0
- package/out-tsc/test/temba-add-input-labels.test.js.map +1 -0
- package/out-tsc/test/temba-field-renderer.test.js +296 -0
- package/out-tsc/test/temba-field-renderer.test.js.map +1 -0
- package/out-tsc/test/temba-markdown.test.js +1 -1
- package/out-tsc/test/temba-markdown.test.js.map +1 -1
- package/out-tsc/test/temba-node-editor.test.js +400 -0
- package/out-tsc/test/temba-node-editor.test.js.map +1 -1
- package/out-tsc/test/temba-select.test.js +6 -3
- package/out-tsc/test/temba-select.test.js.map +1 -1
- package/out-tsc/test/temba-webchat.test.js +1 -1
- package/out-tsc/test/temba-webchat.test.js.map +1 -1
- package/package.json +1 -1
- 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/call_llm/editor/information-extraction.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/sentiment-analysis.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/summarization.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/translation-task.png +0 -0
- package/screenshots/truth/actions/call_llm/render/information-extraction.png +0 -0
- package/screenshots/truth/actions/call_llm/render/sentiment-analysis.png +0 -0
- package/screenshots/truth/actions/call_llm/render/summarization.png +0 -0
- package/screenshots/truth/actions/call_llm/render/translation-task.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/remove-from-all-groups.png +0 -0
- package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiple-recipients.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/editor/router.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/editor/wait.png +0 -0
- package/screenshots/truth/field-renderer/checkbox-checked.png +0 -0
- package/screenshots/truth/field-renderer/checkbox-unchecked.png +0 -0
- package/screenshots/truth/field-renderer/checkbox-with-errors.png +0 -0
- package/screenshots/truth/field-renderer/context-comparison.png +0 -0
- package/screenshots/truth/field-renderer/key-value-with-label.png +0 -0
- package/screenshots/truth/field-renderer/message-editor-with-label.png +0 -0
- package/screenshots/truth/field-renderer/select-multi.png +0 -0
- package/screenshots/truth/field-renderer/select-no-label.png +0 -0
- package/screenshots/truth/field-renderer/select-with-label.png +0 -0
- package/screenshots/truth/field-renderer/text-evaluated.png +0 -0
- package/screenshots/truth/field-renderer/text-no-label.png +0 -0
- package/screenshots/truth/field-renderer/text-with-errors.png +0 -0
- package/screenshots/truth/field-renderer/text-with-label.png +0 -0
- package/screenshots/truth/field-renderer/textarea-evaluated.png +0 -0
- package/screenshots/truth/field-renderer/textarea-with-label.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/omnibox/selected.png +0 -0
- package/screenshots/truth/select/functions.png +0 -0
- package/screenshots/truth/select/multi-with-endpoint.png +0 -0
- package/screenshots/truth/select/search-enabled.png +0 -0
- package/src/events.ts +8 -1
- package/src/excellent/helpers.ts +2 -2
- package/src/flow/CanvasNode.ts +22 -1
- package/src/flow/Editor.ts +12 -1
- package/src/flow/NodeEditor.ts +186 -374
- package/src/flow/actions/add_input_labels.ts +45 -0
- package/src/flow/actions/call_llm.ts +57 -3
- package/src/flow/actions/call_webhook.ts +1 -1
- package/src/flow/actions/open_ticket.ts +74 -3
- package/src/flow/actions/set_run_result.ts +83 -0
- package/src/flow/config.ts +4 -0
- package/src/flow/nodes/split_by_llm_categorize.ts +277 -0
- package/src/flow/nodes/split_by_ticket.ts +19 -0
- package/src/flow/nodes/wait_for_response.ts +28 -1
- package/src/flow/types.ts +26 -127
- package/src/form/ArrayEditor.ts +34 -82
- package/src/form/FieldRenderer.ts +465 -0
- package/src/form/FormField.ts +3 -3
- package/src/form/TextInput.ts +1 -1
- package/src/form/select/Select.ts +51 -20
- package/src/live/ContactChat.ts +39 -15
- package/src/markdown.ts +19 -11
- package/src/store/flow-definition.d.ts +5 -2
- package/static/api/labels.json +31 -0
- package/static/api/topics.json +24 -9
- package/static/api/users.json +35 -16
- package/static/css/temba-components.css +3 -3
- package/stress-test.js +18 -13
- package/test/ActionHelper.ts +2 -0
- package/test/NodeHelper.ts +184 -0
- package/test/actions/call_llm.test.ts +137 -0
- package/test/nodes/README.md +78 -0
- package/test/nodes/split_by_llm_categorize.test.ts +698 -0
- package/test/nodes/split_by_random.test.ts +177 -0
- package/test/nodes/wait_for_digits.test.ts +176 -0
- package/test/nodes/wait_for_response.test.ts +206 -0
- package/test/temba-add-input-labels.test.ts +87 -0
- package/test/temba-field-renderer.test.ts +482 -0
- package/test/temba-markdown.test.ts +1 -1
- package/test/temba-node-editor.test.ts +496 -0
- package/test/temba-select.test.ts +6 -6
- package/test/temba-webchat.test.ts +1 -1
- package/test-assets/select/llms.json +18 -0
- package/web-dev-mock.mjs +96 -6
- package/web-dev-server.config.mjs +29 -7
- package/test/temba-flow-editor.test.ts.backup +0 -563
- package/test/temba-utils-index.test.ts.backup +0 -1737
package/src/flow/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TemplateResult } from 'lit-html';
|
|
2
|
-
import { Action } from '../store/flow-definition';
|
|
2
|
+
import { Action, Node } from '../store/flow-definition';
|
|
3
3
|
|
|
4
4
|
export interface ValidationResult {
|
|
5
5
|
valid: boolean;
|
|
@@ -65,39 +65,16 @@ export interface SliderAttributes {
|
|
|
65
65
|
range?: boolean;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
export type WidgetConfig =
|
|
70
|
-
| { type: 'temba-textinput'; attributes?: TextInputAttributes }
|
|
71
|
-
| { type: 'temba-completion'; attributes?: CompletionAttributes }
|
|
72
|
-
| { type: 'temba-select'; attributes?: SelectAttributes }
|
|
73
|
-
| { type: 'temba-checkbox'; attributes?: CheckboxAttributes }
|
|
74
|
-
| { type: 'temba-slider'; attributes?: SliderAttributes }
|
|
75
|
-
| { type: string; attributes?: { [key: string]: any } }; // Generic fallback
|
|
68
|
+
export interface FormData extends Record<string, any> {}
|
|
76
69
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
required?: boolean;
|
|
83
|
-
maxLength?: number;
|
|
84
|
-
minLength?: number;
|
|
85
|
-
pattern?: string;
|
|
86
|
-
|
|
87
|
-
// Widget configuration
|
|
88
|
-
widget: WidgetConfig;
|
|
89
|
-
|
|
90
|
-
// Conditional behavior based on other field values
|
|
91
|
-
conditions?: {
|
|
92
|
-
// When to show this field
|
|
93
|
-
visible?: (formData: any) => boolean;
|
|
94
|
-
|
|
95
|
-
// When this field is disabled
|
|
96
|
-
disabled?: (formData: any) => boolean;
|
|
97
|
-
};
|
|
70
|
+
export interface FormConfig {
|
|
71
|
+
form?: Record<string, FieldConfig>;
|
|
72
|
+
layout?: LayoutItem[];
|
|
73
|
+
sanitize?: (formData: FormData) => void;
|
|
74
|
+
validate?: (formData: FormData) => ValidationResult;
|
|
98
75
|
}
|
|
99
76
|
|
|
100
|
-
export interface NodeConfig {
|
|
77
|
+
export interface NodeConfig extends FormConfig {
|
|
101
78
|
type: string;
|
|
102
79
|
name?: string;
|
|
103
80
|
color?: string;
|
|
@@ -108,22 +85,28 @@ export interface NodeConfig {
|
|
|
108
85
|
operand?: string;
|
|
109
86
|
configurable?: boolean; // can the rules be configured in the UI
|
|
110
87
|
rules?: {
|
|
111
|
-
type:
|
|
88
|
+
type:
|
|
89
|
+
| 'has_number_between'
|
|
90
|
+
| 'has_string'
|
|
91
|
+
| 'has_value'
|
|
92
|
+
| 'has_not_value'
|
|
93
|
+
| 'has_text';
|
|
112
94
|
arguments: string[];
|
|
113
95
|
categoryName: string;
|
|
114
96
|
}[];
|
|
115
97
|
};
|
|
116
|
-
|
|
117
|
-
toFormData?: (node:
|
|
118
|
-
fromFormData?: (formData:
|
|
98
|
+
|
|
99
|
+
toFormData?: (node: Node) => FormData;
|
|
100
|
+
fromFormData?: (formData: FormData, originalNode: Node) => Node;
|
|
101
|
+
render?: (node: Node) => TemplateResult;
|
|
119
102
|
}
|
|
120
103
|
|
|
121
104
|
// New field configuration system for generic form generation
|
|
122
105
|
export interface BaseFieldConfig {
|
|
123
106
|
label?: string;
|
|
124
107
|
required?: boolean;
|
|
125
|
-
evaluated?: boolean;
|
|
126
|
-
dependsOn?: string[];
|
|
108
|
+
evaluated?: boolean;
|
|
109
|
+
dependsOn?: string[];
|
|
127
110
|
computeValue?: (
|
|
128
111
|
values: Record<string, any>,
|
|
129
112
|
currentValue: any,
|
|
@@ -137,7 +120,7 @@ export interface BaseFieldConfig {
|
|
|
137
120
|
helpText?: string;
|
|
138
121
|
|
|
139
122
|
// Layout properties
|
|
140
|
-
maxWidth?: string;
|
|
123
|
+
maxWidth?: string;
|
|
141
124
|
|
|
142
125
|
// Conditional rendering
|
|
143
126
|
conditions?: {
|
|
@@ -160,7 +143,7 @@ export interface TextareaFieldConfig extends BaseFieldConfig {
|
|
|
160
143
|
|
|
161
144
|
export interface SelectFieldConfig extends BaseFieldConfig {
|
|
162
145
|
type: 'select';
|
|
163
|
-
options
|
|
146
|
+
options?: string[] | { value: string; label: string }[];
|
|
164
147
|
multi?: boolean;
|
|
165
148
|
clearable?: boolean;
|
|
166
149
|
searchable?: boolean;
|
|
@@ -171,7 +154,10 @@ export interface SelectFieldConfig extends BaseFieldConfig {
|
|
|
171
154
|
nameKey?: string;
|
|
172
155
|
endpoint?: string;
|
|
173
156
|
emails?: boolean;
|
|
157
|
+
getName?: (item: any) => string;
|
|
174
158
|
flavor?: 'small' | 'large';
|
|
159
|
+
createArbitraryOption?: (input: string, options: any[]) => any;
|
|
160
|
+
allowCreate?: boolean;
|
|
175
161
|
}
|
|
176
162
|
|
|
177
163
|
export interface KeyValueFieldConfig extends BaseFieldConfig {
|
|
@@ -256,7 +242,7 @@ export type LayoutItem =
|
|
|
256
242
|
| GroupLayoutConfig
|
|
257
243
|
| string; // string is shorthand for field
|
|
258
244
|
|
|
259
|
-
export interface ActionConfig {
|
|
245
|
+
export interface ActionConfig extends FormConfig {
|
|
260
246
|
name: string;
|
|
261
247
|
color: string;
|
|
262
248
|
evaluated?: string[];
|
|
@@ -265,13 +251,8 @@ export interface ActionConfig {
|
|
|
265
251
|
form?: Record<string, FieldConfig>;
|
|
266
252
|
layout?: LayoutItem[]; // optional layout configuration - array of layout items
|
|
267
253
|
|
|
268
|
-
// Action editor configuration (legacy)
|
|
269
|
-
// Form-level transformations
|
|
270
|
-
sanitize?: (formData: any) => any;
|
|
271
254
|
toFormData?: (action: Action) => any;
|
|
272
255
|
fromFormData?: (formData: any) => Action;
|
|
273
|
-
|
|
274
|
-
validate?: (action: Action) => ValidationResult;
|
|
275
256
|
}
|
|
276
257
|
|
|
277
258
|
export const COLORS = {
|
|
@@ -287,85 +268,3 @@ export const COLORS = {
|
|
|
287
268
|
add: '#309c42',
|
|
288
269
|
remove: '#e74c3c'
|
|
289
270
|
};
|
|
290
|
-
|
|
291
|
-
// Default property type mappings
|
|
292
|
-
export function getDefaultComponent(value: any): WidgetConfig['type'] {
|
|
293
|
-
if (typeof value === 'boolean') {
|
|
294
|
-
return 'temba-checkbox';
|
|
295
|
-
}
|
|
296
|
-
if (typeof value === 'number') {
|
|
297
|
-
return 'temba-textinput';
|
|
298
|
-
}
|
|
299
|
-
if (Array.isArray(value)) {
|
|
300
|
-
return 'temba-select'; // For arrays, use multi-select
|
|
301
|
-
}
|
|
302
|
-
// Default to text input for strings and unknown types
|
|
303
|
-
return 'temba-textinput';
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Get component properties for default mappings with proper typing
|
|
307
|
-
export function getDefaultComponentProps(value: any): PropertyConfig {
|
|
308
|
-
if (typeof value === 'boolean') {
|
|
309
|
-
return {
|
|
310
|
-
widget: { type: 'temba-checkbox' }
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
if (typeof value === 'number') {
|
|
314
|
-
return {
|
|
315
|
-
widget: {
|
|
316
|
-
type: 'temba-textinput',
|
|
317
|
-
attributes: { type: 'number' }
|
|
318
|
-
}
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
if (Array.isArray(value)) {
|
|
322
|
-
if (value.length > 0 && typeof value[0] === 'string') {
|
|
323
|
-
return {
|
|
324
|
-
widget: {
|
|
325
|
-
type: 'temba-select',
|
|
326
|
-
attributes: { multi: true, tags: true }
|
|
327
|
-
}
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
return {
|
|
331
|
-
widget: {
|
|
332
|
-
type: 'temba-select',
|
|
333
|
-
attributes: { multi: true }
|
|
334
|
-
}
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
return {
|
|
338
|
-
widget: { type: 'temba-textinput' }
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Type guard functions for working with WidgetConfig
|
|
343
|
-
export function isTextInputWidget(
|
|
344
|
-
config: WidgetConfig
|
|
345
|
-
): config is { type: 'temba-textinput'; attributes?: TextInputAttributes } {
|
|
346
|
-
return config.type === 'temba-textinput';
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
export function isCompletionWidget(
|
|
350
|
-
config: WidgetConfig
|
|
351
|
-
): config is { type: 'temba-completion'; attributes?: CompletionAttributes } {
|
|
352
|
-
return config.type === 'temba-completion';
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
export function isSelectWidget(
|
|
356
|
-
config: WidgetConfig
|
|
357
|
-
): config is { type: 'temba-select'; attributes?: SelectAttributes } {
|
|
358
|
-
return config.type === 'temba-select';
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
export function isCheckboxWidget(
|
|
362
|
-
config: WidgetConfig
|
|
363
|
-
): config is { type: 'temba-checkbox'; attributes?: CheckboxAttributes } {
|
|
364
|
-
return config.type === 'temba-checkbox';
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
export function isSliderWidget(
|
|
368
|
-
config: WidgetConfig
|
|
369
|
-
): config is { type: 'slider'; attributes?: SliderAttributes } {
|
|
370
|
-
return config.type === 'temba-slider';
|
|
371
|
-
}
|
package/src/form/ArrayEditor.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { html, css, TemplateResult } from 'lit';
|
|
|
2
2
|
import { customElement, property } from 'lit/decorators.js';
|
|
3
3
|
import { FieldConfig, SelectFieldConfig } from '../flow/types';
|
|
4
4
|
import { BaseListEditor, ListItem } from './BaseListEditor';
|
|
5
|
+
import { FieldRenderer } from './FieldRenderer';
|
|
5
6
|
|
|
6
7
|
@customElement('temba-array-editor')
|
|
7
8
|
export class TembaArrayEditor extends BaseListEditor<ListItem> {
|
|
@@ -132,87 +133,42 @@ export class TembaArrayEditor extends BaseListEditor<ListItem> {
|
|
|
132
133
|
): TemplateResult {
|
|
133
134
|
const computedValue = this.computeFieldValue(itemIndex, fieldName, config);
|
|
134
135
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
.
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
@change=${(e: any) =>
|
|
151
|
-
this.handleFieldChange(itemIndex, fieldName, e.target.value)}
|
|
152
|
-
></temba-textinput>`;
|
|
153
|
-
|
|
154
|
-
case 'select': {
|
|
155
|
-
const selectConfig = config as SelectFieldConfig;
|
|
156
|
-
const fieldValue = this.computeFieldValue(itemIndex, fieldName, config);
|
|
157
|
-
|
|
158
|
-
return html`<temba-select
|
|
159
|
-
class="form-control"
|
|
160
|
-
?clearable="${selectConfig.clearable || false}"
|
|
161
|
-
?searchable="${selectConfig.searchable || false}"
|
|
162
|
-
?tags="${selectConfig.tags || false}"
|
|
163
|
-
?multi="${selectConfig.multi || false}"
|
|
164
|
-
?emails="${selectConfig.emails || false}"
|
|
165
|
-
placeholder="${selectConfig.placeholder || ''}"
|
|
166
|
-
maxItems="${selectConfig.maxItems || 0}"
|
|
167
|
-
valueKey="${selectConfig.valueKey || 'value'}"
|
|
168
|
-
nameKey="${selectConfig.nameKey || 'name'}"
|
|
169
|
-
endpoint="${selectConfig.endpoint || ''}"
|
|
170
|
-
value="${fieldValue || ''}"
|
|
171
|
-
flavor="small"
|
|
172
|
-
@change="${(e: Event) => {
|
|
173
|
-
const target = e.target as any;
|
|
174
|
-
let value: any;
|
|
175
|
-
|
|
176
|
-
// For temba-select, extract the correct value
|
|
177
|
-
if (target.tagName === 'TEMBA-SELECT') {
|
|
178
|
-
if (target.multi || target.emails || target.tags) {
|
|
179
|
-
value = target.values || [];
|
|
180
|
-
} else {
|
|
181
|
-
// Single select: extract value from first selected option
|
|
182
|
-
const values = target.values || [];
|
|
183
|
-
value =
|
|
184
|
-
values.length > 0 && values[0]
|
|
185
|
-
? values[0].value !== undefined
|
|
186
|
-
? values[0].value
|
|
187
|
-
: values[0]
|
|
188
|
-
: '';
|
|
189
|
-
}
|
|
136
|
+
// Use FieldRenderer for consistent field rendering
|
|
137
|
+
return FieldRenderer.renderField(fieldName, config, computedValue, {
|
|
138
|
+
showLabel: false, // ArrayEditor doesn't show labels for individual fields
|
|
139
|
+
flavor: 'small', // ArrayEditor uses small flavor
|
|
140
|
+
extraClasses: 'form-control',
|
|
141
|
+
onChange: (e: Event) => {
|
|
142
|
+
let value: any;
|
|
143
|
+
const target = e.target as any;
|
|
144
|
+
|
|
145
|
+
// Handle different field types and their change events
|
|
146
|
+
if (config.type === 'select') {
|
|
147
|
+
// For temba-select, extract the correct value
|
|
148
|
+
if (target.tagName === 'TEMBA-SELECT') {
|
|
149
|
+
if (target.multi || target.emails || target.tags) {
|
|
150
|
+
value = target.values || [];
|
|
190
151
|
} else {
|
|
191
|
-
value
|
|
152
|
+
// Single select: extract value from first selected option
|
|
153
|
+
const values = target.values || [];
|
|
154
|
+
value =
|
|
155
|
+
values.length > 0 && values[0]
|
|
156
|
+
? values[0].value !== undefined
|
|
157
|
+
? values[0].value
|
|
158
|
+
: values[0]
|
|
159
|
+
: '';
|
|
192
160
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
></temba-option>`;
|
|
203
|
-
} else {
|
|
204
|
-
return html`<temba-option
|
|
205
|
-
name="${option.label || option.name}"
|
|
206
|
-
value="${option.value}"
|
|
207
|
-
></temba-option>`;
|
|
208
|
-
}
|
|
209
|
-
})}
|
|
210
|
-
</temba-select>`;
|
|
161
|
+
} else {
|
|
162
|
+
value = target.value;
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
// For other field types, use the target value directly
|
|
166
|
+
value = target.value;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
this.handleFieldChange(itemIndex, fieldName, value);
|
|
211
170
|
}
|
|
212
|
-
|
|
213
|
-
default:
|
|
214
|
-
return html`<span>Unsupported field type: ${config.type}</span>`;
|
|
215
|
-
}
|
|
171
|
+
});
|
|
216
172
|
}
|
|
217
173
|
|
|
218
174
|
renderItem(item: ListItem, index: number): TemplateResult {
|
|
@@ -283,10 +239,6 @@ export class TembaArrayEditor extends BaseListEditor<ListItem> {
|
|
|
283
239
|
flex: 1;
|
|
284
240
|
}
|
|
285
241
|
|
|
286
|
-
.field:first-child {
|
|
287
|
-
flex: 0 0 140px; /* Fixed width for type dropdown */
|
|
288
|
-
}
|
|
289
|
-
|
|
290
242
|
.field label {
|
|
291
243
|
display: block;
|
|
292
244
|
margin-bottom: 4px;
|