@flowdrop/flowdrop 1.10.0 → 1.12.0

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.
Files changed (53) hide show
  1. package/dist/api/enhanced-client.d.ts +29 -16
  2. package/dist/api/enhanced-client.js +0 -14
  3. package/dist/components/Navbar.svelte +1 -10
  4. package/dist/components/Navbar.svelte.d.ts +1 -9
  5. package/dist/components/PipelineStatus.svelte +9 -12
  6. package/dist/components/WorkflowEditor.svelte +3 -0
  7. package/dist/components/interrupt/ChoicePrompt.svelte +24 -5
  8. package/dist/components/interrupt/ConfirmationPrompt.svelte +5 -0
  9. package/dist/components/interrupt/InterruptBubble.svelte +12 -0
  10. package/dist/components/interrupt/ReviewPrompt.svelte +20 -0
  11. package/dist/components/interrupt/TextInputPrompt.svelte +5 -0
  12. package/dist/components/nodes/GatewayNode.svelte +2 -6
  13. package/dist/components/nodes/WorkflowNode.svelte +2 -6
  14. package/dist/components/playground/ChatInput.svelte +359 -0
  15. package/dist/components/playground/ChatInput.svelte.d.ts +14 -0
  16. package/dist/components/playground/ChatPanel.svelte +100 -724
  17. package/dist/components/playground/ChatPanel.svelte.d.ts +9 -26
  18. package/dist/components/playground/ControlPanel.svelte +496 -0
  19. package/dist/components/playground/ControlPanel.svelte.d.ts +20 -0
  20. package/dist/components/playground/ExecutionConsole.svelte +163 -0
  21. package/dist/components/playground/ExecutionConsole.svelte.d.ts +14 -0
  22. package/dist/components/playground/MessageStream.svelte +283 -0
  23. package/dist/components/playground/MessageStream.svelte.d.ts +27 -0
  24. package/dist/components/playground/PipelineKanbanView.svelte +284 -0
  25. package/dist/components/playground/PipelineKanbanView.svelte.d.ts +11 -0
  26. package/dist/components/playground/PipelinePanel.svelte +204 -65
  27. package/dist/components/playground/PipelinePanel.svelte.d.ts +3 -1
  28. package/dist/components/playground/PipelineTableView.svelte +376 -0
  29. package/dist/components/playground/PipelineTableView.svelte.d.ts +11 -0
  30. package/dist/components/playground/Playground.svelte +262 -1200
  31. package/dist/components/playground/Playground.svelte.d.ts +0 -13
  32. package/dist/components/playground/PlaygroundApp.svelte +110 -0
  33. package/dist/components/playground/PlaygroundApp.svelte.d.ts +28 -0
  34. package/dist/components/playground/PlaygroundStudio.svelte +35 -61
  35. package/dist/components/playground/PlaygroundStudio.svelte.d.ts +3 -1
  36. package/dist/components/playground/pipelineViewUtils.svelte.d.ts +22 -0
  37. package/dist/components/playground/pipelineViewUtils.svelte.js +77 -0
  38. package/dist/messages/defaults.d.ts +24 -0
  39. package/dist/messages/defaults.js +24 -0
  40. package/dist/playground/index.d.ts +8 -2
  41. package/dist/playground/index.js +8 -1
  42. package/dist/playground/mount.d.ts +59 -4
  43. package/dist/playground/mount.js +102 -9
  44. package/dist/stores/playgroundStore.svelte.d.ts +6 -0
  45. package/dist/stores/playgroundStore.svelte.js +21 -1
  46. package/dist/svelte-app.d.ts +2 -10
  47. package/dist/types/index.d.ts +28 -2
  48. package/dist/types/navbar.d.ts +14 -0
  49. package/dist/types/navbar.js +1 -0
  50. package/dist/types/playground.d.ts +5 -2
  51. package/dist/types/playground.js +5 -7
  52. package/dist/utils/nodeStatus.js +15 -5
  53. package/package.json +1 -1
@@ -0,0 +1,359 @@
1
+ <!--
2
+ ChatInput Component
3
+
4
+ The textarea + Run/Send/Stop button. Reusable input primitive shared by
5
+ ChatPanel (conversational) and ControlPanel (orchestration controls).
6
+
7
+ Reads execution state from playgroundStore. Owns its own input string and
8
+ textarea ref; emits sent content via onSendMessage.
9
+ -->
10
+
11
+ <script lang="ts">
12
+ import Icon from '@iconify/svelte';
13
+ import { tick, untrack } from 'svelte';
14
+ import { hasEnableRunFlag } from '../../types/playground.js';
15
+ import {
16
+ getMessages,
17
+ getIsExecuting,
18
+ getCanSendMessage,
19
+ getCurrentSession
20
+ } from '../../stores/playgroundStore.svelte.js';
21
+ import { m } from '../../messages/index.js';
22
+
23
+ interface Props {
24
+ placeholder?: string;
25
+ /** Show the textarea (default: true). When false, only the Run button is shown. */
26
+ showTextarea?: boolean;
27
+ /** Show the Run button when textarea is hidden (default: true) */
28
+ showRunButton?: boolean;
29
+ /** Message sent when Run is clicked with textarea hidden */
30
+ predefinedMessage?: string;
31
+ onSendMessage?: (content: string) => void;
32
+ onStopExecution?: () => void;
33
+ }
34
+
35
+ let {
36
+ placeholder,
37
+ showTextarea = true,
38
+ showRunButton = true,
39
+ predefinedMessage,
40
+ onSendMessage,
41
+ onStopExecution
42
+ }: Props = $props();
43
+
44
+ const actions = $derived(m().playground.actions);
45
+ const chat = $derived(m().playground.chat);
46
+ const states = $derived(m().playground.states);
47
+
48
+ const resolvedPlaceholder = $derived(placeholder ?? chat.placeholder);
49
+ const resolvedPredefinedMessage = $derived(predefinedMessage ?? chat.predefinedRun);
50
+
51
+ const noInputsAvailable = $derived(!showTextarea && !showRunButton);
52
+
53
+ /**
54
+ * Tracks whether the Run button is enabled. Starts as true; becomes false
55
+ * after Run is clicked; re-enabled when the backend sends a message with
56
+ * enableRun: true metadata.
57
+ */
58
+ let runEnabled = $state(true);
59
+
60
+ let inputValue = $state('');
61
+ let inputField: HTMLTextAreaElement | undefined;
62
+
63
+ // Count of enableRun messages seen so far — plain let, not $state.
64
+ // Written with untrack to make the bookkeeping intent explicit.
65
+ let seenEnableRunCount = 0;
66
+
67
+ $effect(() => {
68
+ const count = getMessages().filter(m => hasEnableRunFlag(m.metadata)).length;
69
+ if (count > seenEnableRunCount) {
70
+ untrack(() => { seenEnableRunCount = count; });
71
+ runEnabled = true;
72
+ }
73
+ });
74
+
75
+ $effect(() => {
76
+ if (getCurrentSession()?.id) {
77
+ untrack(() => { seenEnableRunCount = 0; });
78
+ runEnabled = true;
79
+ }
80
+ });
81
+
82
+ let wasExecuting = false;
83
+
84
+ /** Auto-focus input when execution completes */
85
+ $effect(() => {
86
+ const nowExecuting = getIsExecuting();
87
+ if (wasExecuting && !nowExecuting && inputField) {
88
+ tick().then(() => inputField?.focus({ preventScroll: true }));
89
+ }
90
+ untrack(() => { wasExecuting = nowExecuting; });
91
+ });
92
+
93
+ function handleSend(): void {
94
+ const trimmedValue = inputValue.trim();
95
+ if (!trimmedValue || !getCanSendMessage()) return;
96
+
97
+ onSendMessage?.(trimmedValue);
98
+ inputValue = '';
99
+
100
+ if (inputField) {
101
+ inputField.style.height = 'auto';
102
+ }
103
+
104
+ tick().then(() => {
105
+ inputField?.focus({ preventScroll: true });
106
+ });
107
+ }
108
+
109
+ function handleKeydown(event: KeyboardEvent): void {
110
+ if (event.key === 'Enter' && !event.shiftKey) {
111
+ event.preventDefault();
112
+ handleSend();
113
+ }
114
+ }
115
+
116
+ function handleStop(): void {
117
+ onStopExecution?.();
118
+ }
119
+
120
+ function handleRun(): void {
121
+ if (getIsExecuting() || !runEnabled) return;
122
+ runEnabled = false;
123
+ onSendMessage?.(resolvedPredefinedMessage);
124
+ }
125
+
126
+ function handleInput(): void {
127
+ if (inputField) {
128
+ inputField.style.height = 'auto';
129
+ inputField.style.height = `${Math.min(inputField.scrollHeight, 120)}px`;
130
+ }
131
+ }
132
+ </script>
133
+
134
+ <div class="chat-input">
135
+ {#if noInputsAvailable}
136
+ <div class="chat-input__no-inputs">
137
+ <Icon icon="mdi:information-outline" />
138
+ <span>{states.viewOnlyHelp}</span>
139
+ </div>
140
+ {:else}
141
+ <div class="chat-input__container" class:chat-input__container--run-only={!showTextarea}>
142
+ {#if showTextarea}
143
+ <div class="chat-input__wrapper">
144
+ <textarea
145
+ bind:this={inputField}
146
+ bind:value={inputValue}
147
+ class="chat-input__textarea"
148
+ placeholder={resolvedPlaceholder}
149
+ rows="1"
150
+ disabled={getIsExecuting() || !getCurrentSession()}
151
+ onkeydown={handleKeydown}
152
+ oninput={handleInput}
153
+ ></textarea>
154
+ </div>
155
+ {/if}
156
+
157
+ {#if getIsExecuting()}
158
+ <button
159
+ type="button"
160
+ class="chat-input__stop-btn"
161
+ onclick={handleStop}
162
+ title={actions.stopTitle}
163
+ aria-label={actions.stopTitle}
164
+ >
165
+ <Icon icon="mdi:stop" />
166
+ {actions.stop}
167
+ </button>
168
+ {:else if showTextarea}
169
+ <button
170
+ type="button"
171
+ class="chat-input__send-btn"
172
+ onclick={handleSend}
173
+ disabled={!inputValue.trim() || !getCanSendMessage()}
174
+ title={actions.sendTitle}
175
+ aria-label={actions.sendTitle}
176
+ >
177
+ {actions.send}
178
+ </button>
179
+ {:else if showRunButton}
180
+ {@const runLabel = runEnabled ? actions.runTitle : actions.runWaitingTitle}
181
+ <button
182
+ type="button"
183
+ class="chat-input__run-btn"
184
+ onclick={handleRun}
185
+ disabled={!runEnabled}
186
+ title={runLabel}
187
+ aria-label={runLabel}
188
+ >
189
+ <Icon icon="mdi:play" />
190
+ {actions.run}
191
+ </button>
192
+ {/if}
193
+ </div>
194
+ {/if}
195
+ </div>
196
+
197
+ <style>
198
+ .chat-input {
199
+ flex-shrink: 0;
200
+ padding: var(--fd-space-xl) var(--fd-space-3xl) var(--fd-space-3xl);
201
+ background-color: var(--fd-background);
202
+ border-top: 1px solid var(--fd-border-muted);
203
+ }
204
+
205
+ .chat-input__container {
206
+ display: flex;
207
+ align-items: flex-end;
208
+ gap: var(--fd-space-md);
209
+ max-width: 760px;
210
+ margin: 0 auto;
211
+ }
212
+
213
+ .chat-input__container--run-only {
214
+ justify-content: flex-end;
215
+ }
216
+
217
+ .chat-input__wrapper {
218
+ flex: 1;
219
+ display: flex;
220
+ align-items: flex-end;
221
+ background-color: var(--fd-background);
222
+ border: 1px solid var(--fd-border);
223
+ border-radius: var(--fd-radius-xl);
224
+ padding: var(--fd-space-sm) var(--fd-space-md);
225
+ transition:
226
+ border-color var(--fd-transition-fast),
227
+ box-shadow var(--fd-transition-fast);
228
+ }
229
+
230
+ .chat-input__wrapper:focus-within {
231
+ border-color: var(--fd-primary);
232
+ box-shadow: 0 0 0 3px var(--fd-primary-muted);
233
+ }
234
+
235
+ .chat-input__textarea {
236
+ flex: 1;
237
+ border: none;
238
+ outline: none;
239
+ resize: none;
240
+ font-family: inherit;
241
+ font-size: var(--fd-text-base);
242
+ line-height: var(--fd-leading-normal);
243
+ max-height: 120px;
244
+ background: transparent;
245
+ color: var(--fd-foreground);
246
+ }
247
+
248
+ .chat-input__textarea::placeholder {
249
+ color: var(--fd-muted-foreground);
250
+ }
251
+
252
+ .chat-input__textarea:disabled {
253
+ cursor: not-allowed;
254
+ opacity: 0.6;
255
+ }
256
+
257
+ .chat-input__send-btn {
258
+ display: flex;
259
+ align-items: center;
260
+ justify-content: center;
261
+ padding: var(--fd-space-sm) var(--fd-space-2xl);
262
+ border: none;
263
+ border-radius: var(--fd-radius-lg);
264
+ background-color: var(--fd-foreground);
265
+ color: var(--fd-background);
266
+ font-size: var(--fd-text-sm);
267
+ font-weight: 500;
268
+ cursor: pointer;
269
+ transition: all var(--fd-transition-fast);
270
+ flex-shrink: 0;
271
+ }
272
+
273
+ .chat-input__send-btn:hover:not(:disabled) {
274
+ opacity: 0.85;
275
+ }
276
+
277
+ .chat-input__send-btn:disabled {
278
+ background-color: var(--fd-foreground);
279
+ color: var(--fd-background);
280
+ opacity: 0.3;
281
+ cursor: not-allowed;
282
+ }
283
+
284
+ .chat-input__stop-btn {
285
+ display: flex;
286
+ align-items: center;
287
+ gap: var(--fd-space-3xs);
288
+ padding: var(--fd-space-sm) var(--fd-space-xl);
289
+ border: none;
290
+ border-radius: var(--fd-radius-lg);
291
+ background-color: var(--fd-error);
292
+ color: var(--fd-error-foreground);
293
+ font-size: var(--fd-text-sm);
294
+ font-weight: 500;
295
+ cursor: pointer;
296
+ transition: background-color var(--fd-transition-fast);
297
+ flex-shrink: 0;
298
+ }
299
+
300
+ .chat-input__stop-btn:hover {
301
+ background-color: var(--fd-error-hover);
302
+ }
303
+
304
+ .chat-input__run-btn {
305
+ display: flex;
306
+ align-items: center;
307
+ gap: var(--fd-space-3xs);
308
+ padding: var(--fd-space-sm) var(--fd-space-2xl);
309
+ border: none;
310
+ border-radius: var(--fd-radius-lg);
311
+ background-color: var(--fd-success);
312
+ color: var(--fd-success-foreground);
313
+ font-size: var(--fd-text-sm);
314
+ font-weight: 500;
315
+ cursor: pointer;
316
+ transition: all var(--fd-transition-fast);
317
+ flex-shrink: 0;
318
+ }
319
+
320
+ .chat-input__run-btn:hover:not(:disabled) {
321
+ background-color: var(--fd-success-hover);
322
+ }
323
+
324
+ .chat-input__run-btn:disabled {
325
+ background-color: var(--fd-border);
326
+ color: var(--fd-muted-foreground);
327
+ cursor: not-allowed;
328
+ }
329
+
330
+ .chat-input__no-inputs {
331
+ display: flex;
332
+ align-items: center;
333
+ justify-content: center;
334
+ gap: var(--fd-space-xs);
335
+ padding: var(--fd-space-md) var(--fd-space-xl);
336
+ background-color: var(--fd-muted);
337
+ border-radius: var(--fd-radius-lg);
338
+ color: var(--fd-muted-foreground);
339
+ font-size: var(--fd-text-sm);
340
+ max-width: 760px;
341
+ margin: 0 auto;
342
+ }
343
+
344
+ @media (max-width: 640px) {
345
+ .chat-input {
346
+ padding: var(--fd-space-md) var(--fd-space-xl) var(--fd-space-xl);
347
+ }
348
+
349
+ .chat-input__container {
350
+ gap: var(--fd-space-xs);
351
+ }
352
+
353
+ .chat-input__send-btn,
354
+ .chat-input__stop-btn,
355
+ .chat-input__run-btn {
356
+ padding: var(--fd-space-xs) var(--fd-space-xl);
357
+ }
358
+ }
359
+ </style>
@@ -0,0 +1,14 @@
1
+ interface Props {
2
+ placeholder?: string;
3
+ /** Show the textarea (default: true). When false, only the Run button is shown. */
4
+ showTextarea?: boolean;
5
+ /** Show the Run button when textarea is hidden (default: true) */
6
+ showRunButton?: boolean;
7
+ /** Message sent when Run is clicked with textarea hidden */
8
+ predefinedMessage?: string;
9
+ onSendMessage?: (content: string) => void;
10
+ onStopExecution?: () => void;
11
+ }
12
+ declare const ChatInput: import("svelte").Component<Props, {}, "">;
13
+ type ChatInput = ReturnType<typeof ChatInput>;
14
+ export default ChatInput;