@d34dman/flowdrop 0.0.37 → 0.0.39
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/LICENSE +21 -0
- package/dist/components/NodeSidebar.svelte +1 -0
- package/dist/components/form/FormCodeEditor.svelte +6 -1
- package/dist/components/interrupt/ChoicePrompt.svelte +389 -0
- package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +21 -0
- package/dist/components/interrupt/ConfirmationPrompt.svelte +280 -0
- package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +23 -0
- package/dist/components/interrupt/FormPrompt.svelte +223 -0
- package/dist/components/interrupt/FormPrompt.svelte.d.ts +21 -0
- package/dist/components/interrupt/InterruptBubble.svelte +621 -0
- package/dist/components/interrupt/InterruptBubble.svelte.d.ts +16 -0
- package/dist/components/interrupt/TextInputPrompt.svelte +333 -0
- package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +21 -0
- package/dist/components/interrupt/index.d.ts +13 -0
- package/dist/components/interrupt/index.js +15 -0
- package/dist/components/nodes/GatewayNode.svelte +1 -3
- package/dist/components/nodes/IdeaNode.svelte +30 -35
- package/dist/components/nodes/IdeaNode.svelte.d.ts +1 -1
- package/dist/components/nodes/SimpleNode.svelte +1 -3
- package/dist/components/nodes/TerminalNode.svelte +1 -3
- package/dist/components/nodes/ToolNode.svelte +2 -2
- package/dist/components/nodes/WorkflowNode.svelte +1 -3
- package/dist/components/playground/ChatPanel.svelte +144 -7
- package/dist/components/playground/ChatPanel.svelte.d.ts +2 -0
- package/dist/components/playground/MessageBubble.svelte +1 -3
- package/dist/components/playground/Playground.svelte +50 -5
- package/dist/components/playground/PlaygroundModal.svelte +8 -7
- package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -3
- package/dist/config/endpoints.d.ts +12 -0
- package/dist/config/endpoints.js +7 -0
- package/dist/playground/index.d.ts +5 -0
- package/dist/playground/index.js +21 -0
- package/dist/playground/mount.d.ts +3 -3
- package/dist/playground/mount.js +30 -22
- package/dist/services/interruptService.d.ts +133 -0
- package/dist/services/interruptService.js +279 -0
- package/dist/stores/interruptStore.d.ts +200 -0
- package/dist/stores/interruptStore.js +424 -0
- package/dist/stores/playgroundStore.d.ts +11 -1
- package/dist/stores/playgroundStore.js +34 -0
- package/dist/styles/base.css +89 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/interrupt.d.ts +305 -0
- package/dist/types/interrupt.js +126 -0
- package/dist/types/interruptState.d.ts +211 -0
- package/dist/types/interruptState.js +308 -0
- package/dist/utils/colors.js +1 -0
- package/dist/utils/connections.js +2 -2
- package/dist/utils/icons.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
ConfirmationPrompt Component
|
|
3
|
+
|
|
4
|
+
Renders a Yes/No confirmation prompt for confirmation-type interrupts.
|
|
5
|
+
Displays the message and two action buttons with customizable labels.
|
|
6
|
+
Shows the selected response when resolved.
|
|
7
|
+
Styled with BEM syntax.
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
<script lang="ts">
|
|
11
|
+
import Icon from '@iconify/svelte';
|
|
12
|
+
import type { ConfirmationConfig } from '../../types/interrupt.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Component props
|
|
16
|
+
*/
|
|
17
|
+
interface Props {
|
|
18
|
+
/** Confirmation configuration from the interrupt */
|
|
19
|
+
config: ConfirmationConfig;
|
|
20
|
+
/** Whether this interrupt has been resolved */
|
|
21
|
+
isResolved: boolean;
|
|
22
|
+
/** The resolved value (true/false) if resolved */
|
|
23
|
+
resolvedValue?: boolean;
|
|
24
|
+
/** Whether the form is currently submitting */
|
|
25
|
+
isSubmitting: boolean;
|
|
26
|
+
/** Error message if submission failed */
|
|
27
|
+
error?: string;
|
|
28
|
+
/** Callback when user confirms (Yes) */
|
|
29
|
+
onConfirm: () => void;
|
|
30
|
+
/** Callback when user declines (No) */
|
|
31
|
+
onDecline: () => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let { config, isResolved, resolvedValue, isSubmitting, error, onConfirm, onDecline }: Props =
|
|
35
|
+
$props();
|
|
36
|
+
|
|
37
|
+
/** Computed label for confirm button */
|
|
38
|
+
const confirmLabel = $derived(config.confirmLabel ?? 'Yes');
|
|
39
|
+
|
|
40
|
+
/** Computed label for decline/cancel button */
|
|
41
|
+
const declineLabel = $derived(config.cancelLabel ?? 'No');
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<div
|
|
45
|
+
class="confirmation-prompt"
|
|
46
|
+
class:confirmation-prompt--resolved={isResolved}
|
|
47
|
+
class:confirmation-prompt--submitting={isSubmitting}
|
|
48
|
+
>
|
|
49
|
+
<!-- Message -->
|
|
50
|
+
<p class="confirmation-prompt__message">{config.message}</p>
|
|
51
|
+
|
|
52
|
+
<!-- Error message -->
|
|
53
|
+
{#if error}
|
|
54
|
+
<div class="confirmation-prompt__error">
|
|
55
|
+
<Icon icon="mdi:alert-circle" />
|
|
56
|
+
<span>{error}</span>
|
|
57
|
+
</div>
|
|
58
|
+
{/if}
|
|
59
|
+
|
|
60
|
+
<!-- Actions -->
|
|
61
|
+
<div class="confirmation-prompt__actions">
|
|
62
|
+
<button
|
|
63
|
+
type="button"
|
|
64
|
+
class="confirmation-prompt__button confirmation-prompt__button--decline"
|
|
65
|
+
class:confirmation-prompt__button--selected={isResolved && resolvedValue === false}
|
|
66
|
+
class:confirmation-prompt__button--not-selected={isResolved && resolvedValue !== false}
|
|
67
|
+
onclick={onDecline}
|
|
68
|
+
disabled={isResolved || isSubmitting}
|
|
69
|
+
aria-label={declineLabel}
|
|
70
|
+
>
|
|
71
|
+
{#if isSubmitting && !isResolved}
|
|
72
|
+
<span class="confirmation-prompt__spinner"></span>
|
|
73
|
+
{:else if isResolved && resolvedValue === false}
|
|
74
|
+
<Icon icon="mdi:check-circle" />
|
|
75
|
+
{:else if isResolved}
|
|
76
|
+
<!-- Not selected - show dimmed X icon -->
|
|
77
|
+
<Icon icon="mdi:close" />
|
|
78
|
+
{:else}
|
|
79
|
+
<Icon icon="mdi:close" />
|
|
80
|
+
{/if}
|
|
81
|
+
<span>{declineLabel}</span>
|
|
82
|
+
</button>
|
|
83
|
+
|
|
84
|
+
<button
|
|
85
|
+
type="button"
|
|
86
|
+
class="confirmation-prompt__button confirmation-prompt__button--confirm"
|
|
87
|
+
class:confirmation-prompt__button--selected={isResolved && resolvedValue === true}
|
|
88
|
+
class:confirmation-prompt__button--not-selected={isResolved && resolvedValue !== true}
|
|
89
|
+
onclick={onConfirm}
|
|
90
|
+
disabled={isResolved || isSubmitting}
|
|
91
|
+
aria-label={confirmLabel}
|
|
92
|
+
>
|
|
93
|
+
{#if isSubmitting && !isResolved}
|
|
94
|
+
<span class="confirmation-prompt__spinner"></span>
|
|
95
|
+
{:else if isResolved && resolvedValue === true}
|
|
96
|
+
<Icon icon="mdi:check-circle" />
|
|
97
|
+
{:else if isResolved}
|
|
98
|
+
<!-- Not selected - show dimmed check icon -->
|
|
99
|
+
<Icon icon="mdi:check" />
|
|
100
|
+
{:else}
|
|
101
|
+
<Icon icon="mdi:check" />
|
|
102
|
+
{/if}
|
|
103
|
+
<span>{confirmLabel}</span>
|
|
104
|
+
</button>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<!-- Resolved indicator -->
|
|
108
|
+
{#if isResolved}
|
|
109
|
+
<div class="confirmation-prompt__resolved-badge">
|
|
110
|
+
<Icon icon="mdi:check-circle" />
|
|
111
|
+
<span>Response submitted</span>
|
|
112
|
+
</div>
|
|
113
|
+
{/if}
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<style>
|
|
117
|
+
.confirmation-prompt {
|
|
118
|
+
display: flex;
|
|
119
|
+
flex-direction: column;
|
|
120
|
+
gap: 0.75rem;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.confirmation-prompt--resolved {
|
|
124
|
+
opacity: 0.85;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.confirmation-prompt--submitting {
|
|
128
|
+
pointer-events: none;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.confirmation-prompt__message {
|
|
132
|
+
margin: 0;
|
|
133
|
+
font-size: 0.9375rem;
|
|
134
|
+
line-height: 1.5;
|
|
135
|
+
color: var(--color-ref-gray-800, #1f2937);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.confirmation-prompt__error {
|
|
139
|
+
display: flex;
|
|
140
|
+
align-items: center;
|
|
141
|
+
gap: 0.375rem;
|
|
142
|
+
padding: 0.5rem 0.75rem;
|
|
143
|
+
background-color: var(--color-ref-red-50, #fef2f2);
|
|
144
|
+
border-radius: 0.375rem;
|
|
145
|
+
color: var(--color-ref-red-600, #dc2626);
|
|
146
|
+
font-size: 0.8125rem;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.confirmation-prompt__actions {
|
|
150
|
+
display: flex;
|
|
151
|
+
gap: 0.75rem;
|
|
152
|
+
flex-wrap: wrap;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.confirmation-prompt__button {
|
|
156
|
+
display: inline-flex;
|
|
157
|
+
align-items: center;
|
|
158
|
+
justify-content: center;
|
|
159
|
+
gap: 0.5rem;
|
|
160
|
+
padding: 0.625rem 1.25rem;
|
|
161
|
+
border-radius: 0.5rem;
|
|
162
|
+
font-size: 0.875rem;
|
|
163
|
+
font-weight: 600;
|
|
164
|
+
font-family: inherit;
|
|
165
|
+
cursor: pointer;
|
|
166
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
167
|
+
border: 1px solid transparent;
|
|
168
|
+
min-height: 2.5rem;
|
|
169
|
+
min-width: 100px;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.confirmation-prompt__button:disabled {
|
|
173
|
+
cursor: not-allowed;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/* Uses design tokens from base.css: --flowdrop-interrupt-* */
|
|
177
|
+
.confirmation-prompt__button--decline {
|
|
178
|
+
background-color: var(--flowdrop-interrupt-btn-secondary-bg);
|
|
179
|
+
border-color: var(--flowdrop-interrupt-btn-secondary-border);
|
|
180
|
+
color: var(--flowdrop-interrupt-btn-secondary-text);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.confirmation-prompt__button--decline:hover:not(:disabled) {
|
|
184
|
+
background-color: var(--color-ref-gray-200, #e5e7eb);
|
|
185
|
+
border-color: var(--color-ref-gray-400, #9ca3af);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.confirmation-prompt__button--decline:disabled {
|
|
189
|
+
opacity: 0.6;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* Non-selected decline button when resolved - very dimmed */
|
|
193
|
+
.confirmation-prompt__button--decline.confirmation-prompt__button--not-selected {
|
|
194
|
+
opacity: var(--flowdrop-interrupt-not-selected-opacity);
|
|
195
|
+
background-color: var(--color-ref-gray-50, #f9fafb);
|
|
196
|
+
border-color: var(--color-ref-gray-200, #e5e7eb);
|
|
197
|
+
color: var(--color-ref-gray-400, #9ca3af);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* Selected decline button - highlighted with border and background */
|
|
201
|
+
.confirmation-prompt__button--decline.confirmation-prompt__button--selected {
|
|
202
|
+
opacity: 1;
|
|
203
|
+
background-color: var(--flowdrop-interrupt-selected-decline-bg);
|
|
204
|
+
border-color: var(--flowdrop-interrupt-selected-decline-border);
|
|
205
|
+
border-width: 2px;
|
|
206
|
+
color: var(--flowdrop-interrupt-selected-decline-text);
|
|
207
|
+
box-shadow: 0 0 0 3px var(--flowdrop-interrupt-selected-decline-glow);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.confirmation-prompt__button--confirm {
|
|
211
|
+
background: var(--flowdrop-interrupt-btn-primary-bg);
|
|
212
|
+
color: #ffffff;
|
|
213
|
+
box-shadow: 0 1px 3px var(--flowdrop-interrupt-btn-primary-shadow);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.confirmation-prompt__button--confirm:hover:not(:disabled) {
|
|
217
|
+
background: var(--flowdrop-interrupt-btn-primary-bg-hover);
|
|
218
|
+
box-shadow: 0 4px 12px var(--flowdrop-interrupt-btn-primary-shadow);
|
|
219
|
+
transform: translateY(-1px);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.confirmation-prompt__button--confirm:disabled {
|
|
223
|
+
opacity: 0.6;
|
|
224
|
+
transform: none;
|
|
225
|
+
box-shadow: none;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* Non-selected confirm button when resolved - very dimmed */
|
|
229
|
+
.confirmation-prompt__button--confirm.confirmation-prompt__button--not-selected {
|
|
230
|
+
opacity: var(--flowdrop-interrupt-not-selected-opacity);
|
|
231
|
+
background: var(--color-ref-gray-200, #e5e7eb);
|
|
232
|
+
color: var(--color-ref-gray-400, #9ca3af);
|
|
233
|
+
box-shadow: none;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* Selected confirm button - highlighted with glow */
|
|
237
|
+
.confirmation-prompt__button--confirm.confirmation-prompt__button--selected {
|
|
238
|
+
opacity: 1;
|
|
239
|
+
background: var(--flowdrop-interrupt-selected-confirm-bg);
|
|
240
|
+
border-width: 2px;
|
|
241
|
+
border-color: var(--flowdrop-interrupt-selected-confirm-border);
|
|
242
|
+
box-shadow:
|
|
243
|
+
0 0 0 3px var(--flowdrop-interrupt-selected-confirm-glow),
|
|
244
|
+
0 2px 8px var(--flowdrop-interrupt-btn-primary-shadow);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.confirmation-prompt__spinner {
|
|
248
|
+
width: 1rem;
|
|
249
|
+
height: 1rem;
|
|
250
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
251
|
+
border-top-color: currentColor;
|
|
252
|
+
border-radius: 50%;
|
|
253
|
+
animation: confirmation-spin 0.6s linear infinite;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.confirmation-prompt__button--decline .confirmation-prompt__spinner {
|
|
257
|
+
border-color: rgba(55, 65, 81, 0.3);
|
|
258
|
+
border-top-color: #374151;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
@keyframes confirmation-spin {
|
|
262
|
+
to {
|
|
263
|
+
transform: rotate(360deg);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* Resolved badge - neutral blue theme */
|
|
268
|
+
.confirmation-prompt__resolved-badge {
|
|
269
|
+
display: inline-flex;
|
|
270
|
+
align-items: center;
|
|
271
|
+
gap: 0.375rem;
|
|
272
|
+
padding: 0.375rem 0.75rem;
|
|
273
|
+
background-color: var(--flowdrop-interrupt-badge-completed-bg);
|
|
274
|
+
border-radius: 9999px;
|
|
275
|
+
color: var(--flowdrop-interrupt-badge-completed-text);
|
|
276
|
+
font-size: 0.75rem;
|
|
277
|
+
font-weight: 500;
|
|
278
|
+
align-self: flex-start;
|
|
279
|
+
}
|
|
280
|
+
</style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ConfirmationConfig } from '../../types/interrupt.js';
|
|
2
|
+
/**
|
|
3
|
+
* Component props
|
|
4
|
+
*/
|
|
5
|
+
interface Props {
|
|
6
|
+
/** Confirmation configuration from the interrupt */
|
|
7
|
+
config: ConfirmationConfig;
|
|
8
|
+
/** Whether this interrupt has been resolved */
|
|
9
|
+
isResolved: boolean;
|
|
10
|
+
/** The resolved value (true/false) if resolved */
|
|
11
|
+
resolvedValue?: boolean;
|
|
12
|
+
/** Whether the form is currently submitting */
|
|
13
|
+
isSubmitting: boolean;
|
|
14
|
+
/** Error message if submission failed */
|
|
15
|
+
error?: string;
|
|
16
|
+
/** Callback when user confirms (Yes) */
|
|
17
|
+
onConfirm: () => void;
|
|
18
|
+
/** Callback when user declines (No) */
|
|
19
|
+
onDecline: () => void;
|
|
20
|
+
}
|
|
21
|
+
declare const ConfirmationPrompt: import("svelte").Component<Props, {}, "">;
|
|
22
|
+
type ConfirmationPrompt = ReturnType<typeof ConfirmationPrompt>;
|
|
23
|
+
export default ConfirmationPrompt;
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
FormPrompt Component
|
|
3
|
+
|
|
4
|
+
Renders a JSON Schema-based form for form-type interrupts.
|
|
5
|
+
Wraps the existing SchemaForm component for consistent form handling.
|
|
6
|
+
Shows the submitted form data when resolved.
|
|
7
|
+
Styled with BEM syntax.
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
<script lang="ts">
|
|
11
|
+
import Icon from '@iconify/svelte';
|
|
12
|
+
import SchemaForm from '../SchemaForm.svelte';
|
|
13
|
+
import type { FormConfig } from '../../types/interrupt.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Component props
|
|
17
|
+
*/
|
|
18
|
+
interface Props {
|
|
19
|
+
/** Form configuration from the interrupt */
|
|
20
|
+
config: FormConfig;
|
|
21
|
+
/** Whether this interrupt has been resolved */
|
|
22
|
+
isResolved: boolean;
|
|
23
|
+
/** The resolved form values if resolved */
|
|
24
|
+
resolvedValue?: Record<string, unknown>;
|
|
25
|
+
/** Whether the form is currently submitting */
|
|
26
|
+
isSubmitting: boolean;
|
|
27
|
+
/** Error message if submission failed */
|
|
28
|
+
error?: string;
|
|
29
|
+
/** Callback when user submits form */
|
|
30
|
+
onSubmit: (value: Record<string, unknown>) => void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let { config, isResolved, resolvedValue, isSubmitting, error, onSubmit }: Props = $props();
|
|
34
|
+
|
|
35
|
+
/** Local state for form values */
|
|
36
|
+
let formValues = $state<Record<string, unknown>>(config.defaultValues ?? {});
|
|
37
|
+
|
|
38
|
+
/** Display values - either resolved or current form values */
|
|
39
|
+
const displayValues = $derived(isResolved ? (resolvedValue ?? {}) : formValues);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Handle form value changes
|
|
43
|
+
*/
|
|
44
|
+
function handleChange(values: Record<string, unknown>): void {
|
|
45
|
+
if (isResolved || isSubmitting) return;
|
|
46
|
+
formValues = values;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Handle form submission
|
|
51
|
+
*/
|
|
52
|
+
function handleSave(values: Record<string, unknown>): void {
|
|
53
|
+
if (isResolved || isSubmitting) return;
|
|
54
|
+
onSubmit(values);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Format resolved value for display
|
|
59
|
+
*/
|
|
60
|
+
function formatResolvedValue(value: unknown): string {
|
|
61
|
+
if (value === null || value === undefined) return '—';
|
|
62
|
+
if (typeof value === 'boolean') return value ? 'Yes' : 'No';
|
|
63
|
+
if (typeof value === 'object') return JSON.stringify(value, null, 2);
|
|
64
|
+
return String(value);
|
|
65
|
+
}
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
<div
|
|
69
|
+
class="form-prompt"
|
|
70
|
+
class:form-prompt--resolved={isResolved}
|
|
71
|
+
class:form-prompt--submitting={isSubmitting}
|
|
72
|
+
>
|
|
73
|
+
<!-- Message -->
|
|
74
|
+
<p class="form-prompt__message">{config.message}</p>
|
|
75
|
+
|
|
76
|
+
<!-- Error message -->
|
|
77
|
+
{#if error}
|
|
78
|
+
<div class="form-prompt__error">
|
|
79
|
+
<Icon icon="mdi:alert-circle" />
|
|
80
|
+
<span>{error}</span>
|
|
81
|
+
</div>
|
|
82
|
+
{/if}
|
|
83
|
+
|
|
84
|
+
<!-- Form -->
|
|
85
|
+
{#if !isResolved}
|
|
86
|
+
<div class="form-prompt__form-wrapper">
|
|
87
|
+
<SchemaForm
|
|
88
|
+
schema={config.schema}
|
|
89
|
+
values={formValues}
|
|
90
|
+
onChange={handleChange}
|
|
91
|
+
onSave={handleSave}
|
|
92
|
+
showActions={true}
|
|
93
|
+
saveLabel="Submit"
|
|
94
|
+
cancelLabel=""
|
|
95
|
+
loading={isSubmitting}
|
|
96
|
+
disabled={isResolved}
|
|
97
|
+
/>
|
|
98
|
+
</div>
|
|
99
|
+
{:else}
|
|
100
|
+
<!-- Resolved state: Show submitted values as read-only -->
|
|
101
|
+
<div class="form-prompt__resolved-values">
|
|
102
|
+
<h4 class="form-prompt__resolved-title">Submitted Values</h4>
|
|
103
|
+
<div class="form-prompt__values-list">
|
|
104
|
+
{#each Object.entries(config.schema.properties ?? {}) as [key, field]}
|
|
105
|
+
{@const value = displayValues[key]}
|
|
106
|
+
{@const fieldTitle = ((field as Record<string, unknown>).title as string) ?? key}
|
|
107
|
+
<div class="form-prompt__value-item">
|
|
108
|
+
<span class="form-prompt__value-label">{fieldTitle}</span>
|
|
109
|
+
<span class="form-prompt__value-content">
|
|
110
|
+
{formatResolvedValue(value)}
|
|
111
|
+
</span>
|
|
112
|
+
</div>
|
|
113
|
+
{/each}
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
{/if}
|
|
117
|
+
|
|
118
|
+
<!-- Resolved indicator -->
|
|
119
|
+
{#if isResolved}
|
|
120
|
+
<div class="form-prompt__resolved-badge">
|
|
121
|
+
<Icon icon="mdi:check-circle" />
|
|
122
|
+
<span>Response submitted</span>
|
|
123
|
+
</div>
|
|
124
|
+
{/if}
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<style>
|
|
128
|
+
/* Uses design tokens from base.css: --flowdrop-interrupt-*, --color-ref-* */
|
|
129
|
+
.form-prompt {
|
|
130
|
+
display: flex;
|
|
131
|
+
flex-direction: column;
|
|
132
|
+
gap: 0.75rem;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.form-prompt--resolved {
|
|
136
|
+
opacity: 0.85;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.form-prompt--submitting {
|
|
140
|
+
pointer-events: none;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.form-prompt__message {
|
|
144
|
+
margin: 0;
|
|
145
|
+
font-size: 0.9375rem;
|
|
146
|
+
line-height: 1.5;
|
|
147
|
+
color: var(--color-ref-gray-800, #1f2937);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.form-prompt__error {
|
|
151
|
+
display: flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
gap: 0.375rem;
|
|
154
|
+
padding: 0.5rem 0.75rem;
|
|
155
|
+
background-color: var(--color-ref-red-50, #fef2f2);
|
|
156
|
+
border-radius: 0.375rem;
|
|
157
|
+
color: var(--color-ref-red-600, #dc2626);
|
|
158
|
+
font-size: 0.8125rem;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.form-prompt__form-wrapper {
|
|
162
|
+
background-color: var(--color-ref-gray-50, #f9fafb);
|
|
163
|
+
border: 1px solid var(--color-ref-gray-200, #e5e7eb);
|
|
164
|
+
border-radius: 0.5rem;
|
|
165
|
+
padding: 1rem;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* Resolved values - neutral blue theme */
|
|
169
|
+
.form-prompt__resolved-values {
|
|
170
|
+
background-color: var(--color-ref-blue-50, #eff6ff);
|
|
171
|
+
border: 1px solid var(--flowdrop-interrupt-completed-border);
|
|
172
|
+
border-radius: 0.5rem;
|
|
173
|
+
padding: 1rem;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.form-prompt__resolved-title {
|
|
177
|
+
margin: 0 0 0.75rem 0;
|
|
178
|
+
font-size: 0.8125rem;
|
|
179
|
+
font-weight: 600;
|
|
180
|
+
color: var(--flowdrop-interrupt-badge-completed-text);
|
|
181
|
+
text-transform: uppercase;
|
|
182
|
+
letter-spacing: 0.05em;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.form-prompt__values-list {
|
|
186
|
+
display: flex;
|
|
187
|
+
flex-direction: column;
|
|
188
|
+
gap: 0.5rem;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.form-prompt__value-item {
|
|
192
|
+
display: flex;
|
|
193
|
+
flex-direction: column;
|
|
194
|
+
gap: 0.125rem;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.form-prompt__value-label {
|
|
198
|
+
font-size: 0.75rem;
|
|
199
|
+
font-weight: 500;
|
|
200
|
+
color: var(--color-ref-gray-500, #6b7280);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.form-prompt__value-content {
|
|
204
|
+
font-size: 0.875rem;
|
|
205
|
+
color: var(--color-ref-gray-800, #1f2937);
|
|
206
|
+
word-break: break-word;
|
|
207
|
+
white-space: pre-wrap;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/* Resolved badge - neutral blue theme */
|
|
211
|
+
.form-prompt__resolved-badge {
|
|
212
|
+
display: inline-flex;
|
|
213
|
+
align-items: center;
|
|
214
|
+
gap: 0.375rem;
|
|
215
|
+
padding: 0.375rem 0.75rem;
|
|
216
|
+
background-color: var(--flowdrop-interrupt-badge-completed-bg);
|
|
217
|
+
border-radius: 9999px;
|
|
218
|
+
color: var(--flowdrop-interrupt-badge-completed-text);
|
|
219
|
+
font-size: 0.75rem;
|
|
220
|
+
font-weight: 500;
|
|
221
|
+
align-self: flex-start;
|
|
222
|
+
}
|
|
223
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FormConfig } from '../../types/interrupt.js';
|
|
2
|
+
/**
|
|
3
|
+
* Component props
|
|
4
|
+
*/
|
|
5
|
+
interface Props {
|
|
6
|
+
/** Form configuration from the interrupt */
|
|
7
|
+
config: FormConfig;
|
|
8
|
+
/** Whether this interrupt has been resolved */
|
|
9
|
+
isResolved: boolean;
|
|
10
|
+
/** The resolved form values if resolved */
|
|
11
|
+
resolvedValue?: Record<string, unknown>;
|
|
12
|
+
/** Whether the form is currently submitting */
|
|
13
|
+
isSubmitting: boolean;
|
|
14
|
+
/** Error message if submission failed */
|
|
15
|
+
error?: string;
|
|
16
|
+
/** Callback when user submits form */
|
|
17
|
+
onSubmit: (value: Record<string, unknown>) => void;
|
|
18
|
+
}
|
|
19
|
+
declare const FormPrompt: import("svelte").Component<Props, {}, "">;
|
|
20
|
+
type FormPrompt = ReturnType<typeof FormPrompt>;
|
|
21
|
+
export default FormPrompt;
|