@flowdrop/flowdrop 1.7.0 → 1.8.1
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/chat/responseParser.js +7 -0
- package/dist/commands/parser.js +12 -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 +33 -8
- 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
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
import { FormField } from './form/index.js';
|
|
62
62
|
import FormUISchemaRenderer from './form/FormUISchemaRenderer.svelte';
|
|
63
63
|
import type { FieldSchema } from './form/index.js';
|
|
64
|
+
import { m, warnDeprecatedProp } from '../messages/index.js';
|
|
64
65
|
|
|
65
66
|
/**
|
|
66
67
|
* Props interface for SchemaForm component
|
|
@@ -100,14 +101,12 @@
|
|
|
100
101
|
showActions?: boolean;
|
|
101
102
|
|
|
102
103
|
/**
|
|
103
|
-
*
|
|
104
|
-
* @default "Save"
|
|
104
|
+
* @deprecated since v1.8 — use `messages.form.schema.save`. Removed in v2.0.
|
|
105
105
|
*/
|
|
106
106
|
saveLabel?: string;
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
|
-
*
|
|
110
|
-
* @default "Cancel"
|
|
109
|
+
* @deprecated since v1.8 — use `messages.form.schema.cancel`. Removed in v2.0.
|
|
111
110
|
*/
|
|
112
111
|
cancelLabel?: string;
|
|
113
112
|
|
|
@@ -160,8 +159,8 @@
|
|
|
160
159
|
values = {},
|
|
161
160
|
onChange,
|
|
162
161
|
showActions = false,
|
|
163
|
-
saveLabel
|
|
164
|
-
cancelLabel
|
|
162
|
+
saveLabel,
|
|
163
|
+
cancelLabel,
|
|
165
164
|
onSave,
|
|
166
165
|
onCancel,
|
|
167
166
|
loading = false,
|
|
@@ -171,6 +170,18 @@
|
|
|
171
170
|
baseUrl = ''
|
|
172
171
|
}: Props = $props();
|
|
173
172
|
|
|
173
|
+
// svelte-ignore state_referenced_locally — deprecation warns once per mount; later prop rebinds aren't relevant
|
|
174
|
+
if (saveLabel !== undefined) {
|
|
175
|
+
warnDeprecatedProp('SchemaForm', 'saveLabel', 'messages.form.schema.save');
|
|
176
|
+
}
|
|
177
|
+
// svelte-ignore state_referenced_locally
|
|
178
|
+
if (cancelLabel !== undefined) {
|
|
179
|
+
warnDeprecatedProp('SchemaForm', 'cancelLabel', 'messages.form.schema.cancel');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const resolvedSaveLabel = $derived(saveLabel ?? m().form.schema.save);
|
|
183
|
+
const resolvedCancelLabel = $derived(cancelLabel ?? m().form.schema.cancel);
|
|
184
|
+
|
|
174
185
|
// Set context for child components (e.g., FormAutocomplete)
|
|
175
186
|
// Use getter functions to ensure child components always get the current prop value,
|
|
176
187
|
// even if the prop changes after initial mount
|
|
@@ -352,7 +363,7 @@
|
|
|
352
363
|
disabled={loading}
|
|
353
364
|
>
|
|
354
365
|
<Icon icon="heroicons:x-mark" class="schema-form__button-icon" />
|
|
355
|
-
<span>{
|
|
366
|
+
<span>{resolvedCancelLabel}</span>
|
|
356
367
|
</button>
|
|
357
368
|
<button
|
|
358
369
|
type="submit"
|
|
@@ -364,7 +375,7 @@
|
|
|
364
375
|
{:else}
|
|
365
376
|
<Icon icon="heroicons:check" class="schema-form__button-icon" />
|
|
366
377
|
{/if}
|
|
367
|
-
<span>{
|
|
378
|
+
<span>{resolvedSaveLabel}</span>
|
|
368
379
|
</button>
|
|
369
380
|
</div>
|
|
370
381
|
{/if}
|
|
@@ -374,7 +385,7 @@
|
|
|
374
385
|
<div class="schema-form__empty-icon">
|
|
375
386
|
<Icon icon="heroicons:document-text" />
|
|
376
387
|
</div>
|
|
377
|
-
<p class="schema-form__empty-text">
|
|
388
|
+
<p class="schema-form__empty-text">{m().form.schema.empty}</p>
|
|
378
389
|
</div>
|
|
379
390
|
{/if}
|
|
380
391
|
|
|
@@ -33,13 +33,11 @@ interface Props {
|
|
|
33
33
|
*/
|
|
34
34
|
showActions?: boolean;
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
37
|
-
* @default "Save"
|
|
36
|
+
* @deprecated since v1.8 — use `messages.form.schema.save`. Removed in v2.0.
|
|
38
37
|
*/
|
|
39
38
|
saveLabel?: string;
|
|
40
39
|
/**
|
|
41
|
-
*
|
|
42
|
-
* @default "Cancel"
|
|
40
|
+
* @deprecated since v1.8 — use `messages.form.schema.cancel`. Removed in v2.0.
|
|
43
41
|
*/
|
|
44
42
|
cancelLabel?: string;
|
|
45
43
|
/**
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
import Icon from '@iconify/svelte';
|
|
28
28
|
import SettingsPanel from './SettingsPanel.svelte';
|
|
29
29
|
import type { SettingsCategory } from '../types/settings.js';
|
|
30
|
+
import { m } from '../messages/index.js';
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* Props interface for SettingsModal component
|
|
@@ -131,13 +132,13 @@
|
|
|
131
132
|
<div class="flowdrop-settings-modal__header">
|
|
132
133
|
<h2 id="settings-modal-title" class="flowdrop-settings-modal__title">
|
|
133
134
|
<Icon icon="mdi:cog" class="flowdrop-settings-modal__title-icon" />
|
|
134
|
-
|
|
135
|
+
{m().navigation.settingsTitle}
|
|
135
136
|
</h2>
|
|
136
137
|
<button
|
|
137
138
|
class="flowdrop-settings-modal__close"
|
|
138
139
|
onclick={closeModal}
|
|
139
|
-
aria-label=
|
|
140
|
-
title=
|
|
140
|
+
aria-label={m().navigation.closeSettings}
|
|
141
|
+
title={m().common.close}
|
|
141
142
|
>
|
|
142
143
|
<Icon icon="mdi:close" />
|
|
143
144
|
</button>
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
<script lang="ts">
|
|
31
31
|
import Icon from '@iconify/svelte';
|
|
32
32
|
import { SchemaForm } from '../form/index.js';
|
|
33
|
+
import { m } from '../messages/index.js';
|
|
33
34
|
import type { ConfigSchema } from '../types/index.js';
|
|
34
35
|
import type { SettingsCategory } from '../types/settings.js';
|
|
35
36
|
import {
|
|
@@ -231,7 +232,7 @@
|
|
|
231
232
|
},
|
|
232
233
|
chatAutoRetry: {
|
|
233
234
|
type: 'boolean',
|
|
234
|
-
title: 'AI
|
|
235
|
+
title: 'AI Assistant Auto-retry',
|
|
235
236
|
description: 'Automatically ask the AI to self-correct when commands fail',
|
|
236
237
|
default: true
|
|
237
238
|
}
|
|
@@ -361,7 +362,7 @@
|
|
|
361
362
|
|
|
362
363
|
<div class="flowdrop-settings-panel {className}">
|
|
363
364
|
<!-- Tab Navigation -->
|
|
364
|
-
<div class="flowdrop-settings-panel__tabs" role="tablist" aria-label=
|
|
365
|
+
<div class="flowdrop-settings-panel__tabs" role="tablist" aria-label={m().layout.settingsCategories}>
|
|
365
366
|
{#each categories as category, index (category)}
|
|
366
367
|
<button
|
|
367
368
|
class="flowdrop-settings-panel__tab"
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import { getCategoryColorToken } from '../utils/colors.js';
|
|
15
15
|
import PortMappingRow from './PortMappingRow.svelte';
|
|
16
16
|
import ConfigMappingRow from './ConfigMappingRow.svelte';
|
|
17
|
+
import { m } from '../messages/index.js';
|
|
17
18
|
|
|
18
19
|
interface Props {
|
|
19
20
|
interactiveState: InteractiveSwapState;
|
|
@@ -129,7 +130,7 @@
|
|
|
129
130
|
<div class="swap-editor">
|
|
130
131
|
<!-- Header -->
|
|
131
132
|
<div class="swap-editor__header">
|
|
132
|
-
<button class="swap-editor__back" onclick={onBack} aria-label=
|
|
133
|
+
<button class="swap-editor__back" onclick={onBack} aria-label={m().layout.backToNodeSelection}>
|
|
133
134
|
<Icon icon="heroicons:arrow-left" />
|
|
134
135
|
</button>
|
|
135
136
|
<h2 class="swap-editor__title">Swap Mapping</h2>
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
import type { EndpointConfig } from '../config/endpoints.js';
|
|
36
36
|
import ConnectionLine from './ConnectionLine.svelte';
|
|
37
37
|
import FlowDropEdge from './FlowDropEdge.svelte';
|
|
38
|
+
import { m } from '../messages/index.js';
|
|
38
39
|
import { getWorkflowStore, workflowActions } from '../stores/workflowStore.svelte.js';
|
|
39
40
|
import { historyActions, setOnRestoreCallback } from '../stores/historyStore.svelte.js';
|
|
40
41
|
import UniversalNode from './UniversalNode.svelte';
|
|
@@ -835,8 +836,8 @@
|
|
|
835
836
|
class="flowdrop-console-toggle"
|
|
836
837
|
class:flowdrop-console-toggle--active={props.consoleOpen}
|
|
837
838
|
onclick={props.onToggleConsole}
|
|
838
|
-
aria-label=
|
|
839
|
-
title=
|
|
839
|
+
aria-label={m().layout.commandConsole}
|
|
840
|
+
title={m().layout.commandConsole}
|
|
840
841
|
type="button"
|
|
841
842
|
>
|
|
842
843
|
<Icon icon="heroicons:command-line" width="18" height="18" />
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import MarkdownDisplay from '../MarkdownDisplay.svelte';
|
|
16
16
|
import { tick } from 'svelte';
|
|
17
17
|
import Icon from '@iconify/svelte';
|
|
18
|
+
import { m, warnDeprecatedProp } from '../../messages/index.js';
|
|
18
19
|
|
|
19
20
|
// =========================================================================
|
|
20
21
|
// Internal Display Message Type
|
|
@@ -35,12 +36,26 @@
|
|
|
35
36
|
nodeTypes: NodeMetadata[];
|
|
36
37
|
workflowId?: string;
|
|
37
38
|
onUIAction?: (action: UIAction) => void;
|
|
39
|
+
/**
|
|
40
|
+
* @deprecated since v1.8 — use `messages.chat.placeholder`. Removed in v2.0.
|
|
41
|
+
*/
|
|
38
42
|
placeholder?: string;
|
|
39
43
|
endpointConfig?: EndpointConfig | null;
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
let { nodeTypes, workflowId, onUIAction, placeholder, endpointConfig }: Props = $props();
|
|
43
47
|
|
|
48
|
+
// svelte-ignore state_referenced_locally — deprecation warns once per mount; later prop rebinds aren't relevant
|
|
49
|
+
if (placeholder !== undefined) {
|
|
50
|
+
warnDeprecatedProp('AIChatPanel', 'placeholder', 'messages.chat.placeholder');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Hoist the chat branch — read in placeholder, header, three welcome states,
|
|
54
|
+
// auto-retry banner, and the send button aria-label.
|
|
55
|
+
const t = $derived(m().chat);
|
|
56
|
+
|
|
57
|
+
const resolvedPlaceholder = $derived(placeholder ?? t.placeholder);
|
|
58
|
+
|
|
44
59
|
// =========================================================================
|
|
45
60
|
// State
|
|
46
61
|
// =========================================================================
|
|
@@ -176,6 +191,11 @@
|
|
|
176
191
|
const msg = displayMessages[messageIndex];
|
|
177
192
|
if (!msg?.commandPreview) return;
|
|
178
193
|
|
|
194
|
+
// Capture pre-existing parse errors before execution. If the LLM produced
|
|
195
|
+
// a malformed batch (e.g. unclosed """), retrying tends to reproduce the
|
|
196
|
+
// same shape and just locks the input behind isLoading for the cascade.
|
|
197
|
+
const hadParseErrors = msg.commandPreview.some((c) => c.status === 'error');
|
|
198
|
+
|
|
179
199
|
const context = getCommandContext();
|
|
180
200
|
if (!context) {
|
|
181
201
|
for (const cmd of msg.commandPreview) {
|
|
@@ -256,7 +276,12 @@
|
|
|
256
276
|
return;
|
|
257
277
|
}
|
|
258
278
|
|
|
259
|
-
if (
|
|
279
|
+
if (
|
|
280
|
+
!hadParseErrors &&
|
|
281
|
+
getBehaviorSettings().chatAutoRetry &&
|
|
282
|
+
workflowId &&
|
|
283
|
+
autoRetryCount < MAX_AUTO_RETRIES
|
|
284
|
+
) {
|
|
260
285
|
autoRetryCount++;
|
|
261
286
|
const errorText = buildBatchErrorMessage(
|
|
262
287
|
completedCount,
|
|
@@ -365,18 +390,18 @@
|
|
|
365
390
|
}
|
|
366
391
|
</script>
|
|
367
392
|
|
|
368
|
-
<div class="ai-chat-panel" role="region" aria-label=
|
|
393
|
+
<div class="ai-chat-panel" role="region" aria-label={t.aiAssistant}>
|
|
369
394
|
{#if !isChatConfigured}
|
|
370
395
|
<!-- No backend configured -->
|
|
371
396
|
<div class="ai-chat-panel__notice">
|
|
372
397
|
<Icon icon="mdi:robot-off-outline" />
|
|
373
|
-
<span>
|
|
398
|
+
<span>{t.requiresBackend}</span>
|
|
374
399
|
</div>
|
|
375
400
|
{:else if isDisabled}
|
|
376
401
|
<!-- No workflow loaded -->
|
|
377
402
|
<div class="ai-chat-panel__notice">
|
|
378
403
|
<Icon icon="mdi:chat-sleep-outline" />
|
|
379
|
-
<span>
|
|
404
|
+
<span>{t.loadWorkflow}</span>
|
|
380
405
|
</div>
|
|
381
406
|
{:else}
|
|
382
407
|
<!-- Messages area -->
|
|
@@ -384,7 +409,7 @@
|
|
|
384
409
|
{#if displayMessages.length === 0}
|
|
385
410
|
<div class="ai-chat-panel__empty">
|
|
386
411
|
<Icon icon="mdi:chat-outline" />
|
|
387
|
-
<span>
|
|
412
|
+
<span>{t.helpBuild}</span>
|
|
388
413
|
</div>
|
|
389
414
|
{/if}
|
|
390
415
|
{#each displayMessages as message, msgIndex}
|
|
@@ -395,7 +420,7 @@
|
|
|
395
420
|
msgIndex === displayMessages.length - 1}
|
|
396
421
|
>
|
|
397
422
|
<Icon icon="mdi:autorenew" />
|
|
398
|
-
<span>
|
|
423
|
+
<span>{t.autoRetry({ attempt: message.retryAttempt, max: MAX_AUTO_RETRIES })}</span>
|
|
399
424
|
</div>
|
|
400
425
|
{:else}
|
|
401
426
|
<div class="ai-chat-panel__bubble ai-chat-panel__bubble--{message.role}">
|
|
@@ -443,7 +468,7 @@
|
|
|
443
468
|
bind:value={inputValue}
|
|
444
469
|
onkeydown={handleKeydown}
|
|
445
470
|
class="ai-chat-panel__input"
|
|
446
|
-
placeholder={
|
|
471
|
+
placeholder={resolvedPlaceholder}
|
|
447
472
|
rows="1"
|
|
448
473
|
disabled={isLoading}
|
|
449
474
|
></textarea>
|
|
@@ -451,7 +476,7 @@
|
|
|
451
476
|
class="ai-chat-panel__send"
|
|
452
477
|
onclick={sendMessage}
|
|
453
478
|
disabled={!canSend}
|
|
454
|
-
aria-label=
|
|
479
|
+
aria-label={t.send}
|
|
455
480
|
>
|
|
456
481
|
<Icon icon="mdi:send" />
|
|
457
482
|
</button>
|
|
@@ -5,6 +5,9 @@ interface Props {
|
|
|
5
5
|
nodeTypes: NodeMetadata[];
|
|
6
6
|
workflowId?: string;
|
|
7
7
|
onUIAction?: (action: UIAction) => void;
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated since v1.8 — use `messages.chat.placeholder`. Removed in v2.0.
|
|
10
|
+
*/
|
|
8
11
|
placeholder?: string;
|
|
9
12
|
endpointConfig?: EndpointConfig | null;
|
|
10
13
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { CommandPreviewItem } from '../../types/chat.js';
|
|
3
3
|
import Icon from '@iconify/svelte';
|
|
4
|
+
import { m } from '../../messages/index.js';
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
6
7
|
commands: CommandPreviewItem[];
|
|
@@ -24,9 +25,12 @@
|
|
|
24
25
|
resolvedAction = 'cancelled';
|
|
25
26
|
onCancel();
|
|
26
27
|
}
|
|
28
|
+
|
|
29
|
+
// Hoist the commandPreview branch — six template reads.
|
|
30
|
+
const t = $derived(m().chat.commandPreview);
|
|
27
31
|
</script>
|
|
28
32
|
|
|
29
|
-
<div class="command-preview" role="region" aria-label=
|
|
33
|
+
<div class="command-preview" role="region" aria-label={t.ariaLabel}>
|
|
30
34
|
<div class="command-preview__list">
|
|
31
35
|
{#each commands as command, i}
|
|
32
36
|
<div class="command-preview__item command-preview__item--{command.status}">
|
|
@@ -54,16 +58,16 @@
|
|
|
54
58
|
<span class="command-preview__resolved command-preview__resolved--applied">
|
|
55
59
|
{#if isExecuting}
|
|
56
60
|
<Icon icon="mdi:loading" />
|
|
57
|
-
|
|
61
|
+
{t.applying}
|
|
58
62
|
{:else}
|
|
59
63
|
<Icon icon="mdi:check-all" />
|
|
60
|
-
|
|
64
|
+
{t.applied}
|
|
61
65
|
{/if}
|
|
62
66
|
</span>
|
|
63
67
|
{:else if resolvedAction === 'cancelled'}
|
|
64
68
|
<span class="command-preview__resolved command-preview__resolved--cancelled">
|
|
65
69
|
<Icon icon="mdi:close" />
|
|
66
|
-
|
|
70
|
+
{t.dismissed}
|
|
67
71
|
</span>
|
|
68
72
|
{:else}
|
|
69
73
|
<button
|
|
@@ -72,14 +76,14 @@
|
|
|
72
76
|
disabled={!hasPending || isExecuting}
|
|
73
77
|
>
|
|
74
78
|
<Icon icon="mdi:check-all" />
|
|
75
|
-
|
|
79
|
+
{t.applyAll}
|
|
76
80
|
</button>
|
|
77
81
|
<button
|
|
78
82
|
class="command-preview__btn command-preview__btn--cancel"
|
|
79
83
|
onclick={handleCancel}
|
|
80
84
|
disabled={isExecuting}
|
|
81
85
|
>
|
|
82
|
-
|
|
86
|
+
{t.cancel}
|
|
83
87
|
</button>
|
|
84
88
|
{/if}
|
|
85
89
|
</div>
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
import { updateSettings, getUiSettings } from '../../stores/settingsStore.svelte.js';
|
|
24
24
|
import ConsoleInput from './ConsoleInput.svelte';
|
|
25
25
|
import ConsoleOutput, { type ConsoleEntry } from './ConsoleOutput.svelte';
|
|
26
|
+
import { m } from '../../messages/index.js';
|
|
26
27
|
import {
|
|
27
28
|
formatListNodes,
|
|
28
29
|
formatListEdges,
|
|
@@ -186,13 +187,13 @@
|
|
|
186
187
|
}
|
|
187
188
|
</script>
|
|
188
189
|
|
|
189
|
-
<div class="command-console" role="region" aria-label=
|
|
190
|
+
<div class="command-console" role="region" aria-label={m().layout.commandConsole}>
|
|
190
191
|
<div class="command-console__header">
|
|
191
|
-
<h2 class="command-console__title">
|
|
192
|
+
<h2 class="command-console__title">{m().navigation.bottomPanel.console}</h2>
|
|
192
193
|
<button
|
|
193
194
|
class="command-console__close"
|
|
194
195
|
onclick={closeConsole}
|
|
195
|
-
aria-label=
|
|
196
|
+
aria-label={m().layout.closeConsole}
|
|
196
197
|
type="button"
|
|
197
198
|
>
|
|
198
199
|
×
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
<script lang="ts">
|
|
21
21
|
import Icon from '@iconify/svelte';
|
|
22
22
|
import type { FieldSchema } from './types.js';
|
|
23
|
+
import { m, warnDeprecatedProp } from '../../messages/index.js';
|
|
23
24
|
|
|
24
25
|
interface Props {
|
|
25
26
|
/** Field identifier */
|
|
@@ -32,7 +33,9 @@
|
|
|
32
33
|
minItems?: number;
|
|
33
34
|
/** Maximum number of items allowed */
|
|
34
35
|
maxItems?: number;
|
|
35
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* @deprecated since v1.8 — use `messages.form.array.add`. Removed in v2.0.
|
|
38
|
+
*/
|
|
36
39
|
addLabel?: string;
|
|
37
40
|
/** Whether the field is disabled */
|
|
38
41
|
disabled?: boolean;
|
|
@@ -46,11 +49,21 @@
|
|
|
46
49
|
itemSchema,
|
|
47
50
|
minItems = 0,
|
|
48
51
|
maxItems,
|
|
49
|
-
addLabel
|
|
52
|
+
addLabel,
|
|
50
53
|
disabled = false,
|
|
51
54
|
onChange
|
|
52
55
|
}: Props = $props();
|
|
53
56
|
|
|
57
|
+
// svelte-ignore state_referenced_locally — deprecation warns once per mount; later prop rebinds aren't relevant
|
|
58
|
+
if (addLabel !== undefined) {
|
|
59
|
+
warnDeprecatedProp('FormArray', 'addLabel', 'messages.form.array.add');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Hoist the array branch — every {#each} iteration would otherwise re-walk
|
|
63
|
+
// `m().form.array.*` for ~6 keys per item. One getter call instead of N×6.
|
|
64
|
+
const t = $derived(m().form.array);
|
|
65
|
+
const resolvedAddLabel = $derived(addLabel ?? t.add);
|
|
66
|
+
|
|
54
67
|
/**
|
|
55
68
|
* Ensure value is always an array
|
|
56
69
|
*/
|
|
@@ -197,7 +210,7 @@
|
|
|
197
210
|
const itemStr = String(item);
|
|
198
211
|
return itemStr.length > 30
|
|
199
212
|
? `${itemStr.substring(0, 30)}...`
|
|
200
|
-
: itemStr ||
|
|
213
|
+
: itemStr || t.itemLabel({ n: index + 1 });
|
|
201
214
|
}
|
|
202
215
|
|
|
203
216
|
// For objects, try to find a name/label/title property
|
|
@@ -211,7 +224,7 @@
|
|
|
211
224
|
}
|
|
212
225
|
}
|
|
213
226
|
|
|
214
|
-
return
|
|
227
|
+
return t.itemLabel({ n: index + 1 });
|
|
215
228
|
}
|
|
216
229
|
|
|
217
230
|
/**
|
|
@@ -260,7 +273,7 @@
|
|
|
260
273
|
class="form-array__item-toggle"
|
|
261
274
|
onclick={() => toggleCollapse(index)}
|
|
262
275
|
aria-expanded={!isCollapsed(index)}
|
|
263
|
-
aria-label={isCollapsed(index) ?
|
|
276
|
+
aria-label={isCollapsed(index) ? t.expandItem : t.collapseItem}
|
|
264
277
|
>
|
|
265
278
|
<Icon
|
|
266
279
|
icon={isCollapsed(index) ? 'heroicons:chevron-right' : 'heroicons:chevron-down'}
|
|
@@ -280,8 +293,8 @@
|
|
|
280
293
|
class="form-array__action-btn form-array__action-btn--move"
|
|
281
294
|
onclick={() => moveItemUp(index)}
|
|
282
295
|
disabled={index === 0 || disabled}
|
|
283
|
-
aria-label=
|
|
284
|
-
title=
|
|
296
|
+
aria-label={t.moveItemUp({ n: index + 1 })}
|
|
297
|
+
title={t.moveUp}
|
|
285
298
|
>
|
|
286
299
|
<Icon icon="heroicons:arrow-up" />
|
|
287
300
|
</button>
|
|
@@ -292,8 +305,8 @@
|
|
|
292
305
|
class="form-array__action-btn form-array__action-btn--move"
|
|
293
306
|
onclick={() => moveItemDown(index)}
|
|
294
307
|
disabled={index === items.length - 1 || disabled}
|
|
295
|
-
aria-label=
|
|
296
|
-
title=
|
|
308
|
+
aria-label={t.moveItemDown({ n: index + 1 })}
|
|
309
|
+
title={t.moveDown}
|
|
297
310
|
>
|
|
298
311
|
<Icon icon="heroicons:arrow-down" />
|
|
299
312
|
</button>
|
|
@@ -304,8 +317,8 @@
|
|
|
304
317
|
class="form-array__action-btn form-array__action-btn--delete"
|
|
305
318
|
onclick={() => removeItem(index)}
|
|
306
319
|
disabled={!canRemoveItem || disabled}
|
|
307
|
-
aria-label=
|
|
308
|
-
title=
|
|
320
|
+
aria-label={t.deleteItem({ n: index + 1 })}
|
|
321
|
+
title={t.delete}
|
|
309
322
|
>
|
|
310
323
|
<Icon icon="heroicons:trash" />
|
|
311
324
|
</button>
|
|
@@ -366,7 +379,7 @@
|
|
|
366
379
|
<span class="form-array__toggle-thumb"></span>
|
|
367
380
|
</span>
|
|
368
381
|
<span class="form-array__toggle-label">
|
|
369
|
-
{item ?
|
|
382
|
+
{item ? t.yes : t.no}
|
|
370
383
|
</span>
|
|
371
384
|
</label>
|
|
372
385
|
{:else if itemSchema.enum}
|
|
@@ -480,7 +493,7 @@
|
|
|
480
493
|
<span class="form-array__toggle-thumb"></span>
|
|
481
494
|
</span>
|
|
482
495
|
<span class="form-array__toggle-label">
|
|
483
|
-
{propValue ?
|
|
496
|
+
{propValue ? t.yes : t.no}
|
|
484
497
|
</span>
|
|
485
498
|
</label>
|
|
486
499
|
{:else}
|
|
@@ -510,7 +523,7 @@
|
|
|
510
523
|
<!-- Unknown complex type -->
|
|
511
524
|
<div class="form-array__unsupported">
|
|
512
525
|
<p>
|
|
513
|
-
|
|
526
|
+
{t.unsupported({ type: String(itemSchema.type ?? '') })}
|
|
514
527
|
</p>
|
|
515
528
|
</div>
|
|
516
529
|
{/if}
|
|
@@ -522,7 +535,7 @@
|
|
|
522
535
|
<!-- Empty State -->
|
|
523
536
|
<div class="form-array__empty">
|
|
524
537
|
<Icon icon="heroicons:squares-plus" class="form-array__empty-icon" />
|
|
525
|
-
<p class="form-array__empty-text">
|
|
538
|
+
<p class="form-array__empty-text">{t.empty}</p>
|
|
526
539
|
</div>
|
|
527
540
|
{/if}
|
|
528
541
|
|
|
@@ -532,21 +545,21 @@
|
|
|
532
545
|
class="form-array__add-btn"
|
|
533
546
|
onclick={addItem}
|
|
534
547
|
disabled={!canAddItem || disabled}
|
|
535
|
-
aria-label={
|
|
548
|
+
aria-label={resolvedAddLabel}
|
|
536
549
|
>
|
|
537
550
|
<Icon icon="heroicons:plus" />
|
|
538
|
-
<span>{
|
|
551
|
+
<span>{resolvedAddLabel}</span>
|
|
539
552
|
</button>
|
|
540
553
|
|
|
541
554
|
<!-- Item count and limits -->
|
|
542
555
|
{#if minItems > 0 || maxItems !== undefined}
|
|
543
556
|
<div class="form-array__info">
|
|
544
|
-
<span class="form-array__count">{
|
|
557
|
+
<span class="form-array__count">{t.count({ n: items.length })}</span>
|
|
545
558
|
{#if minItems > 0}
|
|
546
|
-
<span class="form-array__limit">
|
|
559
|
+
<span class="form-array__limit">{t.min({ n: minItems })}</span>
|
|
547
560
|
{/if}
|
|
548
561
|
{#if maxItems !== undefined}
|
|
549
|
-
<span class="form-array__limit">
|
|
562
|
+
<span class="form-array__limit">{t.max({ n: maxItems })}</span>
|
|
550
563
|
{/if}
|
|
551
564
|
</div>
|
|
552
565
|
{/if}
|
|
@@ -10,7 +10,9 @@ interface Props {
|
|
|
10
10
|
minItems?: number;
|
|
11
11
|
/** Maximum number of items allowed */
|
|
12
12
|
maxItems?: number;
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* @deprecated since v1.8 — use `messages.form.array.add`. Removed in v2.0.
|
|
15
|
+
*/
|
|
14
16
|
addLabel?: string;
|
|
15
17
|
/** Whether the field is disabled */
|
|
16
18
|
disabled?: boolean;
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
import type { FieldOption } from './types.js';
|
|
28
28
|
import { buildFetchHeaders } from '../../utils/fetchWithAuth.js';
|
|
29
29
|
import { logger } from '../../utils/logger.js';
|
|
30
|
+
import { m } from '../../messages/index.js';
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* Props interface for FormAutocomplete component
|
|
@@ -68,6 +69,10 @@
|
|
|
68
69
|
);
|
|
69
70
|
const getBaseUrl = getContext<(() => string) | undefined>('flowdrop:getBaseUrl');
|
|
70
71
|
|
|
72
|
+
// Hoist the autocomplete branch — seven reads in the template, one inside
|
|
73
|
+
// an {#each tag} loop. One getter walk per render.
|
|
74
|
+
const t = $derived(m().form.autocomplete);
|
|
75
|
+
|
|
71
76
|
// Configuration with defaults
|
|
72
77
|
const queryParam = $derived(autocomplete.queryParam ?? 'q');
|
|
73
78
|
const minChars = $derived(autocomplete.minChars ?? 0);
|
|
@@ -579,7 +584,9 @@
|
|
|
579
584
|
<button
|
|
580
585
|
type="button"
|
|
581
586
|
class="form-autocomplete__tag-remove"
|
|
582
|
-
aria-label={
|
|
587
|
+
aria-label={t.removeTag({
|
|
588
|
+
label: getDisplayLabel(selectedVal)
|
|
589
|
+
})}
|
|
583
590
|
onclick={(e) => {
|
|
584
591
|
e.stopPropagation();
|
|
585
592
|
removeTag(selectedVal);
|
|
@@ -622,14 +629,14 @@
|
|
|
622
629
|
<!-- Status icons -->
|
|
623
630
|
<div class="form-autocomplete__icons">
|
|
624
631
|
{#if isLoading}
|
|
625
|
-
<span class="form-autocomplete__spinner" aria-label=
|
|
632
|
+
<span class="form-autocomplete__spinner" aria-label={t.loading}>
|
|
626
633
|
<Icon icon="heroicons:arrow-path" />
|
|
627
634
|
</span>
|
|
628
635
|
{:else if selectedValues.length > 0 && !disabled}
|
|
629
636
|
<button
|
|
630
637
|
type="button"
|
|
631
638
|
class="form-autocomplete__clear"
|
|
632
|
-
aria-label=
|
|
639
|
+
aria-label={t.clearAll}
|
|
633
640
|
onclick={(e) => {
|
|
634
641
|
e.stopPropagation();
|
|
635
642
|
handleClearAll();
|
|
@@ -657,24 +664,28 @@
|
|
|
657
664
|
style={popoverStyle}
|
|
658
665
|
onmousedown={(e) => e.preventDefault()}
|
|
659
666
|
>
|
|
660
|
-
<ul
|
|
667
|
+
<ul
|
|
668
|
+
class="form-autocomplete__listbox"
|
|
669
|
+
role="listbox"
|
|
670
|
+
aria-label={t.suggestions}
|
|
671
|
+
>
|
|
661
672
|
{#if isLoading}
|
|
662
673
|
<li class="form-autocomplete__status form-autocomplete__status--loading">
|
|
663
674
|
<Icon icon="heroicons:arrow-path" class="form-autocomplete__status-icon" />
|
|
664
|
-
<span>
|
|
675
|
+
<span>{t.loadingPending}</span>
|
|
665
676
|
</li>
|
|
666
677
|
{:else if error}
|
|
667
678
|
<li class="form-autocomplete__status form-autocomplete__status--error">
|
|
668
679
|
<Icon icon="heroicons:exclamation-triangle" class="form-autocomplete__status-icon" />
|
|
669
680
|
<span>{error}</span>
|
|
670
681
|
<button type="button" class="form-autocomplete__retry" onclick={handleRetry}>
|
|
671
|
-
|
|
682
|
+
{t.retry}
|
|
672
683
|
</button>
|
|
673
684
|
</li>
|
|
674
685
|
{:else if suggestions.length === 0}
|
|
675
686
|
<li class="form-autocomplete__status form-autocomplete__status--empty">
|
|
676
687
|
<Icon icon="heroicons:magnifying-glass" class="form-autocomplete__status-icon" />
|
|
677
|
-
<span>
|
|
688
|
+
<span>{t.noResults}</span>
|
|
678
689
|
</li>
|
|
679
690
|
{:else}
|
|
680
691
|
{#each suggestions as option, index (option.value)}
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
import { json, jsonParseLinter } from '@codemirror/lang-json';
|
|
32
32
|
import { oneDark } from '@codemirror/theme-one-dark';
|
|
33
33
|
import { linter } from '@codemirror/lint';
|
|
34
|
+
import { m } from '../../messages/index.js';
|
|
34
35
|
|
|
35
36
|
interface Props {
|
|
36
37
|
/** Field identifier */
|
|
@@ -322,7 +323,7 @@
|
|
|
322
323
|
class:form-code-editor__container--dark={darkTheme}
|
|
323
324
|
role="textbox"
|
|
324
325
|
aria-multiline="true"
|
|
325
|
-
aria-label=
|
|
326
|
+
aria-label={m().form.code.editor}
|
|
326
327
|
onblur={formatContent}
|
|
327
328
|
></div>
|
|
328
329
|
|