@flowdrop/flowdrop 1.7.0 → 1.8.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 +10 -0
- package/dist/components/App.svelte +92 -54
- package/dist/components/App.svelte.d.ts +13 -0
- package/dist/components/ConfigModal.svelte +2 -1
- package/dist/components/ConfigPanel.svelte +3 -2
- package/dist/components/FlowDropZone.svelte +2 -1
- package/dist/components/LogsSidebar.svelte +3 -2
- package/dist/components/Navbar.svelte +10 -6
- package/dist/components/NodeSidebar.svelte +4 -3
- package/dist/components/NodeStatusOverlay.svelte +14 -7
- package/dist/components/NodeSwapPicker.svelte +2 -1
- package/dist/components/PipelineStatus.svelte +10 -7
- package/dist/components/ReadOnlyDetails.svelte +4 -2
- package/dist/components/SchemaForm.svelte +20 -9
- package/dist/components/SchemaForm.svelte.d.ts +2 -4
- package/dist/components/SettingsModal.svelte +4 -3
- package/dist/components/SettingsPanel.svelte +3 -2
- package/dist/components/SwapMappingEditor.svelte +2 -1
- package/dist/components/WorkflowEditor.svelte +3 -2
- package/dist/components/chat/AIChatPanel.svelte +22 -7
- package/dist/components/chat/AIChatPanel.svelte.d.ts +3 -0
- package/dist/components/chat/CommandPreview.svelte +10 -6
- package/dist/components/console/CommandConsole.svelte +4 -3
- package/dist/components/form/FormArray.svelte +33 -20
- package/dist/components/form/FormArray.svelte.d.ts +3 -1
- package/dist/components/form/FormAutocomplete.svelte +18 -7
- package/dist/components/form/FormCodeEditor.svelte +2 -1
- package/dist/components/form/FormFieldWrapper.svelte +2 -1
- package/dist/components/form/FormMarkdownEditor.svelte +152 -108
- package/dist/components/form/FormMarkdownEditor.svelte.d.ts +1 -1
- package/dist/components/form/FormTemplateEditor.svelte +2 -1
- package/dist/components/form/FormToggle.svelte +23 -5
- package/dist/components/form/FormToggle.svelte.d.ts +6 -2
- package/dist/components/interrupt/ChoicePrompt.svelte +14 -5
- package/dist/components/interrupt/ConfirmationPrompt.svelte +8 -5
- package/dist/components/interrupt/FormPrompt.svelte +28 -7
- package/dist/components/interrupt/InterruptBubble.svelte +27 -18
- package/dist/components/interrupt/ReviewPrompt.svelte +32 -22
- package/dist/components/interrupt/TextInputPrompt.svelte +12 -5
- package/dist/components/layouts/MainLayout.svelte +4 -3
- package/dist/components/nodes/GatewayNode.svelte +8 -3
- package/dist/components/nodes/IdeaNode.svelte +2 -1
- package/dist/components/nodes/NotesNode.svelte +18 -12
- package/dist/components/nodes/WorkflowNode.svelte +8 -3
- package/dist/components/playground/ChatPanel.svelte +36 -24
- package/dist/components/playground/MessageBubble.svelte +15 -7
- package/dist/components/playground/Playground.svelte +2 -1
- package/dist/components/playground/PlaygroundModal.svelte +2 -1
- package/dist/components/playground/SessionManager.svelte +14 -10
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +9 -0
- package/dist/editor/index.d.ts +1 -1
- package/dist/editor/index.js +1 -1
- package/dist/messages/context.d.ts +29 -0
- package/dist/messages/context.js +38 -0
- package/dist/messages/defaults.d.ts +396 -0
- package/dist/messages/defaults.js +356 -0
- package/dist/messages/deprecation.d.ts +20 -0
- package/dist/messages/deprecation.js +33 -0
- package/dist/messages/index.d.ts +11 -0
- package/dist/messages/index.js +10 -0
- package/dist/messages/merge.d.ts +28 -0
- package/dist/messages/merge.js +53 -0
- package/dist/messages/types.d.ts +29 -0
- package/dist/messages/types.js +13 -0
- package/dist/services/draftStorage.d.ts +13 -0
- package/dist/services/draftStorage.js +36 -0
- package/dist/styles/base.css +13 -4
- package/dist/svelte-app.d.ts +11 -0
- package/dist/svelte-app.js +11 -2
- package/package.json +1 -1
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
} from '../../stores/interruptStore.svelte.js';
|
|
38
38
|
import { interruptService } from '../../services/interruptService.js';
|
|
39
39
|
import { logger } from '../../utils/logger.js';
|
|
40
|
+
import { m } from '../../messages/index.js';
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
43
|
* Component props
|
|
@@ -105,41 +106,46 @@
|
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
// Hoist the bubble branch — five reads inside the header alone.
|
|
110
|
+
const t = $derived(m().interrupt.bubble);
|
|
111
|
+
|
|
108
112
|
/**
|
|
109
113
|
* Get the label for the interrupt type
|
|
110
114
|
*/
|
|
111
115
|
function getTypeLabel(type: InterruptType): string {
|
|
116
|
+
const required = t.required;
|
|
112
117
|
switch (type) {
|
|
113
118
|
case 'confirmation':
|
|
114
|
-
return
|
|
119
|
+
return required.confirmation;
|
|
115
120
|
case 'choice':
|
|
116
|
-
return
|
|
121
|
+
return required.selection;
|
|
117
122
|
case 'text':
|
|
118
|
-
return
|
|
123
|
+
return required.input;
|
|
119
124
|
case 'form':
|
|
120
|
-
return
|
|
125
|
+
return required.form;
|
|
121
126
|
case 'review':
|
|
122
|
-
return
|
|
127
|
+
return required.review;
|
|
123
128
|
default:
|
|
124
|
-
return
|
|
129
|
+
return required.default;
|
|
125
130
|
}
|
|
126
131
|
}
|
|
127
132
|
|
|
128
133
|
/** Get resolved label for the header when resolved */
|
|
129
134
|
function getResolvedLabel(type: InterruptType): string {
|
|
135
|
+
const submitted = t.submitted;
|
|
130
136
|
switch (type) {
|
|
131
137
|
case 'confirmation':
|
|
132
|
-
return
|
|
138
|
+
return submitted.confirmation;
|
|
133
139
|
case 'choice':
|
|
134
|
-
return
|
|
140
|
+
return submitted.selection;
|
|
135
141
|
case 'text':
|
|
136
|
-
return
|
|
142
|
+
return submitted.input;
|
|
137
143
|
case 'form':
|
|
138
|
-
return
|
|
144
|
+
return submitted.form;
|
|
139
145
|
case 'review':
|
|
140
|
-
return
|
|
146
|
+
return submitted.review;
|
|
141
147
|
default:
|
|
142
|
-
return
|
|
148
|
+
return submitted.default;
|
|
143
149
|
}
|
|
144
150
|
}
|
|
145
151
|
|
|
@@ -257,10 +263,10 @@
|
|
|
257
263
|
<Icon icon={getTypeIcon(currentInterrupt.type)} />
|
|
258
264
|
{#if isResolved}
|
|
259
265
|
{currentInterrupt.machineState.status === 'cancelled'
|
|
260
|
-
?
|
|
266
|
+
? t.cancelled
|
|
261
267
|
: getResolvedLabel(currentInterrupt.type)}
|
|
262
268
|
{:else if currentInterrupt.machineState.status === 'error'}
|
|
263
|
-
|
|
269
|
+
{t.errorRetry}
|
|
264
270
|
{:else}
|
|
265
271
|
{getTypeLabel(currentInterrupt.type)}
|
|
266
272
|
{/if}
|
|
@@ -279,7 +285,7 @@
|
|
|
279
285
|
<span>{error}</span>
|
|
280
286
|
<button type="button" class="interrupt-bubble__retry-btn" onclick={handleRetry}>
|
|
281
287
|
<Icon icon="mdi:refresh" />
|
|
282
|
-
|
|
288
|
+
{t.retry}
|
|
283
289
|
</button>
|
|
284
290
|
</div>
|
|
285
291
|
{/if}
|
|
@@ -344,9 +350,12 @@
|
|
|
344
350
|
{#if currentInterrupt.nodeId || (currentInterrupt.allowCancel && !isResolved && currentInterrupt.type !== 'confirmation')}
|
|
345
351
|
<div class="interrupt-bubble__footer">
|
|
346
352
|
{#if currentInterrupt.nodeId}
|
|
347
|
-
<span
|
|
353
|
+
<span
|
|
354
|
+
class="interrupt-bubble__node"
|
|
355
|
+
title={t.nodeIdTooltip({ id: currentInterrupt.nodeId })}
|
|
356
|
+
>
|
|
348
357
|
<Icon icon="mdi:graph" />
|
|
349
|
-
<span>
|
|
358
|
+
<span>{t.fromWorkflow}</span>
|
|
350
359
|
</span>
|
|
351
360
|
{/if}
|
|
352
361
|
{#if currentInterrupt.allowCancel && !isResolved && currentInterrupt.type !== 'confirmation'}
|
|
@@ -357,7 +366,7 @@
|
|
|
357
366
|
disabled={isSubmitting}
|
|
358
367
|
>
|
|
359
368
|
<Icon icon="mdi:close" />
|
|
360
|
-
<span>
|
|
369
|
+
<span>{t.cancel}</span>
|
|
361
370
|
</button>
|
|
362
371
|
{/if}
|
|
363
372
|
</div>
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
ReviewResolution,
|
|
19
19
|
ReviewFieldDecision
|
|
20
20
|
} from '../../types/interrupt.js';
|
|
21
|
+
import { m } from '../../messages/index.js';
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Component props
|
|
@@ -70,10 +71,14 @@
|
|
|
70
71
|
/** Total number of changes */
|
|
71
72
|
const totalCount = $derived(config.changes.length);
|
|
72
73
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
74
|
+
// Hoist the review branch — 18 reads inside the template, plus three label
|
|
75
|
+
// resolvers below. One getter walk per render is enough.
|
|
76
|
+
const t = $derived(m().interrupt.review);
|
|
77
|
+
|
|
78
|
+
/** Button labels — config wins, falls back to messages tree. */
|
|
79
|
+
const acceptAllLabel = $derived(config.acceptAllLabel ?? t.acceptAll);
|
|
80
|
+
const rejectAllLabel = $derived(config.rejectAllLabel ?? t.rejectAll);
|
|
81
|
+
const submitLabel = $derived(config.submitLabel ?? t.submit);
|
|
77
82
|
|
|
78
83
|
/**
|
|
79
84
|
* Set a specific field's decision
|
|
@@ -166,9 +171,9 @@
|
|
|
166
171
|
* Format a value for display
|
|
167
172
|
*/
|
|
168
173
|
function formatValue(value: unknown): string {
|
|
169
|
-
if (value === null || value === undefined) return
|
|
174
|
+
if (value === null || value === undefined) return t.empty;
|
|
170
175
|
if (typeof value === 'string') return value;
|
|
171
|
-
if (typeof value === 'boolean') return value ?
|
|
176
|
+
if (typeof value === 'boolean') return value ? t.yes : t.no;
|
|
172
177
|
if (typeof value === 'object') return JSON.stringify(value, null, 2);
|
|
173
178
|
return String(value);
|
|
174
179
|
}
|
|
@@ -258,7 +263,7 @@
|
|
|
258
263
|
</button>
|
|
259
264
|
</div>
|
|
260
265
|
<span class="review-prompt__counter">
|
|
261
|
-
{acceptedCount
|
|
266
|
+
{t.counter({ accepted: acceptedCount, total: totalCount })}
|
|
262
267
|
</span>
|
|
263
268
|
</div>
|
|
264
269
|
{/if}
|
|
@@ -288,11 +293,11 @@
|
|
|
288
293
|
class:review-prompt__toggle-btn--active={isAccepted}
|
|
289
294
|
onclick={() => setFieldDecision(change.field, true)}
|
|
290
295
|
disabled={isSubmitting}
|
|
291
|
-
aria-label=
|
|
292
|
-
title=
|
|
296
|
+
aria-label={t.acceptItem({ label: change.label })}
|
|
297
|
+
title={t.accept}
|
|
293
298
|
>
|
|
294
299
|
<Icon icon="mdi:check" />
|
|
295
|
-
<span>
|
|
300
|
+
<span>{t.accept}</span>
|
|
296
301
|
</button>
|
|
297
302
|
<button
|
|
298
303
|
type="button"
|
|
@@ -300,11 +305,11 @@
|
|
|
300
305
|
class:review-prompt__toggle-btn--active={!isAccepted}
|
|
301
306
|
onclick={() => setFieldDecision(change.field, false)}
|
|
302
307
|
disabled={isSubmitting}
|
|
303
|
-
aria-label=
|
|
304
|
-
title=
|
|
308
|
+
aria-label={t.rejectItem({ label: change.label })}
|
|
309
|
+
title={t.reject}
|
|
305
310
|
>
|
|
306
311
|
<Icon icon="mdi:close" />
|
|
307
|
-
<span>
|
|
312
|
+
<span>{t.reject}</span>
|
|
308
313
|
</button>
|
|
309
314
|
</div>
|
|
310
315
|
{:else}
|
|
@@ -315,10 +320,10 @@
|
|
|
315
320
|
>
|
|
316
321
|
{#if isAccepted}
|
|
317
322
|
<Icon icon="mdi:check-circle" />
|
|
318
|
-
<span>
|
|
323
|
+
<span>{t.accepted}</span>
|
|
319
324
|
{:else}
|
|
320
325
|
<Icon icon="mdi:close-circle" />
|
|
321
|
-
<span>
|
|
326
|
+
<span>{t.rejected}</span>
|
|
322
327
|
{/if}
|
|
323
328
|
</span>
|
|
324
329
|
{/if}
|
|
@@ -334,12 +339,12 @@
|
|
|
334
339
|
onclick={() => toggleHtmlView(change.field)}
|
|
335
340
|
>
|
|
336
341
|
<Icon icon={isRawView ? 'mdi:eye' : 'mdi:code-tags'} />
|
|
337
|
-
<span>{isRawView ?
|
|
342
|
+
<span>{isRawView ? t.rendered : t.rawHtml}</span>
|
|
338
343
|
</button>
|
|
339
344
|
</div>
|
|
340
345
|
{/if}
|
|
341
346
|
<div class="review-prompt__diff-row">
|
|
342
|
-
<span class="review-prompt__diff-label">
|
|
347
|
+
<span class="review-prompt__diff-label">{t.original}</span>
|
|
343
348
|
{#if isHtml && !isRawView}
|
|
344
349
|
<span class="review-prompt__diff-value review-prompt__html-content"
|
|
345
350
|
>{@html sanitizeHtml(String(change.original))}</span
|
|
@@ -355,7 +360,7 @@
|
|
|
355
360
|
{/if}
|
|
356
361
|
</div>
|
|
357
362
|
<div class="review-prompt__diff-row">
|
|
358
|
-
<span class="review-prompt__diff-label">
|
|
363
|
+
<span class="review-prompt__diff-label">{t.proposed}</span>
|
|
359
364
|
{#if isHtml && !isRawView}
|
|
360
365
|
<span
|
|
361
366
|
class="review-prompt__diff-value review-prompt__diff-value--proposed review-prompt__html-content"
|
|
@@ -374,7 +379,7 @@
|
|
|
374
379
|
</div>
|
|
375
380
|
{#if diff}
|
|
376
381
|
<div class="review-prompt__diff-row">
|
|
377
|
-
<span class="review-prompt__diff-label">
|
|
382
|
+
<span class="review-prompt__diff-label">{t.diff}</span>
|
|
378
383
|
{#if isMultiLineDiff(diff)}
|
|
379
384
|
<pre
|
|
380
385
|
class="review-prompt__diff-value review-prompt__diff-block">{#each diff as part}{#if part.added}<span
|
|
@@ -425,8 +430,11 @@
|
|
|
425
430
|
{#if isResolved && resolvedValue}
|
|
426
431
|
<div class="review-prompt__summary">
|
|
427
432
|
<span class="review-prompt__summary-text">
|
|
428
|
-
{
|
|
429
|
-
.summary.
|
|
433
|
+
{t.summary({
|
|
434
|
+
accepted: resolvedValue.summary.accepted,
|
|
435
|
+
rejected: resolvedValue.summary.rejected,
|
|
436
|
+
total: resolvedValue.summary.total
|
|
437
|
+
})}
|
|
430
438
|
</span>
|
|
431
439
|
</div>
|
|
432
440
|
{/if}
|
|
@@ -436,7 +444,9 @@
|
|
|
436
444
|
<div class="review-prompt__resolved-badge">
|
|
437
445
|
<Icon icon="mdi:check-circle" />
|
|
438
446
|
<span>
|
|
439
|
-
{resolvedByUserName
|
|
447
|
+
{resolvedByUserName
|
|
448
|
+
? m().interrupt.responseSubmittedBy({ name: resolvedByUserName })
|
|
449
|
+
: m().interrupt.responseSubmitted}
|
|
440
450
|
</span>
|
|
441
451
|
</div>
|
|
442
452
|
{/if}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
<script lang="ts">
|
|
11
11
|
import Icon from '@iconify/svelte';
|
|
12
12
|
import type { TextConfig } from '../../types/interrupt.js';
|
|
13
|
+
import { m } from '../../messages/index.js';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Component props
|
|
@@ -41,6 +42,10 @@
|
|
|
41
42
|
onSubmit
|
|
42
43
|
}: Props = $props();
|
|
43
44
|
|
|
45
|
+
// Hoist the text branch — placeholder/min/submit reads, including duplicate
|
|
46
|
+
// placeholder in single- vs. multiline branches.
|
|
47
|
+
const t = $derived(m().interrupt.text);
|
|
48
|
+
|
|
44
49
|
/** Local state for input value */
|
|
45
50
|
// svelte-ignore state_referenced_locally — initial default, user edits the input
|
|
46
51
|
let inputValue = $state(config.defaultValue ?? '');
|
|
@@ -112,7 +117,7 @@
|
|
|
112
117
|
class="text-prompt__textarea"
|
|
113
118
|
class:text-prompt__textarea--resolved={isResolved}
|
|
114
119
|
value={displayValue}
|
|
115
|
-
placeholder={config.placeholder ??
|
|
120
|
+
placeholder={config.placeholder ?? t.placeholder}
|
|
116
121
|
disabled={isResolved || isSubmitting}
|
|
117
122
|
oninput={handleInput}
|
|
118
123
|
onkeydown={handleKeyDown}
|
|
@@ -126,7 +131,7 @@
|
|
|
126
131
|
class="text-prompt__input"
|
|
127
132
|
class:text-prompt__input--resolved={isResolved}
|
|
128
133
|
value={displayValue}
|
|
129
|
-
placeholder={config.placeholder ??
|
|
134
|
+
placeholder={config.placeholder ?? t.placeholder}
|
|
130
135
|
disabled={isResolved || isSubmitting}
|
|
131
136
|
oninput={handleInput}
|
|
132
137
|
onkeydown={handleKeyDown}
|
|
@@ -148,7 +153,7 @@
|
|
|
148
153
|
/ {config.maxLength}
|
|
149
154
|
{/if}
|
|
150
155
|
{#if config.minLength !== undefined}
|
|
151
|
-
(
|
|
156
|
+
{t.min({ n: config.minLength })}
|
|
152
157
|
{/if}
|
|
153
158
|
</span>
|
|
154
159
|
</div>
|
|
@@ -168,7 +173,7 @@
|
|
|
168
173
|
{:else}
|
|
169
174
|
<Icon icon="mdi:send" />
|
|
170
175
|
{/if}
|
|
171
|
-
<span>
|
|
176
|
+
<span>{t.submit}</span>
|
|
172
177
|
</button>
|
|
173
178
|
</div>
|
|
174
179
|
{/if}
|
|
@@ -178,7 +183,9 @@
|
|
|
178
183
|
<div class="text-prompt__resolved-badge">
|
|
179
184
|
<Icon icon="mdi:check-circle" />
|
|
180
185
|
<span>
|
|
181
|
-
{resolvedByUserName
|
|
186
|
+
{resolvedByUserName
|
|
187
|
+
? m().interrupt.responseSubmittedBy({ name: resolvedByUserName })
|
|
188
|
+
: m().interrupt.responseSubmitted}
|
|
182
189
|
</span>
|
|
183
190
|
</div>
|
|
184
191
|
{/if}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
<script lang="ts">
|
|
13
13
|
import { onMount } from 'svelte';
|
|
14
|
+
import { m } from '../../messages/index.js';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Configuration props for the MainLayout component
|
|
@@ -342,7 +343,7 @@
|
|
|
342
343
|
aria-valuenow={leftSidebarWidth}
|
|
343
344
|
aria-valuemin={leftSidebarMinWidth}
|
|
344
345
|
aria-valuemax={leftSidebarMaxWidth}
|
|
345
|
-
aria-label=
|
|
346
|
+
aria-label={m().layout.resizeLeftSidebar}
|
|
346
347
|
tabindex="0"
|
|
347
348
|
>
|
|
348
349
|
<div class="flowdrop-main-layout__divider-handle"></div>
|
|
@@ -377,7 +378,7 @@
|
|
|
377
378
|
aria-valuenow={bottomPanelHeightState}
|
|
378
379
|
aria-valuemin={bottomPanelMinHeight}
|
|
379
380
|
aria-valuemax={bottomPanelMaxHeight}
|
|
380
|
-
aria-label=
|
|
381
|
+
aria-label={m().layout.resizeBottomPanel}
|
|
381
382
|
tabindex="0"
|
|
382
383
|
>
|
|
383
384
|
<div
|
|
@@ -408,7 +409,7 @@
|
|
|
408
409
|
aria-valuenow={rightSidebarWidth}
|
|
409
410
|
aria-valuemin={rightSidebarMinWidth}
|
|
410
411
|
aria-valuemax={rightSidebarMaxWidth}
|
|
411
|
-
aria-label=
|
|
412
|
+
aria-label={m().layout.resizeRightSidebar}
|
|
412
413
|
tabindex="0"
|
|
413
414
|
>
|
|
414
415
|
<div class="flowdrop-main-layout__divider-handle"></div>
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
getPortBackgroundColor
|
|
20
20
|
} from '../../utils/colors.js';
|
|
21
21
|
import { getConnectedHandles } from '../../stores/workflowStore.svelte.js';
|
|
22
|
+
import { m } from '../../messages/index.js';
|
|
22
23
|
|
|
23
24
|
interface Props {
|
|
24
25
|
data: WorkflowNode['data'] & {
|
|
@@ -30,6 +31,10 @@
|
|
|
30
31
|
|
|
31
32
|
let props: Props = $props();
|
|
32
33
|
|
|
34
|
+
// Hoist the graph branch — three reads in the template, two inside
|
|
35
|
+
// {#each port} / {#each branch} loops. One getter walk per render.
|
|
36
|
+
const graph = $derived(m().nodes.graph);
|
|
37
|
+
|
|
33
38
|
/**
|
|
34
39
|
* Instance-specific title override from config.
|
|
35
40
|
* Falls back to the original label if not set.
|
|
@@ -159,7 +164,7 @@
|
|
|
159
164
|
onkeydown={handleKeydown}
|
|
160
165
|
role="button"
|
|
161
166
|
tabindex="0"
|
|
162
|
-
aria-label=
|
|
167
|
+
aria-label={graph.gatewayNode({ title: displayTitle })}
|
|
163
168
|
aria-describedby="node-description-{props.data.nodeId || 'unknown'}"
|
|
164
169
|
>
|
|
165
170
|
<!-- Node Header: expands in multiples of 10 (title row 40px + gap 10px + description 20px per line) -->
|
|
@@ -207,7 +212,7 @@
|
|
|
207
212
|
)}; --fd-handle-border-color: var(--fd-handle-border);"
|
|
208
213
|
role="button"
|
|
209
214
|
tabindex={0}
|
|
210
|
-
aria-label=
|
|
215
|
+
aria-label={graph.connectInputPort({ name: port.name })}
|
|
211
216
|
/>
|
|
212
217
|
|
|
213
218
|
<!-- Port Info: padding lives here so handle position is simple -->
|
|
@@ -295,7 +300,7 @@
|
|
|
295
300
|
)}; --fd-handle-border-color: var(--fd-handle-border);"
|
|
296
301
|
role="button"
|
|
297
302
|
tabindex={0}
|
|
298
|
-
aria-label=
|
|
303
|
+
aria-label={graph.connectBranch({ name: branch.name })}
|
|
299
304
|
/>
|
|
300
305
|
</div>
|
|
301
306
|
{/each}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import type { ConfigValues, NodeMetadata } from '../../types/index.js';
|
|
12
12
|
import Icon from '@iconify/svelte';
|
|
13
13
|
import { getDataTypeColor } from '../../utils/colors.js';
|
|
14
|
+
import { m } from '../../messages/index.js';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* IdeaNode component props
|
|
@@ -142,7 +143,7 @@
|
|
|
142
143
|
onkeydown={handleKeydown}
|
|
143
144
|
role="button"
|
|
144
145
|
tabindex="0"
|
|
145
|
-
aria-label=
|
|
146
|
+
aria-label={m().nodes.graph.ideaNode({ title: displayTitle })}
|
|
146
147
|
>
|
|
147
148
|
<!-- Left Port (Target/Input): center at top 40px (multiple of 10), 20px connection area -->
|
|
148
149
|
{#if enableLeftPort}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { ConfigValues, NodeMetadata } from '../../types/index.js';
|
|
3
3
|
import Icon from '@iconify/svelte';
|
|
4
4
|
import MarkdownDisplay from '../MarkdownDisplay.svelte';
|
|
5
|
+
import { m } from '../../messages/index.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* NotesNode component props
|
|
@@ -24,40 +25,45 @@
|
|
|
24
25
|
isError?: boolean;
|
|
25
26
|
}>();
|
|
26
27
|
|
|
28
|
+
// Hoist the notes branch — read for placeholder, every type name, processing,
|
|
29
|
+
// error, and configure tooltip.
|
|
30
|
+
const notes = $derived(m().nodes.notes);
|
|
31
|
+
|
|
27
32
|
/** Note content derived from config */
|
|
28
|
-
const noteContent = $derived((props.data.config?.content as string) ||
|
|
33
|
+
const noteContent = $derived((props.data.config?.content as string) || notes.placeholder);
|
|
29
34
|
|
|
30
35
|
/** Note type derived from config */
|
|
31
36
|
const noteType = $derived((props.data.config?.noteType as string) || 'info');
|
|
32
37
|
|
|
33
|
-
/** Note type configuration with styling for each type
|
|
34
|
-
|
|
38
|
+
/** Note type configuration with styling for each type. Type names track the
|
|
39
|
+
* messages tree so locale changes flow through. */
|
|
40
|
+
const noteTypes = $derived({
|
|
35
41
|
info: {
|
|
36
|
-
name:
|
|
42
|
+
name: notes.types.info,
|
|
37
43
|
typeClass: 'flowdrop-notes-node--info',
|
|
38
44
|
icon: 'mdi:information'
|
|
39
45
|
},
|
|
40
46
|
warning: {
|
|
41
|
-
name:
|
|
47
|
+
name: notes.types.warning,
|
|
42
48
|
typeClass: 'flowdrop-notes-node--warning',
|
|
43
49
|
icon: 'mdi:alert'
|
|
44
50
|
},
|
|
45
51
|
success: {
|
|
46
|
-
name:
|
|
52
|
+
name: notes.types.success,
|
|
47
53
|
typeClass: 'flowdrop-notes-node--success',
|
|
48
54
|
icon: 'mdi:check-circle'
|
|
49
55
|
},
|
|
50
56
|
error: {
|
|
51
|
-
name:
|
|
57
|
+
name: notes.types.error,
|
|
52
58
|
typeClass: 'flowdrop-notes-node--error',
|
|
53
59
|
icon: 'mdi:close-circle'
|
|
54
60
|
},
|
|
55
61
|
note: {
|
|
56
|
-
name:
|
|
62
|
+
name: notes.types.default,
|
|
57
63
|
typeClass: 'flowdrop-notes-node--note',
|
|
58
64
|
icon: 'mdi:note-text'
|
|
59
65
|
}
|
|
60
|
-
};
|
|
66
|
+
});
|
|
61
67
|
|
|
62
68
|
/** Current note type configuration based on selected type */
|
|
63
69
|
const currentType = $derived(noteTypes[noteType as keyof typeof noteTypes] || noteTypes.info);
|
|
@@ -126,7 +132,7 @@
|
|
|
126
132
|
{#if props.isProcessing}
|
|
127
133
|
<div class="flowdrop-notes-node__processing">
|
|
128
134
|
<div class="flowdrop-notes-node__spinner"></div>
|
|
129
|
-
<span>
|
|
135
|
+
<span>{notes.processing}</span>
|
|
130
136
|
</div>
|
|
131
137
|
{/if}
|
|
132
138
|
|
|
@@ -134,7 +140,7 @@
|
|
|
134
140
|
{#if props.isError}
|
|
135
141
|
<div class="flowdrop-notes-node__error-indicator">
|
|
136
142
|
<Icon icon="mdi:alert-circle" class="flowdrop-notes-node__error-icon" />
|
|
137
|
-
<span>
|
|
143
|
+
<span>{notes.errorOccurred}</span>
|
|
138
144
|
</div>
|
|
139
145
|
{/if}
|
|
140
146
|
</div>
|
|
@@ -143,7 +149,7 @@
|
|
|
143
149
|
<button
|
|
144
150
|
class="flowdrop-notes-node__config-btn"
|
|
145
151
|
onclick={openConfigSidebar}
|
|
146
|
-
title=
|
|
152
|
+
title={notes.configure}
|
|
147
153
|
>
|
|
148
154
|
<Icon icon="mdi:cog" />
|
|
149
155
|
</button>
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
} from '../../utils/colors.js';
|
|
25
25
|
import { getConnectedHandles } from '../../stores/workflowStore.svelte.js';
|
|
26
26
|
import { applyPortOrder } from '../../utils/portUtils.js';
|
|
27
|
+
import { m } from '../../messages/index.js';
|
|
27
28
|
|
|
28
29
|
interface Props {
|
|
29
30
|
data: WorkflowNode['data'] & {
|
|
@@ -36,6 +37,10 @@
|
|
|
36
37
|
let props: Props = $props();
|
|
37
38
|
let isHandleInteraction = $state(false);
|
|
38
39
|
|
|
40
|
+
// Hoist the graph branch — three reads in the template, two of them inside
|
|
41
|
+
// {#each port} loops where N×M reads add up. One getter walk per render.
|
|
42
|
+
const graph = $derived(m().nodes.graph);
|
|
43
|
+
|
|
39
44
|
/**
|
|
40
45
|
* Instance-specific title override from config.
|
|
41
46
|
* Falls back to the original label if not set.
|
|
@@ -205,7 +210,7 @@
|
|
|
205
210
|
handleDoubleClick();
|
|
206
211
|
}
|
|
207
212
|
}}
|
|
208
|
-
aria-label=
|
|
213
|
+
aria-label={graph.workflowNode({ name: props.data.metadata.name })}
|
|
209
214
|
aria-describedby="node-description-{props.data.nodeId || 'unknown'}"
|
|
210
215
|
>
|
|
211
216
|
<!-- Default Node Header: expands in multiples of 10 (title row 40px + gap 10px + description 20px per line) -->
|
|
@@ -261,7 +266,7 @@
|
|
|
261
266
|
)}); --fd-handle-border-color: var(--fd-handle-border);"
|
|
262
267
|
role="button"
|
|
263
268
|
tabindex={0}
|
|
264
|
-
aria-label=
|
|
269
|
+
aria-label={graph.connectInputPort({ name: port.name })}
|
|
265
270
|
/>
|
|
266
271
|
|
|
267
272
|
<!-- Port Info: padding lives here so handle position is simple -->
|
|
@@ -339,7 +344,7 @@
|
|
|
339
344
|
)}); --fd-handle-border-color: var(--fd-handle-border);"
|
|
340
345
|
role="button"
|
|
341
346
|
tabindex={0}
|
|
342
|
-
aria-label=
|
|
347
|
+
aria-label={graph.connectOutputPort({ name: port.name })}
|
|
343
348
|
/>
|
|
344
349
|
</div>
|
|
345
350
|
{/each}
|