@flowdrop/flowdrop 1.12.0 → 1.14.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.
- package/README.md +5 -0
- package/dist/components/ConfigForm.svelte +1 -0
- package/dist/components/ConfigPanel.svelte +7 -1
- package/dist/components/NodeSwapPicker.svelte +5 -1
- package/dist/components/PipelineStatus.svelte +11 -2
- package/dist/components/SchemaForm.svelte +1 -0
- package/dist/components/SettingsPanel.svelte +5 -1
- package/dist/components/WorkflowEditor.svelte +5 -1
- package/dist/components/chat/AIChatPanel.svelte +1 -5
- package/dist/components/form/FormAutocomplete.svelte +69 -15
- package/dist/components/form/FormField.svelte +21 -0
- package/dist/components/form/FormFieldLight.svelte +1 -0
- package/dist/components/interrupt/ChoicePrompt.svelte +5 -1
- package/dist/components/interrupt/InterruptBubble.svelte +75 -17
- package/dist/components/interrupt/InterruptBubble.svelte.d.ts +11 -0
- package/dist/components/playground/ChatBubble.svelte +287 -0
- package/dist/components/playground/ChatBubble.svelte.d.ts +10 -0
- package/dist/components/playground/ChatInput.svelte +11 -5
- package/dist/components/playground/ControlPanel.svelte +42 -29
- package/dist/components/playground/ExecutionConsole.svelte +5 -1
- package/dist/components/playground/ExecutionConsole.svelte.d.ts +2 -0
- package/dist/components/playground/ExecutionList.svelte +7 -2
- package/dist/components/playground/HierarchyTrail.svelte +88 -0
- package/dist/components/playground/HierarchyTrail.svelte.d.ts +7 -0
- package/dist/components/playground/LogRow.svelte +179 -0
- package/dist/components/playground/LogRow.svelte.d.ts +8 -0
- package/dist/components/playground/MessageBubble.stories.svelte +89 -0
- package/dist/components/playground/MessageBubble.svelte +23 -738
- package/dist/components/playground/MessageBubble.svelte.d.ts +3 -11
- package/dist/components/playground/MessageCard.svelte +107 -0
- package/dist/components/playground/MessageCard.svelte.d.ts +10 -0
- package/dist/components/playground/MessageMarkdown.svelte +170 -0
- package/dist/components/playground/MessageMarkdown.svelte.d.ts +7 -0
- package/dist/components/playground/MessageNotice.svelte +121 -0
- package/dist/components/playground/MessageNotice.svelte.d.ts +9 -0
- package/dist/components/playground/MessageStream.svelte +215 -10
- package/dist/components/playground/MessageStream.svelte.d.ts +5 -0
- package/dist/components/playground/MessageTagChip.svelte +117 -0
- package/dist/components/playground/MessageTagChip.svelte.d.ts +7 -0
- package/dist/components/playground/MessageTagStrip.svelte +37 -0
- package/dist/components/playground/MessageTagStrip.svelte.d.ts +7 -0
- package/dist/components/playground/PipelineKanbanView.svelte +40 -11
- package/dist/components/playground/PipelinePanel.svelte +5 -1
- package/dist/components/playground/PipelineTableView.svelte +20 -6
- package/dist/components/playground/Playground.svelte +84 -22
- package/dist/components/playground/PlaygroundStudio.svelte +99 -7
- package/dist/components/playground/messageDisplay.d.ts +19 -0
- package/dist/components/playground/messageDisplay.js +62 -0
- package/dist/components/playground/pipelineViewUtils.svelte.js +11 -4
- package/dist/form/autocomplete.d.ts +1 -0
- package/dist/form/autocomplete.js +1 -0
- package/dist/form/index.d.ts +17 -0
- package/dist/form/index.js +19 -0
- package/dist/messages/defaults.d.ts +5 -0
- package/dist/messages/defaults.js +6 -0
- package/dist/openapi/v1/openapi.yaml +6403 -0
- package/dist/schemas/v1/workflow.schema.json +46 -1
- package/dist/services/categoriesApi.d.ts +2 -1
- package/dist/services/categoriesApi.js +5 -3
- package/dist/services/playgroundService.d.ts +23 -4
- package/dist/services/playgroundService.js +22 -9
- package/dist/services/portConfigApi.d.ts +2 -1
- package/dist/services/portConfigApi.js +5 -3
- package/dist/stores/playgroundStore.svelte.d.ts +22 -1
- package/dist/stores/playgroundStore.svelte.js +109 -32
- package/dist/svelte-app.d.ts +1 -0
- package/dist/svelte-app.js +5 -5
- package/dist/types/index.d.ts +13 -0
- package/dist/types/playground.d.ts +112 -2
- package/dist/types/playground.js +14 -0
- package/package.json +12 -1
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
ChatBubble — avatar + bubble layout for user/assistant/system messages.
|
|
3
|
+
Markdown typography comes from MessageMarkdown; user-bubble overrides
|
|
4
|
+
(primary-bg) are scoped here.
|
|
5
|
+
-->
|
|
6
|
+
|
|
7
|
+
<script lang="ts">
|
|
8
|
+
import Icon from '@iconify/svelte';
|
|
9
|
+
import type { PlaygroundMessage } from '../../types/playground.js';
|
|
10
|
+
import HierarchyTrail from './HierarchyTrail.svelte';
|
|
11
|
+
import MessageTagStrip from './MessageTagStrip.svelte';
|
|
12
|
+
import MessageMarkdown from './MessageMarkdown.svelte';
|
|
13
|
+
import { formatDuration, formatTimestamp, getRoleIcon, getRoleLabel } from './messageDisplay.js';
|
|
14
|
+
import { m } from '../../messages/index.js';
|
|
15
|
+
|
|
16
|
+
interface Props {
|
|
17
|
+
message: PlaygroundMessage;
|
|
18
|
+
showTimestamp?: boolean;
|
|
19
|
+
isLast?: boolean;
|
|
20
|
+
enableMarkdown?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let { message, showTimestamp = true, isLast = false, enableMarkdown = true }: Props = $props();
|
|
24
|
+
|
|
25
|
+
const hierarchy = $derived(message.hierarchy ?? []);
|
|
26
|
+
const tags = $derived(message.tags ?? []);
|
|
27
|
+
const roleLabel = $derived(getRoleLabel(message, m().playground.roles));
|
|
28
|
+
const hasFooter = $derived(
|
|
29
|
+
message.metadata?.duration !== undefined || !!message.nodeId || tags.length > 0
|
|
30
|
+
);
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<article
|
|
34
|
+
class="message-bubble"
|
|
35
|
+
class:message-bubble--user={message.role === 'user'}
|
|
36
|
+
class:message-bubble--assistant={message.role === 'assistant'}
|
|
37
|
+
class:message-bubble--system={message.role === 'system'}
|
|
38
|
+
class:message-bubble--last={isLast}
|
|
39
|
+
aria-label="{roleLabel} message"
|
|
40
|
+
>
|
|
41
|
+
<div class="message-bubble__avatar" aria-hidden="true">
|
|
42
|
+
<Icon icon={getRoleIcon(message.role)} />
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div class="message-bubble__content">
|
|
46
|
+
<div class="message-bubble__header">
|
|
47
|
+
<span class="message-bubble__role">{roleLabel}</span>
|
|
48
|
+
{#if showTimestamp}
|
|
49
|
+
<time
|
|
50
|
+
class="message-bubble__timestamp"
|
|
51
|
+
datetime={message.timestamp}
|
|
52
|
+
aria-label="sent at {formatTimestamp(message.timestamp)}"
|
|
53
|
+
>{formatTimestamp(message.timestamp)}</time
|
|
54
|
+
>
|
|
55
|
+
{/if}
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
{#if hierarchy.length > 0}
|
|
59
|
+
<div class="message-bubble__hierarchy">
|
|
60
|
+
<HierarchyTrail items={hierarchy} />
|
|
61
|
+
</div>
|
|
62
|
+
{/if}
|
|
63
|
+
|
|
64
|
+
<MessageMarkdown content={message.content} {enableMarkdown} />
|
|
65
|
+
|
|
66
|
+
{#if hasFooter}
|
|
67
|
+
<div class="message-bubble__footer">
|
|
68
|
+
{#if message.nodeId}
|
|
69
|
+
<span
|
|
70
|
+
class="message-bubble__node"
|
|
71
|
+
title={m().playground.messageTooltips.nodeId({ id: message.nodeId })}
|
|
72
|
+
>
|
|
73
|
+
<Icon icon="mdi:vector-square" aria-hidden="true" />
|
|
74
|
+
via {message.metadata?.nodeLabel ?? message.nodeId}
|
|
75
|
+
</span>
|
|
76
|
+
{/if}
|
|
77
|
+
{#if message.metadata?.duration !== undefined}
|
|
78
|
+
<span
|
|
79
|
+
class="message-bubble__duration"
|
|
80
|
+
title={m().playground.messageTooltips.executionDuration}
|
|
81
|
+
aria-label="execution duration {formatDuration(message.metadata.duration)}"
|
|
82
|
+
>
|
|
83
|
+
<Icon icon="mdi:timer-outline" aria-hidden="true" />
|
|
84
|
+
{formatDuration(message.metadata.duration)}
|
|
85
|
+
</span>
|
|
86
|
+
{/if}
|
|
87
|
+
<MessageTagStrip {tags} />
|
|
88
|
+
</div>
|
|
89
|
+
{/if}
|
|
90
|
+
</div>
|
|
91
|
+
</article>
|
|
92
|
+
|
|
93
|
+
<style>
|
|
94
|
+
.message-bubble {
|
|
95
|
+
display: flex;
|
|
96
|
+
gap: var(--fd-space-sm);
|
|
97
|
+
padding: 2px var(--fd-space-xl);
|
|
98
|
+
margin-bottom: 2px;
|
|
99
|
+
align-items: flex-end;
|
|
100
|
+
/* fd-fade-in + reduced-motion guard live in MessageStream.svelte */
|
|
101
|
+
animation: fd-fade-in 0.18s ease-out;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.message-bubble--user {
|
|
105
|
+
flex-direction: row-reverse;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.message-bubble--last {
|
|
109
|
+
margin-bottom: var(--fd-space-xl);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.message-bubble__avatar {
|
|
113
|
+
flex-shrink: 0;
|
|
114
|
+
width: 1.875rem;
|
|
115
|
+
height: 1.875rem;
|
|
116
|
+
display: flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
justify-content: center;
|
|
119
|
+
border-radius: var(--fd-radius-full);
|
|
120
|
+
font-size: 1rem;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.message-bubble--user .message-bubble__avatar {
|
|
124
|
+
background-color: var(--fd-primary);
|
|
125
|
+
color: var(--fd-primary-foreground);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.message-bubble--assistant .message-bubble__avatar {
|
|
129
|
+
background-color: var(--fd-secondary);
|
|
130
|
+
color: var(--fd-secondary-foreground);
|
|
131
|
+
border: 1px solid var(--fd-border);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.message-bubble--system .message-bubble__avatar {
|
|
135
|
+
background-color: var(--fd-muted);
|
|
136
|
+
color: var(--fd-muted-foreground);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.message-bubble__content {
|
|
140
|
+
min-width: 0;
|
|
141
|
+
max-width: 78%;
|
|
142
|
+
padding: var(--fd-space-sm) var(--fd-space-md);
|
|
143
|
+
border-radius: var(--fd-radius-2xl);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.message-bubble--user .message-bubble__content {
|
|
147
|
+
background-color: var(--fd-primary);
|
|
148
|
+
color: var(--fd-primary-foreground);
|
|
149
|
+
border-bottom-right-radius: var(--fd-radius-sm);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.message-bubble--assistant .message-bubble__content {
|
|
153
|
+
background-color: var(--fd-card);
|
|
154
|
+
border: 1px solid var(--fd-border);
|
|
155
|
+
color: var(--fd-card-foreground);
|
|
156
|
+
box-shadow:
|
|
157
|
+
0 1px 3px 0 oklch(0% 0 0 / 0.06),
|
|
158
|
+
0 1px 2px -1px oklch(0% 0 0 / 0.04);
|
|
159
|
+
border-bottom-left-radius: var(--fd-radius-sm);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.message-bubble--system .message-bubble__content {
|
|
163
|
+
background-color: var(--fd-muted);
|
|
164
|
+
border: 1px solid var(--fd-border);
|
|
165
|
+
color: var(--fd-muted-foreground);
|
|
166
|
+
font-size: var(--fd-text-sm);
|
|
167
|
+
max-width: 88%;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.message-bubble__header {
|
|
171
|
+
display: flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
gap: var(--fd-space-xs);
|
|
174
|
+
margin-bottom: var(--fd-space-3xs);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.message-bubble--user .message-bubble__header {
|
|
178
|
+
flex-direction: row-reverse;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.message-bubble__role {
|
|
182
|
+
font-weight: 600;
|
|
183
|
+
font-size: var(--fd-text-xs);
|
|
184
|
+
text-transform: uppercase;
|
|
185
|
+
letter-spacing: 0.05em;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.message-bubble--user .message-bubble__role {
|
|
189
|
+
color: var(--fd-primary-foreground);
|
|
190
|
+
opacity: 0.75;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.message-bubble--assistant .message-bubble__role,
|
|
194
|
+
.message-bubble--system .message-bubble__role {
|
|
195
|
+
color: var(--fd-muted-foreground);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.message-bubble__timestamp {
|
|
199
|
+
font-size: 0.6875rem;
|
|
200
|
+
font-family: var(--fd-font-mono);
|
|
201
|
+
opacity: 0.55;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.message-bubble--user .message-bubble__timestamp {
|
|
205
|
+
color: var(--fd-primary-foreground);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.message-bubble--assistant .message-bubble__timestamp {
|
|
209
|
+
color: var(--fd-muted-foreground);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.message-bubble__hierarchy {
|
|
213
|
+
margin: var(--fd-space-3xs) 0 var(--fd-space-xs);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* Override markdown styling on the primary-bg user bubble */
|
|
217
|
+
.message-bubble--user :global(.message-markdown code) {
|
|
218
|
+
background-color: color-mix(in srgb, var(--fd-primary-foreground) 18%, transparent);
|
|
219
|
+
color: var(--fd-primary-foreground);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.message-bubble--user :global(.message-markdown pre) {
|
|
223
|
+
background-color: rgb(0 0 0 / 0.25);
|
|
224
|
+
color: var(--fd-primary-foreground);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.message-bubble--user :global(.message-markdown a) {
|
|
228
|
+
color: var(--fd-primary-foreground);
|
|
229
|
+
text-decoration: underline;
|
|
230
|
+
opacity: 0.85;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.message-bubble--user :global(.message-markdown blockquote) {
|
|
234
|
+
border-left-color: color-mix(in srgb, var(--fd-primary-foreground) 40%, transparent);
|
|
235
|
+
color: var(--fd-primary-foreground);
|
|
236
|
+
opacity: 0.8;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.message-bubble__footer {
|
|
240
|
+
display: flex;
|
|
241
|
+
align-items: center;
|
|
242
|
+
flex-wrap: wrap;
|
|
243
|
+
gap: var(--fd-space-md);
|
|
244
|
+
margin-top: var(--fd-space-xs);
|
|
245
|
+
padding-top: var(--fd-space-3xs);
|
|
246
|
+
border-top: 1px solid var(--fd-border);
|
|
247
|
+
font-size: var(--fd-text-xs);
|
|
248
|
+
color: var(--fd-muted-foreground);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.message-bubble--user .message-bubble__footer {
|
|
252
|
+
justify-content: flex-end;
|
|
253
|
+
border-top-color: color-mix(in srgb, var(--fd-primary-foreground) 20%, transparent);
|
|
254
|
+
color: var(--fd-primary-foreground);
|
|
255
|
+
opacity: 0.75;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.message-bubble__node,
|
|
259
|
+
.message-bubble__duration {
|
|
260
|
+
display: flex;
|
|
261
|
+
align-items: center;
|
|
262
|
+
gap: var(--fd-space-3xs);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@media (max-width: 640px) {
|
|
266
|
+
.message-bubble {
|
|
267
|
+
padding: 2px var(--fd-space-md);
|
|
268
|
+
gap: var(--fd-space-xs);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.message-bubble__content {
|
|
272
|
+
max-width: calc(100% - 2.5rem);
|
|
273
|
+
padding: var(--fd-space-xs) var(--fd-space-sm);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.message-bubble__avatar {
|
|
277
|
+
width: 1.625rem;
|
|
278
|
+
height: 1.625rem;
|
|
279
|
+
font-size: var(--fd-text-sm);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.message-bubble__footer {
|
|
283
|
+
gap: var(--fd-space-xs);
|
|
284
|
+
font-size: var(--fd-text-2xs);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
</style>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PlaygroundMessage } from '../../types/playground.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
message: PlaygroundMessage;
|
|
4
|
+
showTimestamp?: boolean;
|
|
5
|
+
isLast?: boolean;
|
|
6
|
+
enableMarkdown?: boolean;
|
|
7
|
+
}
|
|
8
|
+
declare const ChatBubble: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type ChatBubble = ReturnType<typeof ChatBubble>;
|
|
10
|
+
export default ChatBubble;
|
|
@@ -58,23 +58,27 @@
|
|
|
58
58
|
let runEnabled = $state(true);
|
|
59
59
|
|
|
60
60
|
let inputValue = $state('');
|
|
61
|
-
let inputField: HTMLTextAreaElement | undefined;
|
|
61
|
+
let inputField: HTMLTextAreaElement | undefined = $state();
|
|
62
62
|
|
|
63
63
|
// Count of enableRun messages seen so far — plain let, not $state.
|
|
64
64
|
// Written with untrack to make the bookkeeping intent explicit.
|
|
65
65
|
let seenEnableRunCount = 0;
|
|
66
66
|
|
|
67
67
|
$effect(() => {
|
|
68
|
-
const count = getMessages().filter(m => hasEnableRunFlag(m.metadata)).length;
|
|
68
|
+
const count = getMessages().filter((m) => hasEnableRunFlag(m.metadata)).length;
|
|
69
69
|
if (count > seenEnableRunCount) {
|
|
70
|
-
untrack(() => {
|
|
70
|
+
untrack(() => {
|
|
71
|
+
seenEnableRunCount = count;
|
|
72
|
+
});
|
|
71
73
|
runEnabled = true;
|
|
72
74
|
}
|
|
73
75
|
});
|
|
74
76
|
|
|
75
77
|
$effect(() => {
|
|
76
78
|
if (getCurrentSession()?.id) {
|
|
77
|
-
untrack(() => {
|
|
79
|
+
untrack(() => {
|
|
80
|
+
seenEnableRunCount = 0;
|
|
81
|
+
});
|
|
78
82
|
runEnabled = true;
|
|
79
83
|
}
|
|
80
84
|
});
|
|
@@ -87,7 +91,9 @@
|
|
|
87
91
|
if (wasExecuting && !nowExecuting && inputField) {
|
|
88
92
|
tick().then(() => inputField?.focus({ preventScroll: true }));
|
|
89
93
|
}
|
|
90
|
-
untrack(() => {
|
|
94
|
+
untrack(() => {
|
|
95
|
+
wasExecuting = nowExecuting;
|
|
96
|
+
});
|
|
91
97
|
});
|
|
92
98
|
|
|
93
99
|
function handleSend(): void {
|
|
@@ -159,35 +159,37 @@
|
|
|
159
159
|
</button>
|
|
160
160
|
{#if getSessions().length > 0}
|
|
161
161
|
<div class="control-panel__session-popover-divider"></div>
|
|
162
|
-
|
|
163
|
-
{
|
|
164
|
-
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
162
|
+
<div class="control-panel__session-popover-list">
|
|
163
|
+
{#each getSessions() as session (session.id)}
|
|
164
|
+
{@const isActive = getCurrentSession()?.id === session.id}
|
|
165
|
+
<div class="control-panel__session-popover-row">
|
|
166
|
+
<button
|
|
167
|
+
type="button"
|
|
168
|
+
role="menuitem"
|
|
169
|
+
class="control-panel__session-popover-item"
|
|
170
|
+
class:control-panel__session-popover-item--active={isActive}
|
|
171
|
+
onclick={() => handleSelect(session.id)}
|
|
172
|
+
>
|
|
173
|
+
{#if isActive}
|
|
174
|
+
<Icon icon="mdi:check" class="control-panel__session-popover-check" />
|
|
175
|
+
{:else}
|
|
176
|
+
<Icon icon="mdi:message-outline" />
|
|
177
|
+
{/if}
|
|
178
|
+
<span>{session.name}</span>
|
|
179
|
+
</button>
|
|
180
|
+
<button
|
|
181
|
+
type="button"
|
|
182
|
+
role="menuitem"
|
|
183
|
+
class="control-panel__session-popover-delete"
|
|
184
|
+
onclick={(e) => handleDelete(e, session.id)}
|
|
185
|
+
title={cp.deleteSession}
|
|
186
|
+
aria-label={cp.deleteSession}
|
|
187
|
+
>
|
|
188
|
+
<Icon icon="mdi:delete-outline" />
|
|
189
|
+
</button>
|
|
190
|
+
</div>
|
|
191
|
+
{/each}
|
|
192
|
+
</div>
|
|
191
193
|
{/if}
|
|
192
194
|
</div>
|
|
193
195
|
{/if}
|
|
@@ -333,6 +335,9 @@
|
|
|
333
335
|
z-index: 50;
|
|
334
336
|
min-width: 220px;
|
|
335
337
|
max-width: 300px;
|
|
338
|
+
max-height: min(60vh, 420px);
|
|
339
|
+
display: flex;
|
|
340
|
+
flex-direction: column;
|
|
336
341
|
padding: var(--fd-space-xs);
|
|
337
342
|
background-color: var(--fd-background);
|
|
338
343
|
border: 1px solid var(--fd-border);
|
|
@@ -344,6 +349,13 @@
|
|
|
344
349
|
height: 1px;
|
|
345
350
|
background-color: var(--fd-border-muted);
|
|
346
351
|
margin: var(--fd-space-xs) 0;
|
|
352
|
+
flex-shrink: 0;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.control-panel__session-popover-list {
|
|
356
|
+
flex: 1 1 auto;
|
|
357
|
+
min-height: 0;
|
|
358
|
+
overflow-y: auto;
|
|
347
359
|
}
|
|
348
360
|
|
|
349
361
|
.control-panel__session-popover-row {
|
|
@@ -396,6 +408,7 @@
|
|
|
396
408
|
color: var(--fd-primary);
|
|
397
409
|
font-weight: 500;
|
|
398
410
|
width: 100%;
|
|
411
|
+
flex: 0 0 auto;
|
|
399
412
|
}
|
|
400
413
|
|
|
401
414
|
.control-panel__session-popover-item--new :global(svg) {
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
onInterruptResolved?: () => void;
|
|
23
23
|
/** Optional callback that, when provided, shows a "New session" CTA in the welcome state */
|
|
24
24
|
onCreateSession?: () => void;
|
|
25
|
+
/** Called when the user scrolls near the top to load older messages */
|
|
26
|
+
onLoadOlder?: () => void | Promise<void>;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
let {
|
|
@@ -31,7 +33,8 @@
|
|
|
31
33
|
allowLogs = true,
|
|
32
34
|
compactSystemMessages = true,
|
|
33
35
|
onInterruptResolved,
|
|
34
|
-
onCreateSession
|
|
36
|
+
onCreateSession,
|
|
37
|
+
onLoadOlder
|
|
35
38
|
}: Props = $props();
|
|
36
39
|
|
|
37
40
|
const ec = $derived(m().playground.executionConsole);
|
|
@@ -50,6 +53,7 @@
|
|
|
50
53
|
{allowLogs}
|
|
51
54
|
{compactSystemMessages}
|
|
52
55
|
{onInterruptResolved}
|
|
56
|
+
{onLoadOlder}
|
|
53
57
|
welcome={welcomeState}
|
|
54
58
|
emptySession={readyState}
|
|
55
59
|
/>
|
|
@@ -8,6 +8,8 @@ interface Props {
|
|
|
8
8
|
onInterruptResolved?: () => void;
|
|
9
9
|
/** Optional callback that, when provided, shows a "New session" CTA in the welcome state */
|
|
10
10
|
onCreateSession?: () => void;
|
|
11
|
+
/** Called when the user scrolls near the top to load older messages */
|
|
12
|
+
onLoadOlder?: () => void | Promise<void>;
|
|
11
13
|
}
|
|
12
14
|
declare const ExecutionConsole: import("svelte").Component<Props, {}, "">;
|
|
13
15
|
type ExecutionConsole = ReturnType<typeof ExecutionConsole>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
HierarchyTrail Component
|
|
3
|
+
|
|
4
|
+
Renders a chevron-separated path of MessageHierarchyItem entries. The
|
|
5
|
+
path is a *display*, not a list users navigate, so the SR announcement
|
|
6
|
+
comes entirely from the wrapper's aria-label (built from the labels of
|
|
7
|
+
the items themselves) and the visible chips are hidden from AT to avoid
|
|
8
|
+
the path being announced twice.
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
<script lang="ts">
|
|
12
|
+
import Icon from '@iconify/svelte';
|
|
13
|
+
import type { MessageHierarchyItem } from '../../types/playground.js';
|
|
14
|
+
import { m } from '../../messages/index.js';
|
|
15
|
+
|
|
16
|
+
interface Props {
|
|
17
|
+
items: MessageHierarchyItem[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let { items }: Props = $props();
|
|
21
|
+
|
|
22
|
+
const ariaLabel = $derived.by(() => {
|
|
23
|
+
const path = items.map((i) => i.label).join(' / ');
|
|
24
|
+
return m().playground.messageAnnotations.hierarchyOf({ path });
|
|
25
|
+
});
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
{#if items.length > 0}
|
|
29
|
+
<span class="hierarchy-trail" aria-label={ariaLabel}>
|
|
30
|
+
{#each items as item (item.id)}
|
|
31
|
+
<span class="hierarchy-trail__item" aria-hidden="true">
|
|
32
|
+
{#if item.icon}
|
|
33
|
+
<Icon icon={item.icon} class="hierarchy-trail__icon" />
|
|
34
|
+
{/if}
|
|
35
|
+
<span class="hierarchy-trail__label">{item.label}</span>
|
|
36
|
+
</span>
|
|
37
|
+
{/each}
|
|
38
|
+
</span>
|
|
39
|
+
{/if}
|
|
40
|
+
|
|
41
|
+
<style>
|
|
42
|
+
.hierarchy-trail {
|
|
43
|
+
display: inline-flex;
|
|
44
|
+
flex-wrap: wrap;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: var(--fd-space-3xs);
|
|
47
|
+
font-size: var(--fd-text-2xs);
|
|
48
|
+
color: var(--fd-muted-foreground);
|
|
49
|
+
min-width: 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.hierarchy-trail__item {
|
|
53
|
+
display: inline-flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
gap: var(--fd-space-3xs);
|
|
56
|
+
min-width: 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Chevron separator between items, drawn as a pseudo-element so it
|
|
60
|
+
doesn't enter the markup (and so it never appears to AT — the items
|
|
61
|
+
are already aria-hidden, but belt-and-braces). U+203A SINGLE
|
|
62
|
+
RIGHT-POINTING ANGLE QUOTATION MARK matches mdi:chevron-right
|
|
63
|
+
closely enough without a second iconify dependency. */
|
|
64
|
+
.hierarchy-trail__item:not(:last-child)::after {
|
|
65
|
+
content: '\203A';
|
|
66
|
+
margin-inline-start: var(--fd-space-3xs);
|
|
67
|
+
opacity: 0.5;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.hierarchy-trail__label {
|
|
71
|
+
overflow: hidden;
|
|
72
|
+
text-overflow: ellipsis;
|
|
73
|
+
white-space: nowrap;
|
|
74
|
+
max-width: 8rem;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@media (max-width: 640px) {
|
|
78
|
+
.hierarchy-trail__label {
|
|
79
|
+
max-width: 5rem;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.hierarchy-trail :global(.hierarchy-trail__icon) {
|
|
84
|
+
flex-shrink: 0;
|
|
85
|
+
font-size: 0.875em;
|
|
86
|
+
opacity: 0.7;
|
|
87
|
+
}
|
|
88
|
+
</style>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MessageHierarchyItem } from '../../types/playground.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
items: MessageHierarchyItem[];
|
|
4
|
+
}
|
|
5
|
+
declare const HierarchyTrail: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type HierarchyTrail = ReturnType<typeof HierarchyTrail>;
|
|
7
|
+
export default HierarchyTrail;
|