@flowdrop/flowdrop 1.15.0 → 2.0.0-beta.2
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/CHANGELOG.md +508 -0
- package/MIGRATION-2.0.md +629 -0
- package/README.md +23 -23
- package/dist/adapters/WorkflowAdapter.d.ts +1 -1
- package/dist/adapters/WorkflowAdapter.js +14 -8
- package/dist/adapters/agentspec/AgentSpecAdapter.js +7 -7
- package/dist/api/enhanced-client.js +6 -11
- package/dist/chat/batchFeedback.d.ts +39 -0
- package/dist/chat/batchFeedback.js +51 -0
- package/dist/commands/executor.js +15 -1
- package/dist/commands/storeIntegration.svelte.d.ts +4 -1
- package/dist/commands/storeIntegration.svelte.js +26 -21
- package/dist/commands/types.d.ts +2 -0
- package/dist/components/App.svelte +163 -192
- package/dist/components/App.svelte.d.ts +47 -8
- package/dist/components/ConfigForm.svelte +77 -49
- package/dist/components/ConfigModal.svelte +7 -2
- package/dist/components/ConnectionLine.svelte +4 -2
- package/dist/components/Navbar.svelte +61 -1
- package/dist/components/NodeSidebar.svelte +27 -45
- package/dist/components/NodeStatusOverlay.svelte +94 -6
- package/dist/components/NodeSwapPicker.svelte +10 -8
- package/dist/components/PipelineStatus.svelte +22 -68
- package/dist/components/PipelineStatus.svelte.d.ts +3 -0
- package/dist/components/PortCoordinateTracker.svelte +5 -6
- package/dist/components/SchemaForm.stories.svelte +1 -3
- package/dist/components/SchemaForm.svelte +22 -27
- package/dist/components/SchemaForm.svelte.d.ts +0 -8
- package/dist/components/SettingsModal.svelte +8 -3
- package/dist/components/SettingsPanel.svelte +20 -4
- package/dist/components/SwapMappingEditor.svelte +67 -49
- package/dist/components/SwapMappingEditor.svelte.d.ts +0 -2
- package/dist/components/UniversalNode.svelte +9 -7
- package/dist/components/WorkflowEditor.svelte +121 -111
- package/dist/components/WorkflowEditor.svelte.d.ts +21 -10
- package/dist/components/chat/AIChatPanel.svelte +98 -89
- package/dist/components/chat/AIChatPanel.svelte.d.ts +0 -4
- package/dist/components/chat/CommandPreview.svelte +2 -1
- package/dist/components/console/CommandConsole.svelte +7 -5
- package/dist/components/console/ConsoleAutocomplete.svelte +10 -11
- package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +6 -0
- package/dist/components/console/ConsoleInput.svelte +15 -6
- package/dist/components/console/ConsoleOutput.svelte +2 -1
- package/dist/components/form/FormArray.svelte +5 -9
- package/dist/components/form/FormArray.svelte.d.ts +2 -1
- package/dist/components/form/FormAutocomplete.svelte +16 -15
- package/dist/components/form/FormField.svelte +4 -2
- package/dist/components/form/FormFieldLight.svelte +34 -3
- package/dist/components/form/FormFieldLight.svelte.d.ts +12 -0
- package/dist/components/form/FormMarkdownEditor.svelte +9 -4
- package/dist/components/form/FormRangeField.svelte +1 -0
- package/dist/components/form/FormTemplateEditor.svelte +11 -3
- package/dist/components/form/FormToggle.svelte +5 -12
- package/dist/components/form/FormToggle.svelte.d.ts +4 -2
- package/dist/components/form/FormUISchemaRenderer.svelte +3 -1
- package/dist/components/form/templateAutocomplete.js +1 -5
- package/dist/components/form/types.d.ts +1 -14
- package/dist/components/interrupt/FormPrompt.svelte +3 -2
- package/dist/components/interrupt/InterruptBubble.svelte +25 -17
- package/dist/components/interrupt/ReviewPrompt.svelte +10 -3
- package/dist/components/interrupt/TextInputPrompt.svelte +2 -1
- package/dist/components/layouts/MainLayout.svelte +20 -13
- package/dist/components/layouts/MainLayout.svelte.d.ts +4 -0
- package/dist/components/nodes/AtomNode.svelte +17 -5
- package/dist/components/nodes/GatewayNode.svelte +19 -10
- package/dist/components/nodes/IdeaNode.svelte +7 -0
- package/dist/components/nodes/SimpleNode.svelte +11 -6
- package/dist/components/nodes/SquareNode.svelte +15 -8
- package/dist/components/nodes/TerminalNode.svelte +9 -4
- package/dist/components/nodes/ToolNode.svelte +7 -1
- package/dist/components/nodes/WorkflowNode.svelte +16 -7
- package/dist/components/playground/ChatInput.svelte +11 -14
- package/dist/components/playground/ChatPanel.svelte +6 -49
- package/dist/components/playground/ChatPanel.svelte.d.ts +0 -14
- package/dist/components/playground/ControlPanel.svelte +134 -123
- package/dist/components/playground/ControlPanel.svelte.d.ts +3 -0
- package/dist/components/playground/ExecutionLogs.svelte +11 -9
- package/dist/components/playground/InputCollector.svelte +11 -9
- package/dist/components/playground/MessageStream.svelte +17 -23
- package/dist/components/playground/PipelineKanbanView.svelte +69 -8
- package/dist/components/playground/PipelineKanbanView.svelte.d.ts +2 -0
- package/dist/components/playground/PipelinePanel.svelte +31 -8
- package/dist/components/playground/PipelinePanel.svelte.d.ts +2 -0
- package/dist/components/playground/PipelineTableView.svelte +188 -44
- package/dist/components/playground/PipelineTableView.svelte.d.ts +2 -0
- package/dist/components/playground/Playground.svelte +154 -105
- package/dist/components/playground/Playground.svelte.d.ts +5 -0
- package/dist/components/playground/PlaygroundApp.svelte +11 -1
- package/dist/components/playground/PlaygroundApp.svelte.d.ts +6 -0
- package/dist/components/playground/PlaygroundModal.svelte +18 -3
- package/dist/components/playground/PlaygroundModal.svelte.d.ts +6 -0
- package/dist/components/playground/PlaygroundStudio.svelte +40 -32
- package/dist/components/playground/PlaygroundStudio.svelte.d.ts +6 -0
- package/dist/components/playground/SessionManager.svelte +9 -12
- package/dist/components/playground/pipelineViewUtils.svelte.d.ts +30 -1
- package/dist/components/playground/pipelineViewUtils.svelte.js +40 -3
- package/dist/config/endpoints.d.ts +23 -7
- package/dist/config/endpoints.js +30 -10
- package/dist/core/index.d.ts +5 -6
- package/dist/core/index.js +8 -12
- package/dist/display/index.d.ts +6 -3
- package/dist/display/index.js +7 -5
- package/dist/editor/index.d.ts +20 -21
- package/dist/editor/index.js +26 -36
- package/dist/form/code.d.ts +25 -15
- package/dist/form/code.js +44 -41
- package/dist/form/fieldRegistry.d.ts +17 -13
- package/dist/form/fieldRegistry.js +32 -12
- package/dist/form/full.d.ts +19 -14
- package/dist/form/full.js +26 -28
- package/dist/form/index.d.ts +3 -4
- package/dist/form/index.js +6 -5
- package/dist/form/markdown.d.ts +13 -8
- package/dist/form/markdown.js +22 -23
- package/dist/helpers/proximityConnect.d.ts +3 -2
- package/dist/helpers/proximityConnect.js +2 -5
- package/dist/helpers/workflowEditorHelper.d.ts +14 -5
- package/dist/helpers/workflowEditorHelper.js +28 -25
- package/dist/index.d.ts +28 -24
- package/dist/index.js +27 -50
- package/dist/messages/defaults.d.ts +2 -5
- package/dist/messages/defaults.js +3 -6
- package/dist/messages/index.d.ts +0 -1
- package/dist/messages/index.js +0 -1
- package/dist/mocks/app-forms.d.ts +6 -2
- package/dist/mocks/app-forms.js +11 -4
- package/dist/openapi/v1/openapi.yaml +3 -3
- package/dist/playground/index.d.ts +4 -5
- package/dist/playground/index.js +4 -32
- package/dist/playground/mount.d.ts +25 -0
- package/dist/playground/mount.js +50 -20
- package/dist/registry/{BaseRegistry.d.ts → BaseRegistry.svelte.d.ts} +22 -1
- package/dist/registry/{BaseRegistry.js → BaseRegistry.svelte.js} +37 -1
- package/dist/registry/builtinFormats.d.ts +9 -18
- package/dist/registry/builtinFormats.js +9 -39
- package/dist/registry/builtinNodeTypes.d.ts +53 -0
- package/dist/registry/builtinNodeTypes.js +67 -0
- package/dist/registry/builtinNodes.d.ts +2 -64
- package/dist/registry/builtinNodes.js +7 -103
- package/dist/registry/index.d.ts +3 -4
- package/dist/registry/index.js +4 -6
- package/dist/registry/nodeComponentRegistry.d.ts +182 -15
- package/dist/registry/nodeComponentRegistry.js +235 -17
- package/dist/registry/workflowFormatRegistry.d.ts +14 -9
- package/dist/registry/workflowFormatRegistry.js +24 -8
- package/dist/{schema → schemas}/index.d.ts +2 -2
- package/dist/{schema → schemas}/index.js +2 -2
- package/dist/schemas/v1/workflow.schema.json +3 -3
- package/dist/services/agentSpecExecutionService.d.ts +0 -2
- package/dist/services/agentSpecExecutionService.js +0 -3
- package/dist/services/apiVariableService.d.ts +2 -1
- package/dist/services/apiVariableService.js +16 -47
- package/dist/services/autoSaveService.d.ts +7 -0
- package/dist/services/autoSaveService.js +6 -4
- package/dist/services/categoriesApi.js +3 -6
- package/dist/services/chatService.d.ts +9 -4
- package/dist/services/chatService.js +23 -28
- package/dist/services/draftStorage.d.ts +129 -13
- package/dist/services/draftStorage.js +185 -37
- package/dist/services/dynamicSchemaService.d.ts +2 -1
- package/dist/services/dynamicSchemaService.js +5 -22
- package/dist/services/globalSave.d.ts +13 -12
- package/dist/services/globalSave.js +29 -51
- package/dist/services/historyService.d.ts +9 -3
- package/dist/services/historyService.js +9 -3
- package/dist/services/interruptService.d.ts +15 -9
- package/dist/services/interruptService.js +35 -37
- package/dist/services/nodeExecutionService.d.ts +18 -3
- package/dist/services/nodeExecutionService.js +71 -45
- package/dist/services/playgroundService.d.ts +16 -10
- package/dist/services/playgroundService.js +42 -43
- package/dist/services/portConfigApi.js +3 -6
- package/dist/services/settingsService.d.ts +9 -4
- package/dist/services/settingsService.js +23 -12
- package/dist/services/variableService.d.ts +2 -1
- package/dist/services/variableService.js +2 -2
- package/dist/services/workflowStorage.js +6 -6
- package/dist/stores/apiContext.d.ts +56 -0
- package/dist/stores/apiContext.js +80 -0
- package/dist/stores/categoriesStore.svelte.d.ts +28 -23
- package/dist/stores/categoriesStore.svelte.js +69 -64
- package/dist/stores/getInstance.svelte.d.ts +39 -0
- package/dist/stores/getInstance.svelte.js +65 -0
- package/dist/stores/historyStore.svelte.d.ts +77 -93
- package/dist/stores/historyStore.svelte.js +134 -160
- package/dist/stores/instanceContainer.svelte.d.ts +111 -0
- package/dist/stores/instanceContainer.svelte.js +114 -0
- package/dist/stores/interruptStore.svelte.d.ts +112 -82
- package/dist/stores/interruptStore.svelte.js +253 -226
- package/dist/stores/pipelinePanelStore.svelte.d.ts +27 -3
- package/dist/stores/pipelinePanelStore.svelte.js +61 -14
- package/dist/stores/playgroundStore.svelte.d.ts +169 -222
- package/dist/stores/playgroundStore.svelte.js +513 -580
- package/dist/stores/portCoordinateStore.svelte.d.ts +57 -51
- package/dist/stores/portCoordinateStore.svelte.js +109 -98
- package/dist/stores/settingsStore.svelte.d.ts +4 -1
- package/dist/stores/settingsStore.svelte.js +47 -12
- package/dist/stores/workflowStore.svelte.d.ts +178 -213
- package/dist/stores/workflowStore.svelte.js +449 -501
- package/dist/stories/EdgeDecorator.svelte +5 -2
- package/dist/stories/NodeDecorator.svelte +5 -3
- package/dist/svelte-app.d.ts +60 -10
- package/dist/svelte-app.js +159 -54
- package/dist/types/auth.d.ts +9 -51
- package/dist/types/auth.js +4 -54
- package/dist/types/events.d.ts +6 -3
- package/dist/types/index.d.ts +37 -5
- package/dist/types/index.js +0 -1
- package/dist/types/navbar.d.ts +7 -0
- package/dist/types/playground.d.ts +18 -3
- package/dist/types/settings.d.ts +13 -0
- package/dist/types/settings.js +1 -0
- package/dist/utils/colors.d.ts +47 -21
- package/dist/utils/colors.js +69 -68
- package/dist/utils/connections.d.ts +9 -15
- package/dist/utils/connections.js +13 -32
- package/dist/utils/duration.d.ts +13 -0
- package/dist/utils/duration.js +45 -0
- package/dist/utils/edgeStyling.js +9 -5
- package/dist/utils/fetchWithAuth.d.ts +36 -15
- package/dist/utils/fetchWithAuth.js +53 -23
- package/dist/utils/icons.d.ts +5 -2
- package/dist/utils/icons.js +6 -5
- package/dist/utils/nodeSwap.d.ts +6 -2
- package/dist/utils/nodeSwap.js +62 -126
- package/dist/utils/nodeTypes.d.ts +17 -8
- package/dist/utils/nodeTypes.js +27 -20
- package/dist/utils/performanceUtils.js +7 -0
- package/package.json +7 -5
- package/dist/messages/deprecation.d.ts +0 -20
- package/dist/messages/deprecation.js +0 -33
- package/dist/registry/plugin.d.ts +0 -215
- package/dist/registry/plugin.js +0 -249
- package/dist/services/api.d.ts +0 -129
- package/dist/services/api.js +0 -217
|
@@ -42,21 +42,25 @@
|
|
|
42
42
|
getStatusTextColor,
|
|
43
43
|
getStatusBackgroundColor
|
|
44
44
|
} from '../../utils/nodeStatus.js';
|
|
45
|
+
import { formatMicroseconds } from '../../utils/duration.js';
|
|
45
46
|
import type { NodeStatus } from './pipelineViewUtils.svelte.js';
|
|
46
47
|
import type { Workflow, WorkflowNode } from '../../types/index.js';
|
|
47
48
|
import type { EndpointConfig } from '../../config/endpoints.js';
|
|
49
|
+
import type { AuthProvider } from '../../types/auth.js';
|
|
48
50
|
|
|
49
51
|
interface Props {
|
|
50
52
|
pipelineId: string;
|
|
51
53
|
workflow: Workflow;
|
|
52
54
|
endpointConfig: EndpointConfig;
|
|
55
|
+
authProvider?: AuthProvider;
|
|
53
56
|
refreshTrigger?: number;
|
|
54
57
|
}
|
|
55
58
|
|
|
56
|
-
let { pipelineId, workflow, endpointConfig, refreshTrigger = 0 }: Props = $props();
|
|
59
|
+
let { pipelineId, workflow, endpointConfig, authProvider, refreshTrigger = 0 }: Props = $props();
|
|
57
60
|
|
|
58
|
-
//
|
|
59
|
-
|
|
61
|
+
// endpointConfig is consumed once to build the API client; it must be stable
|
|
62
|
+
// svelte-ignore state_referenced_locally
|
|
63
|
+
const fetcher = createPipelineDataFetcher(() => pipelineId, endpointConfig, authProvider);
|
|
60
64
|
|
|
61
65
|
$effect(() => {
|
|
62
66
|
if (refreshTrigger <= 0) return;
|
|
@@ -65,8 +69,13 @@
|
|
|
65
69
|
});
|
|
66
70
|
|
|
67
71
|
interface CardItem {
|
|
68
|
-
|
|
72
|
+
/** Stable key: job id, or node id for nodes without a job yet */
|
|
73
|
+
key: string;
|
|
74
|
+
label: string;
|
|
75
|
+
typeId: string;
|
|
69
76
|
status: NodeStatus;
|
|
77
|
+
/** Duration in microseconds, for finished jobs */
|
|
78
|
+
durationUs?: number | null;
|
|
70
79
|
}
|
|
71
80
|
|
|
72
81
|
const columnedNodes = $derived.by(() => {
|
|
@@ -85,10 +94,37 @@
|
|
|
85
94
|
nodesByColumn.set(col.key, []);
|
|
86
95
|
}
|
|
87
96
|
|
|
97
|
+
const nodesById = new Map<string, WorkflowNode>(workflow.nodes.map((node) => [node.id, node]));
|
|
98
|
+
|
|
99
|
+
// One card per job: loop iterations create multiple jobs for the same
|
|
100
|
+
// node, and each deserves its own card (label carries the #N suffix).
|
|
101
|
+
const nodesWithJobs = new Set<string>();
|
|
102
|
+
for (const job of fetcher.jobs) {
|
|
103
|
+
const node = nodesById.get(job.nodeId);
|
|
104
|
+
if (!node) continue;
|
|
105
|
+
nodesWithJobs.add(job.nodeId);
|
|
106
|
+
const status = resolveStatus({ status: job.status });
|
|
107
|
+
const colKey = statusToColumn.get(status) ?? fallbackKey;
|
|
108
|
+
nodesByColumn.get(colKey)?.push({
|
|
109
|
+
key: job.id,
|
|
110
|
+
label: job.label || node.data.label,
|
|
111
|
+
typeId: node.data.metadata.id,
|
|
112
|
+
status,
|
|
113
|
+
durationUs: job.executionTimeUs
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Nodes without a job yet keep a single card (pending / not reached).
|
|
88
118
|
for (const node of workflow.nodes) {
|
|
119
|
+
if (nodesWithJobs.has(node.id)) continue;
|
|
89
120
|
const status = resolveStatus(fetcher.nodeStatusMap[node.id]);
|
|
90
121
|
const colKey = statusToColumn.get(status) ?? fallbackKey;
|
|
91
|
-
nodesByColumn.get(colKey)?.push({
|
|
122
|
+
nodesByColumn.get(colKey)?.push({
|
|
123
|
+
key: node.id,
|
|
124
|
+
label: node.data.label,
|
|
125
|
+
typeId: node.data.metadata.id,
|
|
126
|
+
status
|
|
127
|
+
});
|
|
92
128
|
}
|
|
93
129
|
|
|
94
130
|
return { columns, nodesByColumn };
|
|
@@ -122,11 +158,11 @@
|
|
|
122
158
|
<span class="pipeline-kanban__col-count">{items.length}</span>
|
|
123
159
|
</div>
|
|
124
160
|
<div class="pipeline-kanban__cards">
|
|
125
|
-
{#each items as {
|
|
161
|
+
{#each items as { key, label, typeId, status, durationUs } (key)}
|
|
126
162
|
<div class="pipeline-kanban__card">
|
|
127
163
|
<div class="pipeline-kanban__card-body">
|
|
128
164
|
<div class="pipeline-kanban__card-top">
|
|
129
|
-
<span class="pipeline-kanban__card-label">{
|
|
165
|
+
<span class="pipeline-kanban__card-label">{label}</span>
|
|
130
166
|
{#if showStatusPill}
|
|
131
167
|
<span
|
|
132
168
|
class="pipeline-kanban__card-status"
|
|
@@ -137,7 +173,14 @@
|
|
|
137
173
|
>
|
|
138
174
|
{/if}
|
|
139
175
|
</div>
|
|
140
|
-
<
|
|
176
|
+
<div class="pipeline-kanban__card-meta">
|
|
177
|
+
<span class="pipeline-kanban__card-type">{typeId}</span>
|
|
178
|
+
{#if durationUs != null}
|
|
179
|
+
<span class="pipeline-kanban__card-duration"
|
|
180
|
+
>{formatMicroseconds(durationUs)}</span
|
|
181
|
+
>
|
|
182
|
+
{/if}
|
|
183
|
+
</div>
|
|
141
184
|
</div>
|
|
142
185
|
</div>
|
|
143
186
|
{/each}
|
|
@@ -296,12 +339,30 @@
|
|
|
296
339
|
flex-shrink: 0;
|
|
297
340
|
}
|
|
298
341
|
|
|
342
|
+
.pipeline-kanban__card-meta {
|
|
343
|
+
display: flex;
|
|
344
|
+
align-items: center;
|
|
345
|
+
gap: var(--fd-space-xs);
|
|
346
|
+
min-width: 0;
|
|
347
|
+
}
|
|
348
|
+
|
|
299
349
|
.pipeline-kanban__card-type {
|
|
300
350
|
color: var(--fd-muted-foreground);
|
|
301
351
|
font-size: var(--fd-text-2xs);
|
|
302
352
|
overflow: hidden;
|
|
303
353
|
text-overflow: ellipsis;
|
|
304
354
|
white-space: nowrap;
|
|
355
|
+
flex: 1;
|
|
356
|
+
min-width: 0;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.pipeline-kanban__card-duration {
|
|
360
|
+
color: var(--fd-muted-foreground);
|
|
361
|
+
font-size: var(--fd-text-2xs);
|
|
362
|
+
font-family: var(--fd-font-mono, monospace);
|
|
363
|
+
font-variant-numeric: tabular-nums;
|
|
364
|
+
white-space: nowrap;
|
|
365
|
+
flex-shrink: 0;
|
|
305
366
|
}
|
|
306
367
|
|
|
307
368
|
.pipeline-kanban__empty {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { Workflow } from '../../types/index.js';
|
|
2
2
|
import type { EndpointConfig } from '../../config/endpoints.js';
|
|
3
|
+
import type { AuthProvider } from '../../types/auth.js';
|
|
3
4
|
interface Props {
|
|
4
5
|
pipelineId: string;
|
|
5
6
|
workflow: Workflow;
|
|
6
7
|
endpointConfig: EndpointConfig;
|
|
8
|
+
authProvider?: AuthProvider;
|
|
7
9
|
refreshTrigger?: number;
|
|
8
10
|
}
|
|
9
11
|
declare const PipelineKanbanView: import("svelte").Component<Props, {}, "">;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
|
-
const
|
|
2
|
+
const VIEW_MODE_KEY_BASE = 'fd-pipeline-view-mode';
|
|
3
3
|
const BUILTIN_VIEWS = ['graph', 'kanban', 'table'] as const;
|
|
4
4
|
// `string & {}` preserves autocomplete for built-in values while still accepting arbitrary strings from extraViews.
|
|
5
5
|
type ViewMode = (typeof BUILTIN_VIEWS)[number] | (string & {});
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<script lang="ts">
|
|
9
9
|
import { onMount } from 'svelte';
|
|
10
|
+
import { getInstance } from '../../stores/getInstance.svelte.js';
|
|
10
11
|
import PipelineStatus from '../PipelineStatus.svelte';
|
|
11
12
|
import PipelineKanbanView from './PipelineKanbanView.svelte';
|
|
12
13
|
import PipelineTableView from './PipelineTableView.svelte';
|
|
@@ -15,12 +16,14 @@
|
|
|
15
16
|
import { logger } from '../../utils/logger.js';
|
|
16
17
|
import type { Workflow, PipelineViewDef } from '../../types/index.js';
|
|
17
18
|
import type { EndpointConfig } from '../../config/endpoints.js';
|
|
19
|
+
import type { AuthProvider } from '../../types/auth.js';
|
|
18
20
|
import type { PlaygroundExecution } from '../../types/playground.js';
|
|
19
21
|
|
|
20
22
|
interface Props {
|
|
21
23
|
pipelineId: string | null;
|
|
22
24
|
workflow: Workflow;
|
|
23
25
|
endpointConfig: EndpointConfig;
|
|
26
|
+
authProvider?: AuthProvider;
|
|
24
27
|
isPinned: boolean;
|
|
25
28
|
/** All executions for the current session, oldest-first */
|
|
26
29
|
executions?: PlaygroundExecution[];
|
|
@@ -38,6 +41,7 @@
|
|
|
38
41
|
pipelineId,
|
|
39
42
|
workflow,
|
|
40
43
|
endpointConfig,
|
|
44
|
+
authProvider,
|
|
41
45
|
isPinned,
|
|
42
46
|
executions = [],
|
|
43
47
|
latestExecutionId = null,
|
|
@@ -46,10 +50,16 @@
|
|
|
46
50
|
extraViews = []
|
|
47
51
|
}: Props = $props();
|
|
48
52
|
|
|
53
|
+
const fd = getInstance();
|
|
54
|
+
|
|
55
|
+
// The default instance keeps the legacy bare key; additional instances get
|
|
56
|
+
// a scoped key so two editors' view-mode choices don't overwrite each other.
|
|
57
|
+
const viewModeKey = fd.isDefault ? VIEW_MODE_KEY_BASE : `${VIEW_MODE_KEY_BASE}:${fd.id}`;
|
|
58
|
+
|
|
49
59
|
let viewMode = $state<ViewMode>('graph');
|
|
50
60
|
|
|
51
61
|
onMount(() => {
|
|
52
|
-
const stored = localStorage.getItem(
|
|
62
|
+
const stored = localStorage.getItem(viewModeKey);
|
|
53
63
|
if (!stored) return;
|
|
54
64
|
const validKeys = [...BUILTIN_VIEWS, ...extraViews.map((v) => v.key)];
|
|
55
65
|
if (validKeys.includes(stored)) viewMode = stored;
|
|
@@ -58,7 +68,7 @@
|
|
|
58
68
|
function selectViewMode(mode: ViewMode) {
|
|
59
69
|
viewMode = mode;
|
|
60
70
|
try {
|
|
61
|
-
localStorage.setItem(
|
|
71
|
+
localStorage.setItem(viewModeKey, mode);
|
|
62
72
|
} catch (e) {
|
|
63
73
|
logger.warn('[FlowDrop] Could not persist view mode to localStorage:', e);
|
|
64
74
|
}
|
|
@@ -241,14 +251,27 @@
|
|
|
241
251
|
{#if pipelineId}
|
|
242
252
|
{#key pipelineId}
|
|
243
253
|
{#if viewMode === 'kanban'}
|
|
244
|
-
<PipelineKanbanView
|
|
254
|
+
<PipelineKanbanView
|
|
255
|
+
{pipelineId}
|
|
256
|
+
{workflow}
|
|
257
|
+
{endpointConfig}
|
|
258
|
+
{authProvider}
|
|
259
|
+
{refreshTrigger}
|
|
260
|
+
/>
|
|
245
261
|
{:else if viewMode === 'table'}
|
|
246
|
-
<PipelineTableView
|
|
262
|
+
<PipelineTableView
|
|
263
|
+
{pipelineId}
|
|
264
|
+
{workflow}
|
|
265
|
+
{endpointConfig}
|
|
266
|
+
{authProvider}
|
|
267
|
+
{refreshTrigger}
|
|
268
|
+
/>
|
|
247
269
|
{:else if viewMode === 'graph'}
|
|
248
270
|
<PipelineStatus
|
|
249
271
|
{pipelineId}
|
|
250
272
|
{workflow}
|
|
251
273
|
{endpointConfig}
|
|
274
|
+
{authProvider}
|
|
252
275
|
runLabel={pipelineId}
|
|
253
276
|
{refreshTrigger}
|
|
254
277
|
isEmbedded={true}
|
|
@@ -257,7 +280,7 @@
|
|
|
257
280
|
{@const activeView = extraViews.find((v) => v.key === viewMode)}
|
|
258
281
|
{#if activeView}
|
|
259
282
|
{@const View = activeView.component}
|
|
260
|
-
<View {pipelineId} {workflow} {endpointConfig} {refreshTrigger} />
|
|
283
|
+
<View {pipelineId} {workflow} {endpointConfig} {authProvider} {refreshTrigger} />
|
|
261
284
|
{/if}
|
|
262
285
|
{/if}
|
|
263
286
|
{/key}
|
|
@@ -268,9 +291,9 @@
|
|
|
268
291
|
width="100%"
|
|
269
292
|
showNavbar={false}
|
|
270
293
|
disableSidebar={true}
|
|
271
|
-
|
|
272
|
-
readOnly={true}
|
|
294
|
+
mode="locked"
|
|
273
295
|
{endpointConfig}
|
|
296
|
+
{authProvider}
|
|
274
297
|
/>
|
|
275
298
|
{/if}
|
|
276
299
|
</div>
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { Workflow, PipelineViewDef } from '../../types/index.js';
|
|
2
2
|
import type { EndpointConfig } from '../../config/endpoints.js';
|
|
3
|
+
import type { AuthProvider } from '../../types/auth.js';
|
|
3
4
|
import type { PlaygroundExecution } from '../../types/playground.js';
|
|
4
5
|
interface Props {
|
|
5
6
|
pipelineId: string | null;
|
|
6
7
|
workflow: Workflow;
|
|
7
8
|
endpointConfig: EndpointConfig;
|
|
9
|
+
authProvider?: AuthProvider;
|
|
8
10
|
isPinned: boolean;
|
|
9
11
|
/** All executions for the current session, oldest-first */
|
|
10
12
|
executions?: PlaygroundExecution[];
|
|
@@ -25,19 +25,26 @@
|
|
|
25
25
|
idle: 'mdi:circle-outline'
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
function formatDuration(ms: number | null | undefined): string | null {
|
|
29
|
-
if (ms == null) return null;
|
|
30
|
-
if (ms < 1000) return `${ms}ms`;
|
|
31
|
-
if (ms < 60000) return `${(ms / 1000).toFixed(2)}s`;
|
|
32
|
-
const mins = Math.floor(ms / 60000);
|
|
33
|
-
const secs = Math.floor((ms % 60000) / 1000);
|
|
34
|
-
return `${mins}m ${secs}s`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
28
|
function formatDateTime(iso: string | null | undefined): string | null {
|
|
38
29
|
if (!iso) return null;
|
|
39
30
|
return new Date(iso).toLocaleString();
|
|
40
31
|
}
|
|
32
|
+
|
|
33
|
+
function formatJson(value: unknown): string {
|
|
34
|
+
if (typeof value === 'string') return value;
|
|
35
|
+
try {
|
|
36
|
+
return JSON.stringify(value, null, 2);
|
|
37
|
+
} catch {
|
|
38
|
+
return String(value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Treat null/undefined and empty objects/arrays as "nothing to show". */
|
|
43
|
+
function hasData(value: unknown): boolean {
|
|
44
|
+
if (value == null) return false;
|
|
45
|
+
if (typeof value === 'object') return Object.keys(value).length > 0;
|
|
46
|
+
return value !== '';
|
|
47
|
+
}
|
|
41
48
|
</script>
|
|
42
49
|
|
|
43
50
|
<script lang="ts">
|
|
@@ -45,27 +52,42 @@
|
|
|
45
52
|
import Icon from '@iconify/svelte';
|
|
46
53
|
import { createPipelineDataFetcher, resolveStatus } from './pipelineViewUtils.svelte.js';
|
|
47
54
|
import { getStatusTextColor } from '../../utils/nodeStatus.js';
|
|
48
|
-
import
|
|
55
|
+
import { formatMicroseconds } from '../../utils/duration.js';
|
|
49
56
|
import type { Workflow, WorkflowNode } from '../../types/index.js';
|
|
50
57
|
import type { EndpointConfig } from '../../config/endpoints.js';
|
|
58
|
+
import type { AuthProvider } from '../../types/auth.js';
|
|
51
59
|
|
|
52
60
|
interface Props {
|
|
53
61
|
pipelineId: string;
|
|
54
62
|
workflow: Workflow;
|
|
55
63
|
endpointConfig: EndpointConfig;
|
|
64
|
+
authProvider?: AuthProvider;
|
|
56
65
|
refreshTrigger?: number;
|
|
57
66
|
}
|
|
58
67
|
|
|
59
|
-
let { pipelineId, workflow, endpointConfig, refreshTrigger = 0 }: Props = $props();
|
|
68
|
+
let { pipelineId, workflow, endpointConfig, authProvider, refreshTrigger = 0 }: Props = $props();
|
|
60
69
|
|
|
61
|
-
interface
|
|
62
|
-
|
|
70
|
+
interface JobRow {
|
|
71
|
+
/** Stable key: job id, or node id for nodes without a job yet */
|
|
72
|
+
key: string;
|
|
73
|
+
label: string;
|
|
74
|
+
typeId: string;
|
|
75
|
+
nodeId: string;
|
|
63
76
|
status: NodeStatus;
|
|
64
|
-
|
|
77
|
+
started?: string | null;
|
|
78
|
+
completed?: string | null;
|
|
79
|
+
/** Duration in microseconds */
|
|
80
|
+
executionTimeUs?: number | null;
|
|
81
|
+
error?: string | null;
|
|
82
|
+
retryCount?: number | null;
|
|
83
|
+
maxRetries?: number | null;
|
|
84
|
+
inputData?: unknown;
|
|
85
|
+
outputData?: unknown;
|
|
65
86
|
}
|
|
66
87
|
|
|
67
|
-
//
|
|
68
|
-
|
|
88
|
+
// endpointConfig is consumed once to build the API client; it must be stable
|
|
89
|
+
// svelte-ignore state_referenced_locally
|
|
90
|
+
const fetcher = createPipelineDataFetcher(() => pipelineId, endpointConfig, authProvider);
|
|
69
91
|
|
|
70
92
|
$effect(() => {
|
|
71
93
|
if (refreshTrigger <= 0) return;
|
|
@@ -73,28 +95,76 @@
|
|
|
73
95
|
return () => clearTimeout(timer);
|
|
74
96
|
});
|
|
75
97
|
|
|
76
|
-
|
|
77
|
-
|
|
98
|
+
// One row per job, timeline style: loop iterations create multiple jobs
|
|
99
|
+
// for the same node and each shows as its own row (label carries the #N
|
|
100
|
+
// suffix). Executed jobs sort by start time; never-started jobs keep
|
|
101
|
+
// pipeline order at the end, followed by nodes that have no job yet.
|
|
102
|
+
const sortedRows = $derived.by((): JobRow[] => {
|
|
103
|
+
const nodesById = new Map<string, WorkflowNode>(workflow.nodes.map((node) => [node.id, node]));
|
|
104
|
+
|
|
105
|
+
const jobRows: JobRow[] = [];
|
|
106
|
+
const nodesWithJobs = new Set<string>();
|
|
107
|
+
for (const job of fetcher.jobs) {
|
|
108
|
+
const node = nodesById.get(job.nodeId);
|
|
109
|
+
if (!node) continue;
|
|
110
|
+
nodesWithJobs.add(job.nodeId);
|
|
111
|
+
jobRows.push({
|
|
112
|
+
key: job.id,
|
|
113
|
+
label: job.label || node.data.label,
|
|
114
|
+
typeId: node.data.metadata.id,
|
|
115
|
+
nodeId: job.nodeId,
|
|
116
|
+
status: resolveStatus({ status: job.status }),
|
|
117
|
+
started: job.started,
|
|
118
|
+
completed: job.completed,
|
|
119
|
+
executionTimeUs: job.executionTimeUs,
|
|
120
|
+
error: job.error,
|
|
121
|
+
retryCount: job.retryCount,
|
|
122
|
+
maxRetries: job.maxRetries,
|
|
123
|
+
inputData: job.inputData,
|
|
124
|
+
outputData: job.outputData
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const startedRows = jobRows
|
|
129
|
+
.filter((row) => row.started)
|
|
130
|
+
.sort((a, b) => Date.parse(a.started!) - Date.parse(b.started!));
|
|
131
|
+
const neverStartedRows = jobRows.filter((row) => !row.started);
|
|
132
|
+
|
|
133
|
+
const nodeRows: JobRow[] = workflow.nodes
|
|
134
|
+
.filter((node) => !nodesWithJobs.has(node.id))
|
|
78
135
|
.map((node) => {
|
|
79
136
|
const statusData = fetcher.nodeStatusMap[node.id];
|
|
80
|
-
return {
|
|
137
|
+
return {
|
|
138
|
+
key: node.id,
|
|
139
|
+
label: node.data.label,
|
|
140
|
+
typeId: node.data.metadata.id,
|
|
141
|
+
nodeId: node.id,
|
|
142
|
+
status: resolveStatus(statusData),
|
|
143
|
+
started: statusData?.last_executed,
|
|
144
|
+
executionTimeUs:
|
|
145
|
+
statusData?.execution_time_us ??
|
|
146
|
+
(statusData?.execution_time != null ? statusData.execution_time * 1000 : null),
|
|
147
|
+
error: statusData?.error
|
|
148
|
+
};
|
|
81
149
|
})
|
|
82
|
-
.sort((a, b) => (STATUS_ORDER[a.status] ?? Infinity) - (STATUS_ORDER[b.status] ?? Infinity))
|
|
83
|
-
|
|
150
|
+
.sort((a, b) => (STATUS_ORDER[a.status] ?? Infinity) - (STATUS_ORDER[b.status] ?? Infinity));
|
|
151
|
+
|
|
152
|
+
return [...startedRows, ...neverStartedRows, ...nodeRows];
|
|
153
|
+
});
|
|
84
154
|
|
|
85
155
|
let expandedIds = $state(new Set<string>());
|
|
86
156
|
|
|
87
|
-
function hasDetails(row:
|
|
88
|
-
return !!(row.
|
|
157
|
+
function hasDetails(row: JobRow): boolean {
|
|
158
|
+
return !!(row.started || row.error || hasData(row.inputData) || hasData(row.outputData));
|
|
89
159
|
}
|
|
90
160
|
|
|
91
|
-
function toggleRow(row:
|
|
161
|
+
function toggleRow(row: JobRow) {
|
|
92
162
|
if (!hasDetails(row)) return;
|
|
93
163
|
const next = new Set(expandedIds);
|
|
94
|
-
if (next.has(row.
|
|
95
|
-
next.delete(row.
|
|
164
|
+
if (next.has(row.key)) {
|
|
165
|
+
next.delete(row.key);
|
|
96
166
|
} else {
|
|
97
|
-
next.add(row.
|
|
167
|
+
next.add(row.key);
|
|
98
168
|
}
|
|
99
169
|
expandedIds = next;
|
|
100
170
|
}
|
|
@@ -121,12 +191,13 @@
|
|
|
121
191
|
<th class="pipeline-table__th">Node</th>
|
|
122
192
|
<th class="pipeline-table__th">Type</th>
|
|
123
193
|
<th class="pipeline-table__th">Status</th>
|
|
194
|
+
<th class="pipeline-table__th pipeline-table__th--duration">Duration</th>
|
|
124
195
|
<th class="pipeline-table__th pipeline-table__th--id">ID</th>
|
|
125
196
|
</tr>
|
|
126
197
|
</thead>
|
|
127
198
|
<tbody>
|
|
128
|
-
{#each sortedRows as row (row.
|
|
129
|
-
{@const expanded = expandedIds.has(row.
|
|
199
|
+
{#each sortedRows as row (row.key)}
|
|
200
|
+
{@const expanded = expandedIds.has(row.key)}
|
|
130
201
|
{@const expandable = hasDetails(row)}
|
|
131
202
|
<tr
|
|
132
203
|
class="pipeline-table__row"
|
|
@@ -144,12 +215,11 @@
|
|
|
144
215
|
/>
|
|
145
216
|
{/if}
|
|
146
217
|
</td>
|
|
147
|
-
<td class="pipeline-table__td pipeline-table__td--label" title={row.
|
|
148
|
-
>{row.
|
|
218
|
+
<td class="pipeline-table__td pipeline-table__td--label" title={row.label}
|
|
219
|
+
>{row.label}</td
|
|
149
220
|
>
|
|
150
|
-
<td
|
|
151
|
-
|
|
152
|
-
title={row.node.data.metadata.id}>{row.node.data.metadata.id}</td
|
|
221
|
+
<td class="pipeline-table__td pipeline-table__td--muted" title={row.typeId}
|
|
222
|
+
>{row.typeId}</td
|
|
153
223
|
>
|
|
154
224
|
<td class="pipeline-table__td">
|
|
155
225
|
<span
|
|
@@ -163,33 +233,62 @@
|
|
|
163
233
|
{row.status}
|
|
164
234
|
</span>
|
|
165
235
|
</td>
|
|
166
|
-
<td class="pipeline-table__td pipeline-table__td--
|
|
167
|
-
|
|
236
|
+
<td class="pipeline-table__td pipeline-table__td--duration">
|
|
237
|
+
{formatMicroseconds(row.executionTimeUs) ?? '—'}
|
|
238
|
+
</td>
|
|
239
|
+
<td class="pipeline-table__td pipeline-table__td--id" title={row.nodeId}
|
|
240
|
+
>{row.nodeId}</td
|
|
168
241
|
>
|
|
169
242
|
</tr>
|
|
170
243
|
{#if expanded && expandable}
|
|
171
244
|
<tr class="pipeline-table__detail-row">
|
|
172
|
-
<td colspan="
|
|
245
|
+
<td colspan="6" class="pipeline-table__detail-cell">
|
|
173
246
|
<dl class="pipeline-table__details">
|
|
174
|
-
{#if row.
|
|
247
|
+
{#if row.started}
|
|
248
|
+
<div class="pipeline-table__detail-item">
|
|
249
|
+
<dt>Started</dt>
|
|
250
|
+
<dd>{formatDateTime(row.started)}</dd>
|
|
251
|
+
</div>
|
|
252
|
+
{/if}
|
|
253
|
+
{#if row.completed}
|
|
175
254
|
<div class="pipeline-table__detail-item">
|
|
176
|
-
<dt>
|
|
177
|
-
<dd>{formatDateTime(row.
|
|
255
|
+
<dt>Completed</dt>
|
|
256
|
+
<dd>{formatDateTime(row.completed)}</dd>
|
|
178
257
|
</div>
|
|
179
258
|
{/if}
|
|
180
|
-
{#if row.
|
|
259
|
+
{#if row.executionTimeUs != null}
|
|
181
260
|
<div class="pipeline-table__detail-item">
|
|
182
261
|
<dt>Duration</dt>
|
|
183
|
-
<dd>{
|
|
262
|
+
<dd>{formatMicroseconds(row.executionTimeUs)}</dd>
|
|
184
263
|
</div>
|
|
185
264
|
{/if}
|
|
186
|
-
{#if row.
|
|
265
|
+
{#if row.retryCount != null && row.retryCount > 0}
|
|
266
|
+
<div class="pipeline-table__detail-item">
|
|
267
|
+
<dt>Retries</dt>
|
|
268
|
+
<dd>
|
|
269
|
+
{row.retryCount}{row.maxRetries != null ? ` / ${row.maxRetries}` : ''}
|
|
270
|
+
</dd>
|
|
271
|
+
</div>
|
|
272
|
+
{/if}
|
|
273
|
+
{#if row.error}
|
|
187
274
|
<div class="pipeline-table__detail-item pipeline-table__detail-item--error">
|
|
188
275
|
<dt>Error</dt>
|
|
189
|
-
<dd>{row.
|
|
276
|
+
<dd>{row.error}</dd>
|
|
190
277
|
</div>
|
|
191
278
|
{/if}
|
|
192
279
|
</dl>
|
|
280
|
+
{#if hasData(row.inputData)}
|
|
281
|
+
<details class="pipeline-table__data">
|
|
282
|
+
<summary class="pipeline-table__data-summary">Input data</summary>
|
|
283
|
+
<pre class="pipeline-table__data-pre">{formatJson(row.inputData)}</pre>
|
|
284
|
+
</details>
|
|
285
|
+
{/if}
|
|
286
|
+
{#if hasData(row.outputData)}
|
|
287
|
+
<details class="pipeline-table__data">
|
|
288
|
+
<summary class="pipeline-table__data-summary">Output data</summary>
|
|
289
|
+
<pre class="pipeline-table__data-pre">{formatJson(row.outputData)}</pre>
|
|
290
|
+
</details>
|
|
291
|
+
{/if}
|
|
193
292
|
</td>
|
|
194
293
|
</tr>
|
|
195
294
|
{/if}
|
|
@@ -270,6 +369,19 @@
|
|
|
270
369
|
font-family: var(--fd-font-mono, monospace);
|
|
271
370
|
}
|
|
272
371
|
|
|
372
|
+
.pipeline-table__th--duration,
|
|
373
|
+
.pipeline-table__td--duration {
|
|
374
|
+
text-align: right;
|
|
375
|
+
white-space: nowrap;
|
|
376
|
+
font-variant-numeric: tabular-nums;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.pipeline-table__td--duration {
|
|
380
|
+
font-family: var(--fd-font-mono, monospace);
|
|
381
|
+
font-size: var(--fd-text-2xs);
|
|
382
|
+
color: var(--fd-muted-foreground);
|
|
383
|
+
}
|
|
384
|
+
|
|
273
385
|
.pipeline-table__th--expand {
|
|
274
386
|
width: 1.5rem;
|
|
275
387
|
padding-right: 0;
|
|
@@ -375,6 +487,38 @@
|
|
|
375
487
|
font-size: var(--fd-text-2xs);
|
|
376
488
|
}
|
|
377
489
|
|
|
490
|
+
.pipeline-table__data {
|
|
491
|
+
margin-top: var(--fd-space-sm);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.pipeline-table__data-summary {
|
|
495
|
+
cursor: pointer;
|
|
496
|
+
font-size: var(--fd-text-2xs);
|
|
497
|
+
font-weight: 600;
|
|
498
|
+
text-transform: uppercase;
|
|
499
|
+
letter-spacing: 0.05em;
|
|
500
|
+
color: var(--fd-muted-foreground);
|
|
501
|
+
user-select: none;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.pipeline-table__data-summary:hover {
|
|
505
|
+
color: var(--fd-foreground);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.pipeline-table__data-pre {
|
|
509
|
+
margin: var(--fd-space-2xs) 0 0;
|
|
510
|
+
padding: var(--fd-space-sm);
|
|
511
|
+
max-height: 16rem;
|
|
512
|
+
overflow: auto;
|
|
513
|
+
font-family: var(--fd-font-mono, monospace);
|
|
514
|
+
font-size: var(--fd-text-2xs);
|
|
515
|
+
background-color: var(--fd-muted);
|
|
516
|
+
border: 1px solid var(--fd-border);
|
|
517
|
+
border-radius: var(--fd-radius-sm, 4px);
|
|
518
|
+
white-space: pre-wrap;
|
|
519
|
+
word-break: break-word;
|
|
520
|
+
}
|
|
521
|
+
|
|
378
522
|
.pipeline-table__status {
|
|
379
523
|
display: inline-flex;
|
|
380
524
|
align-items: center;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { Workflow } from '../../types/index.js';
|
|
2
2
|
import type { EndpointConfig } from '../../config/endpoints.js';
|
|
3
|
+
import type { AuthProvider } from '../../types/auth.js';
|
|
3
4
|
interface Props {
|
|
4
5
|
pipelineId: string;
|
|
5
6
|
workflow: Workflow;
|
|
6
7
|
endpointConfig: EndpointConfig;
|
|
8
|
+
authProvider?: AuthProvider;
|
|
7
9
|
refreshTrigger?: number;
|
|
8
10
|
}
|
|
9
11
|
declare const PipelineTableView: import("svelte").Component<Props, {}, "">;
|