@flowdrop/flowdrop 1.11.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 (46) 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/PipelineStatus.svelte +9 -12
  4. package/dist/components/WorkflowEditor.svelte +3 -0
  5. package/dist/components/interrupt/ChoicePrompt.svelte +24 -5
  6. package/dist/components/interrupt/ConfirmationPrompt.svelte +5 -0
  7. package/dist/components/interrupt/InterruptBubble.svelte +12 -0
  8. package/dist/components/interrupt/ReviewPrompt.svelte +20 -0
  9. package/dist/components/interrupt/TextInputPrompt.svelte +5 -0
  10. package/dist/components/nodes/GatewayNode.svelte +2 -6
  11. package/dist/components/nodes/WorkflowNode.svelte +2 -6
  12. package/dist/components/playground/ChatInput.svelte +359 -0
  13. package/dist/components/playground/ChatInput.svelte.d.ts +14 -0
  14. package/dist/components/playground/ChatPanel.svelte +100 -724
  15. package/dist/components/playground/ChatPanel.svelte.d.ts +9 -26
  16. package/dist/components/playground/ControlPanel.svelte +496 -0
  17. package/dist/components/playground/ControlPanel.svelte.d.ts +20 -0
  18. package/dist/components/playground/ExecutionConsole.svelte +163 -0
  19. package/dist/components/playground/ExecutionConsole.svelte.d.ts +14 -0
  20. package/dist/components/playground/MessageStream.svelte +283 -0
  21. package/dist/components/playground/MessageStream.svelte.d.ts +27 -0
  22. package/dist/components/playground/PipelineKanbanView.svelte +284 -0
  23. package/dist/components/playground/PipelineKanbanView.svelte.d.ts +11 -0
  24. package/dist/components/playground/PipelinePanel.svelte +204 -65
  25. package/dist/components/playground/PipelinePanel.svelte.d.ts +3 -1
  26. package/dist/components/playground/PipelineTableView.svelte +376 -0
  27. package/dist/components/playground/PipelineTableView.svelte.d.ts +11 -0
  28. package/dist/components/playground/Playground.svelte +262 -1200
  29. package/dist/components/playground/Playground.svelte.d.ts +0 -13
  30. package/dist/components/playground/PlaygroundStudio.svelte +35 -61
  31. package/dist/components/playground/PlaygroundStudio.svelte.d.ts +3 -1
  32. package/dist/components/playground/pipelineViewUtils.svelte.d.ts +22 -0
  33. package/dist/components/playground/pipelineViewUtils.svelte.js +77 -0
  34. package/dist/messages/defaults.d.ts +24 -0
  35. package/dist/messages/defaults.js +24 -0
  36. package/dist/playground/index.d.ts +6 -1
  37. package/dist/playground/index.js +6 -0
  38. package/dist/playground/mount.d.ts +3 -0
  39. package/dist/playground/mount.js +3 -2
  40. package/dist/stores/playgroundStore.svelte.d.ts +6 -0
  41. package/dist/stores/playgroundStore.svelte.js +21 -1
  42. package/dist/types/index.d.ts +28 -2
  43. package/dist/types/playground.d.ts +5 -2
  44. package/dist/types/playground.js +5 -7
  45. package/dist/utils/nodeStatus.js +15 -5
  46. package/package.json +1 -1
@@ -1,48 +1,31 @@
1
- /**
2
- * Component props
3
- */
4
1
  interface Props {
5
- /** Whether to show timestamps on messages */
6
2
  showTimestamps?: boolean;
7
- /** Whether to auto-scroll to bottom on new messages */
8
3
  autoScroll?: boolean;
9
- /** Placeholder text for the input */
10
4
  placeholder?: string;
11
- /** Callback when user sends a message */
12
5
  onSendMessage?: (content: string) => void;
13
- /** Callback when user requests to stop execution */
14
6
  onStopExecution?: () => void;
15
- /** Whether to show log messages inline (false = hide them) */
16
7
  showLogsInline?: boolean;
17
- /** Whether to enable markdown rendering in messages */
18
8
  enableMarkdown?: boolean;
19
- /** Callback when an interrupt is resolved (to refresh messages) */
20
9
  onInterruptResolved?: () => void;
10
+ /** Render a "New session" CTA in the welcome state */
11
+ onCreateSession?: () => void;
21
12
  /**
22
- * Whether to show the chat text input (default: true)
23
- * When false, only the "Run" button is displayed.
13
+ * @deprecated Use `<MessageStream />` directly for view-only feeds.
14
+ * Kept for backwards compatibility with PlaygroundConfig URL params.
24
15
  */
25
16
  showChatInput?: boolean;
26
17
  /**
27
- * Whether to show the "Run" button (default: true)
28
- * When false, the Run button is hidden.
18
+ * @deprecated Use `<MessageStream />` directly for view-only feeds.
29
19
  */
30
20
  showRunButton?: boolean;
31
- /**
32
- * Predefined message to send when "Run" button is clicked
33
- * Used when showChatInput is false.
34
- */
35
21
  predefinedMessage?: string;
22
+ compactSystemMessages?: boolean;
36
23
  /**
37
- * Whether to display system messages in compact mode.
38
- * When true, system messages appear as minimal inline text
39
- * instead of full chat bubbles to reduce visual noise.
40
- * @default true
24
+ * @deprecated `showLogs` is now managed by playgroundStore.
25
+ * Setting it here syncs to the store on mount for backwards compatibility.
41
26
  */
42
- compactSystemMessages?: boolean;
43
- /** Whether log messages are visible — bindable so parent can host the toggle */
44
27
  showLogs?: boolean;
45
28
  }
46
- declare const ChatPanel: import("svelte").Component<Props, {}, "showLogs">;
29
+ declare const ChatPanel: import("svelte").Component<Props, {}, "">;
47
30
  type ChatPanel = ReturnType<typeof ChatPanel>;
48
31
  export default ChatPanel;
@@ -0,0 +1,496 @@
1
+ <!--
2
+ ControlPanel Component
3
+
4
+ Where the user talks to the flow: session switcher, orchestration controls
5
+ (Run/Stop via ChatInput), and toolbar buttons (Pipeline toggle, Refresh,
6
+ Logs). Owns the session chip popover; delegates input behaviour to the
7
+ shared ChatInput primitive.
8
+ -->
9
+
10
+ <script lang="ts">
11
+ import Icon from '@iconify/svelte';
12
+ import ChatInput from './ChatInput.svelte';
13
+ import {
14
+ getCurrentSession,
15
+ getSessions,
16
+ getIsLoading,
17
+ getShowLogs,
18
+ playgroundActions
19
+ } from '../../stores/playgroundStore.svelte.js';
20
+ import { m } from '../../messages/index.js';
21
+
22
+ interface Props {
23
+ // Session management
24
+ onCreateSession: () => void;
25
+ onSelectSession: (id: string) => void;
26
+ onDeleteSession: (id: string) => void;
27
+ onSessionNavigate?: (id: string) => void;
28
+ // Orchestration
29
+ onSendMessage: (content: string) => void;
30
+ onStopExecution: () => void;
31
+ // Header actions
32
+ onTogglePanel?: () => void;
33
+ isPipelinePanelOpen?: boolean;
34
+ onRefresh: () => void;
35
+ isRefreshing?: boolean;
36
+ // Input config
37
+ showChatInput?: boolean;
38
+ showRunButton?: boolean;
39
+ predefinedMessage?: string;
40
+ placeholder?: string;
41
+ style?: string;
42
+ }
43
+
44
+ let {
45
+ onCreateSession,
46
+ onSelectSession,
47
+ onDeleteSession,
48
+ onSessionNavigate,
49
+ onSendMessage,
50
+ onStopExecution,
51
+ onTogglePanel,
52
+ isPipelinePanelOpen = false,
53
+ onRefresh,
54
+ isRefreshing = false,
55
+ showChatInput = true,
56
+ showRunButton = true,
57
+ predefinedMessage,
58
+ placeholder,
59
+ style
60
+ }: Props = $props();
61
+
62
+ const cp = $derived(m().playground.controlPanel);
63
+ const logsTitle = $derived(getShowLogs() ? cp.hideLogs : cp.showLogs);
64
+
65
+ let sessionDropdownOpen = $state(false);
66
+ let chipWrapEl = $state<HTMLElement | null>(null);
67
+ let sessionChipEl = $state<HTMLElement | null>(null);
68
+ let sessionPopoverEl = $state<HTMLElement | null>(null);
69
+
70
+ $effect(() => {
71
+ if (sessionDropdownOpen && sessionPopoverEl) {
72
+ sessionPopoverEl.querySelector<HTMLElement>('[role="menuitem"]')?.focus();
73
+ }
74
+ });
75
+
76
+ // Close popover on outside click
77
+ $effect(() => {
78
+ if (!sessionDropdownOpen) return;
79
+ function handleOutside(e: MouseEvent) {
80
+ if (!chipWrapEl?.contains(e.target as Node)) {
81
+ sessionDropdownOpen = false;
82
+ }
83
+ }
84
+ document.addEventListener('click', handleOutside);
85
+ return () => document.removeEventListener('click', handleOutside);
86
+ });
87
+
88
+ function handleSelect(sessionId: string): void {
89
+ sessionDropdownOpen = false;
90
+ if (onSessionNavigate) {
91
+ onSessionNavigate(sessionId);
92
+ } else {
93
+ onSelectSession(sessionId);
94
+ }
95
+ }
96
+
97
+ function handleCreate(): void {
98
+ sessionDropdownOpen = false;
99
+ onCreateSession();
100
+ }
101
+
102
+ function handleDelete(event: Event, sessionId: string): void {
103
+ event.stopPropagation();
104
+ sessionDropdownOpen = false;
105
+ onDeleteSession(sessionId);
106
+ }
107
+ </script>
108
+
109
+ <section class="control-panel" {style}>
110
+ <header class="control-panel__header">
111
+ <Icon icon="mdi:message-text-outline" class="control-panel__icon" />
112
+ <span class="control-panel__label">{cp.sessionsLabel}</span>
113
+
114
+ <div class="control-panel__session-chip-wrap" bind:this={chipWrapEl}>
115
+ <button
116
+ type="button"
117
+ class="control-panel__session-chip"
118
+ class:control-panel__session-chip--open={sessionDropdownOpen}
119
+ bind:this={sessionChipEl}
120
+ aria-haspopup="menu"
121
+ aria-expanded={sessionDropdownOpen}
122
+ onclick={() => (sessionDropdownOpen = !sessionDropdownOpen)}
123
+ onkeydown={(e) => {
124
+ if (e.key === 'Escape') sessionDropdownOpen = false;
125
+ }}
126
+ title={cp.switchSession}
127
+ >
128
+ <span class="control-panel__session-chip-name">
129
+ {getCurrentSession()?.name ?? cp.noSession}
130
+ </span>
131
+ <Icon
132
+ icon={sessionDropdownOpen ? 'mdi:chevron-up' : 'mdi:chevron-down'}
133
+ class="control-panel__session-chip-chevron"
134
+ />
135
+ </button>
136
+
137
+ {#if sessionDropdownOpen}
138
+ <div
139
+ class="control-panel__session-popover"
140
+ bind:this={sessionPopoverEl}
141
+ role="menu"
142
+ tabindex="-1"
143
+ onkeydown={(e) => {
144
+ if (e.key === 'Escape') {
145
+ sessionDropdownOpen = false;
146
+ sessionChipEl?.focus();
147
+ }
148
+ }}
149
+ >
150
+ <button
151
+ type="button"
152
+ role="menuitem"
153
+ class="control-panel__session-popover-item control-panel__session-popover-item--new"
154
+ disabled={getIsLoading()}
155
+ onclick={handleCreate}
156
+ >
157
+ <Icon icon="mdi:plus" />
158
+ <span>{cp.newSession}</span>
159
+ </button>
160
+ {#if getSessions().length > 0}
161
+ <div class="control-panel__session-popover-divider"></div>
162
+ {#each getSessions() as session (session.id)}
163
+ {@const isActive = getCurrentSession()?.id === session.id}
164
+ <div class="control-panel__session-popover-row">
165
+ <button
166
+ type="button"
167
+ role="menuitem"
168
+ class="control-panel__session-popover-item"
169
+ class:control-panel__session-popover-item--active={isActive}
170
+ onclick={() => handleSelect(session.id)}
171
+ >
172
+ {#if isActive}
173
+ <Icon icon="mdi:check" class="control-panel__session-popover-check" />
174
+ {:else}
175
+ <Icon icon="mdi:message-outline" />
176
+ {/if}
177
+ <span>{session.name}</span>
178
+ </button>
179
+ <button
180
+ type="button"
181
+ role="menuitem"
182
+ class="control-panel__session-popover-delete"
183
+ onclick={(e) => handleDelete(e, session.id)}
184
+ title={cp.deleteSession}
185
+ aria-label={cp.deleteSession}
186
+ >
187
+ <Icon icon="mdi:delete-outline" />
188
+ </button>
189
+ </div>
190
+ {/each}
191
+ {/if}
192
+ </div>
193
+ {/if}
194
+ </div>
195
+
196
+ <div class="control-panel__header-actions">
197
+ {#if onTogglePanel}
198
+ {@const pipelineTitle = isPipelinePanelOpen ? cp.hidePipeline : cp.showPipeline}
199
+ <button
200
+ type="button"
201
+ class="control-panel__toolbar-btn"
202
+ class:control-panel__toolbar-btn--active={isPipelinePanelOpen}
203
+ onclick={onTogglePanel}
204
+ title={pipelineTitle}
205
+ aria-label={pipelineTitle}
206
+ >
207
+ <Icon icon="mdi:source-branch" />
208
+ {cp.pipeline}
209
+ </button>
210
+ {/if}
211
+ {#if getCurrentSession()}
212
+ <button
213
+ type="button"
214
+ class="control-panel__toolbar-btn"
215
+ class:control-panel__toolbar-btn--spinning={isRefreshing}
216
+ onclick={onRefresh}
217
+ disabled={isRefreshing}
218
+ title={cp.refreshTitle}
219
+ aria-label={cp.refreshTitle}
220
+ >
221
+ <Icon icon="mdi:refresh" />
222
+ {cp.refresh}
223
+ </button>
224
+ {/if}
225
+ <button
226
+ type="button"
227
+ class="control-panel__toolbar-btn"
228
+ class:control-panel__toolbar-btn--active={getShowLogs()}
229
+ onclick={() => playgroundActions.toggleShowLogs()}
230
+ title={logsTitle}
231
+ aria-label={logsTitle}
232
+ >
233
+ <Icon icon="mdi:console" />
234
+ {cp.logs}
235
+ </button>
236
+ </div>
237
+ </header>
238
+
239
+ <ChatInput
240
+ showTextarea={showChatInput}
241
+ {showRunButton}
242
+ {placeholder}
243
+ {predefinedMessage}
244
+ {onSendMessage}
245
+ {onStopExecution}
246
+ />
247
+ </section>
248
+
249
+ <style>
250
+ .control-panel {
251
+ display: flex;
252
+ flex-direction: column;
253
+ min-height: 0;
254
+ background-color: var(--fd-background);
255
+ border-top: 1px solid var(--fd-border);
256
+ }
257
+
258
+ .control-panel__header {
259
+ display: flex;
260
+ align-items: center;
261
+ gap: var(--fd-space-xs);
262
+ padding: 0 var(--fd-space-xl);
263
+ height: var(--fd-playground-header-height);
264
+ min-height: var(--fd-playground-header-height);
265
+ border-bottom: 1px solid var(--fd-border);
266
+ flex-shrink: 0;
267
+ }
268
+
269
+ :global(.control-panel__icon) {
270
+ font-size: var(--fd-text-base);
271
+ color: var(--fd-muted-foreground);
272
+ flex-shrink: 0;
273
+ }
274
+
275
+ .control-panel__label {
276
+ font-size: var(--fd-text-sm);
277
+ font-weight: 600;
278
+ color: var(--fd-foreground);
279
+ flex-shrink: 0;
280
+ }
281
+
282
+ .control-panel__session-chip-wrap {
283
+ position: relative;
284
+ flex-shrink: 0;
285
+ }
286
+
287
+ .control-panel__session-chip {
288
+ display: inline-flex;
289
+ align-items: center;
290
+ gap: var(--fd-space-xs);
291
+ padding: var(--fd-space-3xs) var(--fd-space-sm) var(--fd-space-3xs) var(--fd-space-xs);
292
+ border: 1px solid var(--fd-border);
293
+ border-radius: var(--fd-radius-md);
294
+ background: var(--fd-background);
295
+ color: var(--fd-foreground);
296
+ font-size: var(--fd-text-sm);
297
+ font-weight: 500;
298
+ cursor: pointer;
299
+ transition: all var(--fd-transition-fast);
300
+ max-width: 220px;
301
+ line-height: 1;
302
+ }
303
+
304
+ .control-panel__session-chip :global(svg) {
305
+ flex-shrink: 0;
306
+ font-size: var(--fd-text-sm);
307
+ color: var(--fd-muted-foreground);
308
+ }
309
+
310
+ .control-panel__session-chip:hover,
311
+ .control-panel__session-chip--open {
312
+ background-color: var(--fd-muted);
313
+ border-color: var(--fd-border-strong);
314
+ }
315
+
316
+ .control-panel__session-chip-name {
317
+ flex: 1;
318
+ white-space: nowrap;
319
+ overflow: hidden;
320
+ text-overflow: ellipsis;
321
+ min-width: 0;
322
+ }
323
+
324
+ :global(.control-panel__session-chip-chevron) {
325
+ color: var(--fd-muted-foreground);
326
+ flex-shrink: 0;
327
+ }
328
+
329
+ .control-panel__session-popover {
330
+ position: absolute;
331
+ bottom: calc(100% + var(--fd-space-xs));
332
+ left: 0;
333
+ z-index: 50;
334
+ min-width: 220px;
335
+ max-width: 300px;
336
+ padding: var(--fd-space-xs);
337
+ background-color: var(--fd-background);
338
+ border: 1px solid var(--fd-border);
339
+ border-radius: var(--fd-radius-lg);
340
+ box-shadow: var(--fd-shadow-lg);
341
+ }
342
+
343
+ .control-panel__session-popover-divider {
344
+ height: 1px;
345
+ background-color: var(--fd-border-muted);
346
+ margin: var(--fd-space-xs) 0;
347
+ }
348
+
349
+ .control-panel__session-popover-row {
350
+ display: flex;
351
+ align-items: center;
352
+ gap: 2px;
353
+ }
354
+
355
+ .control-panel__session-popover-item {
356
+ display: flex;
357
+ align-items: center;
358
+ gap: var(--fd-space-sm);
359
+ flex: 1;
360
+ min-width: 0;
361
+ padding: var(--fd-space-sm);
362
+ border: none;
363
+ border-radius: var(--fd-radius-sm);
364
+ background: transparent;
365
+ color: var(--fd-foreground);
366
+ font-size: var(--fd-text-sm);
367
+ text-align: left;
368
+ cursor: pointer;
369
+ transition: background-color var(--fd-transition-fast);
370
+ white-space: nowrap;
371
+ overflow: hidden;
372
+ text-overflow: ellipsis;
373
+ }
374
+
375
+ .control-panel__session-popover-item :global(svg) {
376
+ flex-shrink: 0;
377
+ color: var(--fd-muted-foreground);
378
+ font-size: var(--fd-text-sm);
379
+ }
380
+
381
+ .control-panel__session-popover-item span {
382
+ overflow: hidden;
383
+ text-overflow: ellipsis;
384
+ }
385
+
386
+ .control-panel__session-popover-item:hover {
387
+ background-color: var(--fd-muted);
388
+ }
389
+
390
+ .control-panel__session-popover-item:disabled {
391
+ opacity: 0.4;
392
+ cursor: not-allowed;
393
+ }
394
+
395
+ .control-panel__session-popover-item--new {
396
+ color: var(--fd-primary);
397
+ font-weight: 500;
398
+ width: 100%;
399
+ }
400
+
401
+ .control-panel__session-popover-item--new :global(svg) {
402
+ color: var(--fd-primary);
403
+ }
404
+
405
+ .control-panel__session-popover-item--active {
406
+ font-weight: 500;
407
+ }
408
+
409
+ :global(.control-panel__session-popover-check) {
410
+ color: var(--fd-primary) !important;
411
+ }
412
+
413
+ .control-panel__session-popover-delete {
414
+ display: flex;
415
+ align-items: center;
416
+ justify-content: center;
417
+ flex-shrink: 0;
418
+ width: var(--fd-size-icon-btn);
419
+ height: var(--fd-size-icon-btn);
420
+ border: none;
421
+ border-radius: var(--fd-radius-sm);
422
+ background: transparent;
423
+ color: var(--fd-muted-foreground);
424
+ cursor: pointer;
425
+ opacity: 0;
426
+ transition: all var(--fd-transition-fast);
427
+ }
428
+
429
+ .control-panel__session-popover-row:hover .control-panel__session-popover-delete,
430
+ .control-panel__session-popover-row:focus-within .control-panel__session-popover-delete {
431
+ opacity: 1;
432
+ }
433
+
434
+ .control-panel__session-popover-delete:hover {
435
+ background-color: var(--fd-error-muted);
436
+ color: var(--fd-error);
437
+ opacity: 1;
438
+ }
439
+
440
+ .control-panel__header-actions {
441
+ display: flex;
442
+ align-items: center;
443
+ gap: var(--fd-space-xs);
444
+ margin-left: auto;
445
+ }
446
+
447
+ .control-panel__toolbar-btn {
448
+ display: inline-flex;
449
+ align-items: center;
450
+ gap: var(--fd-space-3xs);
451
+ padding: var(--fd-space-3xs) var(--fd-space-sm);
452
+ border: 1px solid var(--fd-border);
453
+ border-radius: var(--fd-radius-md);
454
+ background: transparent;
455
+ color: var(--fd-muted-foreground);
456
+ font-size: var(--fd-text-xs);
457
+ font-weight: 500;
458
+ cursor: pointer;
459
+ transition: all var(--fd-transition-fast);
460
+ line-height: 1;
461
+ }
462
+
463
+ .control-panel__toolbar-btn :global(svg) {
464
+ font-size: var(--fd-text-xs);
465
+ }
466
+
467
+ .control-panel__toolbar-btn:hover:not(:disabled) {
468
+ background-color: var(--fd-muted);
469
+ color: var(--fd-foreground);
470
+ border-color: var(--fd-border-strong);
471
+ }
472
+
473
+ .control-panel__toolbar-btn:disabled {
474
+ opacity: 0.5;
475
+ cursor: not-allowed;
476
+ }
477
+
478
+ .control-panel__toolbar-btn--active {
479
+ background-color: var(--fd-primary-muted);
480
+ border-color: var(--fd-primary);
481
+ color: var(--fd-primary);
482
+ }
483
+
484
+ .control-panel__toolbar-btn--spinning :global(svg) {
485
+ animation: control-panel-spin 0.8s linear infinite;
486
+ }
487
+
488
+ @keyframes control-panel-spin {
489
+ from {
490
+ transform: rotate(0deg);
491
+ }
492
+ to {
493
+ transform: rotate(360deg);
494
+ }
495
+ }
496
+ </style>
@@ -0,0 +1,20 @@
1
+ interface Props {
2
+ onCreateSession: () => void;
3
+ onSelectSession: (id: string) => void;
4
+ onDeleteSession: (id: string) => void;
5
+ onSessionNavigate?: (id: string) => void;
6
+ onSendMessage: (content: string) => void;
7
+ onStopExecution: () => void;
8
+ onTogglePanel?: () => void;
9
+ isPipelinePanelOpen?: boolean;
10
+ onRefresh: () => void;
11
+ isRefreshing?: boolean;
12
+ showChatInput?: boolean;
13
+ showRunButton?: boolean;
14
+ predefinedMessage?: string;
15
+ placeholder?: string;
16
+ style?: string;
17
+ }
18
+ declare const ControlPanel: import("svelte").Component<Props, {}, "">;
19
+ type ControlPanel = ReturnType<typeof ControlPanel>;
20
+ export default ControlPanel;