@d34dman/flowdrop 0.0.45 → 0.0.47
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 +2 -2
- package/dist/components/App.svelte +6 -0
- package/dist/components/ConfigForm.svelte +56 -22
- package/dist/components/ConfigForm.svelte.d.ts +11 -1
- package/dist/components/Navbar.svelte +6 -7
- package/dist/components/SchemaForm.svelte +2 -10
- package/dist/components/SettingsPanel.svelte +5 -2
- package/dist/components/WorkflowEditor.svelte +158 -4
- package/dist/components/WorkflowEditor.svelte.d.ts +1 -0
- package/dist/components/form/FormAutocomplete.svelte +5 -9
- package/dist/components/form/FormCheckboxGroup.svelte +11 -1
- package/dist/components/form/FormCheckboxGroup.svelte.d.ts +2 -0
- package/dist/components/form/FormCodeEditor.svelte +16 -7
- package/dist/components/form/FormCodeEditor.svelte.d.ts +2 -0
- package/dist/components/form/FormField.svelte +33 -12
- package/dist/components/form/FormFieldLight.svelte +16 -12
- package/dist/components/form/FormMarkdownEditor.svelte +29 -19
- package/dist/components/form/FormMarkdownEditor.svelte.d.ts +2 -0
- package/dist/components/form/FormNumberField.svelte +4 -0
- package/dist/components/form/FormNumberField.svelte.d.ts +2 -0
- package/dist/components/form/FormRangeField.svelte +4 -0
- package/dist/components/form/FormRangeField.svelte.d.ts +2 -0
- package/dist/components/form/FormSelect.svelte +4 -0
- package/dist/components/form/FormSelect.svelte.d.ts +2 -0
- package/dist/components/form/FormTemplateEditor.svelte +140 -17
- package/dist/components/form/FormTemplateEditor.svelte.d.ts +19 -1
- package/dist/components/form/FormTextField.svelte +4 -0
- package/dist/components/form/FormTextField.svelte.d.ts +2 -0
- package/dist/components/form/FormTextarea.svelte +4 -0
- package/dist/components/form/FormTextarea.svelte.d.ts +2 -0
- package/dist/components/form/FormToggle.svelte +4 -0
- package/dist/components/form/FormToggle.svelte.d.ts +2 -0
- package/dist/components/form/index.d.ts +1 -0
- package/dist/components/form/index.js +2 -0
- package/dist/components/form/templateAutocomplete.d.ts +38 -0
- package/dist/components/form/templateAutocomplete.js +309 -0
- package/dist/components/form/types.d.ts +39 -2
- package/dist/components/form/types.js +1 -1
- package/dist/components/layouts/MainLayout.svelte +5 -2
- package/dist/components/nodes/GatewayNode.svelte +0 -8
- package/dist/components/nodes/SimpleNode.svelte +2 -3
- package/dist/components/nodes/WorkflowNode.svelte +0 -8
- package/dist/components/playground/Playground.svelte +43 -38
- package/dist/editor/index.d.ts +3 -1
- package/dist/editor/index.js +5 -1
- package/dist/helpers/workflowEditorHelper.js +1 -2
- package/dist/registry/nodeComponentRegistry.d.ts +9 -9
- package/dist/registry/nodeComponentRegistry.js +10 -10
- package/dist/services/autoSaveService.js +5 -5
- package/dist/services/historyService.d.ts +207 -0
- package/dist/services/historyService.js +317 -0
- package/dist/services/settingsService.d.ts +2 -2
- package/dist/services/settingsService.js +15 -21
- package/dist/services/toastService.d.ts +1 -1
- package/dist/services/toastService.js +10 -10
- package/dist/services/variableService.d.ts +100 -0
- package/dist/services/variableService.js +367 -0
- package/dist/stores/historyStore.d.ts +133 -0
- package/dist/stores/historyStore.js +188 -0
- package/dist/stores/settingsStore.d.ts +1 -1
- package/dist/stores/settingsStore.js +40 -42
- package/dist/stores/themeStore.d.ts +2 -2
- package/dist/stores/themeStore.js +30 -32
- package/dist/stores/workflowStore.d.ts +52 -2
- package/dist/stores/workflowStore.js +102 -2
- package/dist/styles/base.css +28 -8
- package/dist/styles/toast.css +3 -1
- package/dist/styles/tokens.css +2 -2
- package/dist/types/index.d.ts +120 -0
- package/dist/types/settings.d.ts +3 -3
- package/dist/types/settings.js +13 -19
- package/dist/utils/colors.js +17 -17
- package/dist/utils/nodeTypes.d.ts +15 -10
- package/dist/utils/nodeTypes.js +24 -22
- package/package.json +1 -1
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Variable Autocomplete Extension for CodeMirror
|
|
3
|
+
* Provides autocomplete suggestions for {{ variable }} syntax in template editors.
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Triggers on `{{` to show top-level variables
|
|
7
|
+
* - Triggers on `.` to show child properties for objects
|
|
8
|
+
* - Triggers on `[` to show array index options
|
|
9
|
+
* - Supports deep nesting (e.g., `user.address.city`)
|
|
10
|
+
*
|
|
11
|
+
* @module components/form/templateAutocomplete
|
|
12
|
+
*/
|
|
13
|
+
import { autocompletion } from "@codemirror/autocomplete";
|
|
14
|
+
import { getChildVariables, getArrayIndexSuggestions, isArrayVariable, hasChildren } from "../../services/variableService.js";
|
|
15
|
+
/**
|
|
16
|
+
* Icon type hints for different variable types in autocomplete dropdown.
|
|
17
|
+
*/
|
|
18
|
+
const TYPE_ICONS = {
|
|
19
|
+
string: "𝑆",
|
|
20
|
+
number: "#",
|
|
21
|
+
integer: "#",
|
|
22
|
+
float: "#",
|
|
23
|
+
boolean: "☑",
|
|
24
|
+
array: "[]",
|
|
25
|
+
object: "{}",
|
|
26
|
+
mixed: "⋯"
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Extracts the current variable path being typed inside {{ }}.
|
|
30
|
+
* Returns null if cursor is not inside a template expression.
|
|
31
|
+
*
|
|
32
|
+
* @param text - The full document text
|
|
33
|
+
* @param pos - Current cursor position
|
|
34
|
+
* @returns Object with the path and start position, or null
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* For text "Hello {{ user.name }}" with cursor after "user."
|
|
38
|
+
* Returns { path: "user.", startPos: 9 }
|
|
39
|
+
*/
|
|
40
|
+
function extractVariablePath(text, pos) {
|
|
41
|
+
// Look backwards from cursor to find the opening {{
|
|
42
|
+
let openBracePos = -1;
|
|
43
|
+
let searchPos = pos - 1;
|
|
44
|
+
while (searchPos >= 0) {
|
|
45
|
+
// Check for opening {{
|
|
46
|
+
if (text[searchPos] === "{" && searchPos > 0 && text[searchPos - 1] === "{") {
|
|
47
|
+
openBracePos = searchPos - 1;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
// Check for closing }} - means we're outside an expression
|
|
51
|
+
if (text[searchPos] === "}" && searchPos > 0 && text[searchPos - 1] === "}") {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
searchPos--;
|
|
55
|
+
}
|
|
56
|
+
if (openBracePos === -1) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
// Check if there's a closing }} after cursor (still inside expression)
|
|
60
|
+
const afterCursor = text.slice(pos);
|
|
61
|
+
const closingMatch = afterCursor.match(/^\s*\}\}/);
|
|
62
|
+
const hasClosing = closingMatch !== null;
|
|
63
|
+
// Extract the content between {{ and cursor
|
|
64
|
+
const contentStart = openBracePos + 2;
|
|
65
|
+
const content = text.slice(contentStart, pos).trimStart();
|
|
66
|
+
return {
|
|
67
|
+
path: content,
|
|
68
|
+
startPos: contentStart + (text.slice(contentStart, pos).length - text.slice(contentStart, pos).trimStart().length),
|
|
69
|
+
isInsideExpression: true
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Determines the completion type based on the current input.
|
|
74
|
+
*
|
|
75
|
+
* @param path - The current variable path being typed
|
|
76
|
+
* @returns The type of completion to provide
|
|
77
|
+
*/
|
|
78
|
+
function getCompletionType(path) {
|
|
79
|
+
// Empty or only whitespace - show top-level variables
|
|
80
|
+
if (path.trim() === "") {
|
|
81
|
+
return { type: "top-level" };
|
|
82
|
+
}
|
|
83
|
+
// Ends with [ - show array indices
|
|
84
|
+
if (path.endsWith("[")) {
|
|
85
|
+
const parentPath = path.slice(0, -1);
|
|
86
|
+
return { type: "array-index", parentPath };
|
|
87
|
+
}
|
|
88
|
+
// Ends with . - show child properties
|
|
89
|
+
if (path.endsWith(".")) {
|
|
90
|
+
const parentPath = path.slice(0, -1);
|
|
91
|
+
return { type: "property", parentPath };
|
|
92
|
+
}
|
|
93
|
+
// Otherwise, we're typing a variable name - show matching options
|
|
94
|
+
const lastDotIndex = path.lastIndexOf(".");
|
|
95
|
+
const lastBracketIndex = path.lastIndexOf("[");
|
|
96
|
+
const lastSeparator = Math.max(lastDotIndex, lastBracketIndex);
|
|
97
|
+
if (lastSeparator === -1) {
|
|
98
|
+
// Typing at top level
|
|
99
|
+
return { type: "top-level" };
|
|
100
|
+
}
|
|
101
|
+
// Extract parent path based on separator
|
|
102
|
+
if (lastDotIndex > lastBracketIndex) {
|
|
103
|
+
// Last separator was a dot
|
|
104
|
+
return { type: "property", parentPath: path.slice(0, lastDotIndex) };
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// Last separator was a bracket
|
|
108
|
+
return { type: "array-index", parentPath: path.slice(0, lastBracketIndex) };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Converts a TemplateVariable to a CodeMirror Completion object.
|
|
113
|
+
*
|
|
114
|
+
* @param variable - The template variable
|
|
115
|
+
* @param prefix - Prefix to add to the completion label
|
|
116
|
+
* @returns A CodeMirror Completion object
|
|
117
|
+
*/
|
|
118
|
+
function variableToCompletion(variable, prefix = "") {
|
|
119
|
+
const icon = TYPE_ICONS[variable.type] ?? TYPE_ICONS.mixed;
|
|
120
|
+
const hasChildProps = variable.properties && Object.keys(variable.properties).length > 0;
|
|
121
|
+
const isArray = variable.type === "array";
|
|
122
|
+
// Add indicator if variable can be drilled into
|
|
123
|
+
let suffix = "";
|
|
124
|
+
if (hasChildProps)
|
|
125
|
+
suffix = ".";
|
|
126
|
+
else if (isArray)
|
|
127
|
+
suffix = "[";
|
|
128
|
+
return {
|
|
129
|
+
label: `${prefix}${variable.name}`,
|
|
130
|
+
displayLabel: `${icon} ${variable.label ?? variable.name}${suffix ? " " + suffix : ""}`,
|
|
131
|
+
detail: variable.type,
|
|
132
|
+
info: variable.description,
|
|
133
|
+
type: "variable",
|
|
134
|
+
boost: hasChildProps || isArray ? 1 : 0 // Boost drillable variables
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Creates the completion source function for template variables.
|
|
139
|
+
*
|
|
140
|
+
* @param schema - The variable schema containing available variables
|
|
141
|
+
* @returns A completion source function for CodeMirror
|
|
142
|
+
*/
|
|
143
|
+
function createTemplateCompletionSource(schema) {
|
|
144
|
+
return (context) => {
|
|
145
|
+
const { state, pos } = context;
|
|
146
|
+
const text = state.doc.toString();
|
|
147
|
+
// Check if we're inside a {{ }} expression
|
|
148
|
+
const pathInfo = extractVariablePath(text, pos);
|
|
149
|
+
if (!pathInfo) {
|
|
150
|
+
// Check if user just typed {{
|
|
151
|
+
const beforeCursor = text.slice(Math.max(0, pos - 2), pos);
|
|
152
|
+
if (beforeCursor === "{{") {
|
|
153
|
+
// Show top-level variables
|
|
154
|
+
const options = Object.values(schema.variables).map((v) => variableToCompletion(v));
|
|
155
|
+
return {
|
|
156
|
+
from: pos,
|
|
157
|
+
options,
|
|
158
|
+
validFor: /^[\w.[\]]*$/
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
const { path, startPos } = pathInfo;
|
|
164
|
+
const completionType = getCompletionType(path);
|
|
165
|
+
let options = [];
|
|
166
|
+
let from = pos;
|
|
167
|
+
switch (completionType.type) {
|
|
168
|
+
case "top-level": {
|
|
169
|
+
// Show all top-level variables
|
|
170
|
+
const currentWord = path.trim();
|
|
171
|
+
options = Object.values(schema.variables)
|
|
172
|
+
.filter((v) => currentWord === "" || v.name.toLowerCase().startsWith(currentWord.toLowerCase()))
|
|
173
|
+
.map((v) => variableToCompletion(v));
|
|
174
|
+
// Calculate from position for replacement
|
|
175
|
+
from = startPos + (path.length - path.trimStart().length);
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
case "property": {
|
|
179
|
+
// Show child properties of the parent
|
|
180
|
+
const children = getChildVariables(schema, completionType.parentPath);
|
|
181
|
+
const currentWord = path.slice(path.lastIndexOf(".") + 1);
|
|
182
|
+
options = children
|
|
183
|
+
.filter((v) => currentWord === "" || v.name.toLowerCase().startsWith(currentWord.toLowerCase()))
|
|
184
|
+
.map((v) => variableToCompletion(v));
|
|
185
|
+
// From should be right after the last dot
|
|
186
|
+
from = startPos + path.lastIndexOf(".") + 1;
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
case "array-index": {
|
|
190
|
+
// Check if the parent is actually an array
|
|
191
|
+
if (isArrayVariable(schema, completionType.parentPath)) {
|
|
192
|
+
const indices = getArrayIndexSuggestions(5);
|
|
193
|
+
const currentIndex = path.slice(path.lastIndexOf("[") + 1);
|
|
194
|
+
options = indices
|
|
195
|
+
.filter((idx) => currentIndex === "" || idx.startsWith(currentIndex))
|
|
196
|
+
.map((idx) => ({
|
|
197
|
+
label: idx,
|
|
198
|
+
displayLabel: idx === "*]" ? "* (all items)" : `[${idx}`,
|
|
199
|
+
detail: idx === "*]" ? "Iterate all items" : `Index ${idx.slice(0, -1)}`,
|
|
200
|
+
type: "keyword"
|
|
201
|
+
}));
|
|
202
|
+
// From should be right after the [
|
|
203
|
+
from = startPos + path.lastIndexOf("[") + 1;
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (options.length === 0) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
from,
|
|
213
|
+
options,
|
|
214
|
+
validFor: /^[\w\]*]*$/
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Creates a CodeMirror extension for template variable autocomplete.
|
|
220
|
+
*
|
|
221
|
+
* @param schema - The variable schema containing available variables
|
|
222
|
+
* @returns A CodeMirror extension that provides autocomplete
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```typescript
|
|
226
|
+
* const extensions = [
|
|
227
|
+
* // ... other extensions
|
|
228
|
+
* createTemplateAutocomplete(variableSchema)
|
|
229
|
+
* ];
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
export function createTemplateAutocomplete(schema) {
|
|
233
|
+
return autocompletion({
|
|
234
|
+
override: [createTemplateCompletionSource(schema)],
|
|
235
|
+
activateOnTyping: true,
|
|
236
|
+
defaultKeymap: true,
|
|
237
|
+
optionClass: () => "cm-template-autocomplete-option",
|
|
238
|
+
icons: false, // We use our own icons in displayLabel
|
|
239
|
+
addToOptions: [
|
|
240
|
+
{
|
|
241
|
+
render: (completion) => {
|
|
242
|
+
const el = document.createElement("span");
|
|
243
|
+
el.className = "cm-template-autocomplete-info";
|
|
244
|
+
if (completion.info) {
|
|
245
|
+
el.textContent = String(completion.info);
|
|
246
|
+
}
|
|
247
|
+
return el;
|
|
248
|
+
},
|
|
249
|
+
position: 100
|
|
250
|
+
}
|
|
251
|
+
]
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Creates a simple autocomplete extension that triggers when user types {{
|
|
256
|
+
* and shows top-level variables only (no drilling).
|
|
257
|
+
* Used as a fallback when full variable schema is not available.
|
|
258
|
+
*
|
|
259
|
+
* @param variableHints - Simple array of variable names
|
|
260
|
+
* @returns A CodeMirror extension that provides basic autocomplete
|
|
261
|
+
*/
|
|
262
|
+
export function createSimpleTemplateAutocomplete(variableHints) {
|
|
263
|
+
const completionSource = (context) => {
|
|
264
|
+
const { state, pos } = context;
|
|
265
|
+
const text = state.doc.toString();
|
|
266
|
+
// Check if we're inside a {{ }} expression
|
|
267
|
+
const pathInfo = extractVariablePath(text, pos);
|
|
268
|
+
if (!pathInfo) {
|
|
269
|
+
// Check if user just typed {{
|
|
270
|
+
const beforeCursor = text.slice(Math.max(0, pos - 2), pos);
|
|
271
|
+
if (beforeCursor === "{{") {
|
|
272
|
+
const options = variableHints.map((hint) => ({
|
|
273
|
+
label: hint,
|
|
274
|
+
displayLabel: `⋯ ${hint}`,
|
|
275
|
+
type: "variable"
|
|
276
|
+
}));
|
|
277
|
+
return {
|
|
278
|
+
from: pos,
|
|
279
|
+
options,
|
|
280
|
+
validFor: /^[\w]*$/
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
// Filter based on current input
|
|
286
|
+
const currentWord = pathInfo.path.trim();
|
|
287
|
+
const options = variableHints
|
|
288
|
+
.filter((hint) => currentWord === "" || hint.toLowerCase().startsWith(currentWord.toLowerCase()))
|
|
289
|
+
.map((hint) => ({
|
|
290
|
+
label: hint,
|
|
291
|
+
displayLabel: `⋯ ${hint}`,
|
|
292
|
+
type: "variable"
|
|
293
|
+
}));
|
|
294
|
+
if (options.length === 0) {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
from: pathInfo.startPos + (pathInfo.path.length - pathInfo.path.trimStart().length),
|
|
299
|
+
options,
|
|
300
|
+
validFor: /^[\w]*$/
|
|
301
|
+
};
|
|
302
|
+
};
|
|
303
|
+
return autocompletion({
|
|
304
|
+
override: [completionSource],
|
|
305
|
+
activateOnTyping: true,
|
|
306
|
+
defaultKeymap: true,
|
|
307
|
+
icons: false
|
|
308
|
+
});
|
|
309
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* These types provide a foundation for dynamic form rendering based on JSON Schema
|
|
6
6
|
* and support extensibility for complex field types like arrays and objects.
|
|
7
7
|
*/
|
|
8
|
-
import type { AutocompleteConfig } from '../../types/index.js';
|
|
8
|
+
import type { AutocompleteConfig, VariableSchema, TemplateVariablesConfig } from '../../types/index.js';
|
|
9
9
|
/**
|
|
10
10
|
* Supported field types for form rendering
|
|
11
11
|
* Aligned with JSON Schema specification (draft-07)
|
|
@@ -220,7 +220,22 @@ export interface TemplateEditorFieldProps extends BaseFieldProps {
|
|
|
220
220
|
darkTheme?: boolean;
|
|
221
221
|
/** Editor height in pixels or CSS value */
|
|
222
222
|
height?: string;
|
|
223
|
-
/**
|
|
223
|
+
/**
|
|
224
|
+
* Configuration for template variable autocomplete.
|
|
225
|
+
* Controls which variables are available and how they are displayed.
|
|
226
|
+
*/
|
|
227
|
+
variables?: TemplateVariablesConfig;
|
|
228
|
+
/**
|
|
229
|
+
* Variable schema for advanced autocomplete with nested drilling.
|
|
230
|
+
* When provided, enables dot notation (user.name) and array access (items[0]).
|
|
231
|
+
* @deprecated Use `variables.schema` instead
|
|
232
|
+
*/
|
|
233
|
+
variableSchema?: VariableSchema;
|
|
234
|
+
/**
|
|
235
|
+
* Simple variable names for basic hints (backward compatible).
|
|
236
|
+
* Used when variableSchema is not provided.
|
|
237
|
+
* @deprecated Use `variables.schema` instead
|
|
238
|
+
*/
|
|
224
239
|
variableHints?: string[];
|
|
225
240
|
/** Placeholder variable example for the hint */
|
|
226
241
|
placeholderExample?: string;
|
|
@@ -318,6 +333,28 @@ export interface FieldSchema {
|
|
|
318
333
|
required?: string[];
|
|
319
334
|
/** Autocomplete configuration for fetching suggestions from callback URL */
|
|
320
335
|
autocomplete?: AutocompleteConfig;
|
|
336
|
+
/**
|
|
337
|
+
* Whether the field is read-only (JSON Schema readOnly keyword).
|
|
338
|
+
* When true, the field is displayed but cannot be edited.
|
|
339
|
+
*/
|
|
340
|
+
readOnly?: boolean;
|
|
341
|
+
/**
|
|
342
|
+
* Configuration for template variable autocomplete.
|
|
343
|
+
* Controls which input ports provide variables and how they are displayed.
|
|
344
|
+
*
|
|
345
|
+
* @example
|
|
346
|
+
* ```json
|
|
347
|
+
* {
|
|
348
|
+
* "type": "string",
|
|
349
|
+
* "format": "template",
|
|
350
|
+
* "variables": {
|
|
351
|
+
* "ports": ["data", "context"],
|
|
352
|
+
* "showHints": true
|
|
353
|
+
* }
|
|
354
|
+
* }
|
|
355
|
+
* ```
|
|
356
|
+
*/
|
|
357
|
+
variables?: TemplateVariablesConfig;
|
|
321
358
|
/** Allow additional properties not defined by the schema */
|
|
322
359
|
[key: string]: unknown;
|
|
323
360
|
}
|
|
@@ -15,7 +15,7 @@ export function isFieldOptionArray(options) {
|
|
|
15
15
|
* Type guard to check if items are OneOfItem objects (JSON Schema oneOf pattern)
|
|
16
16
|
*/
|
|
17
17
|
export function isOneOfArray(items) {
|
|
18
|
-
return items.length > 0 && typeof items[0] === 'object' && items[0] !== null && 'const' in items[0];
|
|
18
|
+
return (items.length > 0 && typeof items[0] === 'object' && items[0] !== null && 'const' in items[0]);
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* Convert JSON Schema oneOf items to FieldOption format
|
|
@@ -377,7 +377,9 @@
|
|
|
377
377
|
aria-label="Resize bottom panel"
|
|
378
378
|
tabindex="0"
|
|
379
379
|
>
|
|
380
|
-
<div
|
|
380
|
+
<div
|
|
381
|
+
class="flowdrop-main-layout__divider-handle flowdrop-main-layout__divider-handle--horizontal"
|
|
382
|
+
></div>
|
|
381
383
|
</div>
|
|
382
384
|
{/if}
|
|
383
385
|
|
|
@@ -630,7 +632,8 @@
|
|
|
630
632
|
transform: scaleX(1.2);
|
|
631
633
|
}
|
|
632
634
|
|
|
633
|
-
.flowdrop-main-layout__divider--bottom.flowdrop-main-layout__divider--active
|
|
635
|
+
.flowdrop-main-layout__divider--bottom.flowdrop-main-layout__divider--active
|
|
636
|
+
.flowdrop-main-layout__divider-handle--horizontal {
|
|
634
637
|
transform: scaleX(1.4);
|
|
635
638
|
}
|
|
636
639
|
|
|
@@ -511,10 +511,6 @@
|
|
|
511
511
|
gap: var(--fd-space-2);
|
|
512
512
|
}
|
|
513
513
|
|
|
514
|
-
.flowdrop-gap--3 {
|
|
515
|
-
gap: var(--fd-space-3);
|
|
516
|
-
}
|
|
517
|
-
|
|
518
514
|
.flowdrop-items--center {
|
|
519
515
|
align-items: center;
|
|
520
516
|
}
|
|
@@ -556,10 +552,6 @@
|
|
|
556
552
|
white-space: nowrap;
|
|
557
553
|
}
|
|
558
554
|
|
|
559
|
-
.flowdrop-mt--1 {
|
|
560
|
-
margin-top: var(--fd-space-1);
|
|
561
|
-
}
|
|
562
|
-
|
|
563
555
|
.flowdrop-text--right {
|
|
564
556
|
text-align: right;
|
|
565
557
|
}
|
|
@@ -283,11 +283,10 @@
|
|
|
283
283
|
color: var(--fd-foreground);
|
|
284
284
|
}
|
|
285
285
|
|
|
286
|
-
/* Normal layout (default) */
|
|
286
|
+
/* Normal layout (default): min-height allows variable height for longer descriptions */
|
|
287
287
|
.flowdrop-simple-node--normal {
|
|
288
288
|
width: var(--fd-node-default-width);
|
|
289
|
-
height: var(--fd-node-simple-height);
|
|
290
|
-
overflow: hidden;
|
|
289
|
+
min-height: var(--fd-node-simple-height);
|
|
291
290
|
}
|
|
292
291
|
|
|
293
292
|
.flowdrop-simple-node:hover {
|
|
@@ -509,10 +509,6 @@
|
|
|
509
509
|
gap: var(--fd-space-2);
|
|
510
510
|
}
|
|
511
511
|
|
|
512
|
-
.flowdrop-gap--3 {
|
|
513
|
-
gap: var(--fd-space-3);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
512
|
.flowdrop-items--center {
|
|
517
513
|
align-items: center;
|
|
518
514
|
}
|
|
@@ -549,10 +545,6 @@
|
|
|
549
545
|
white-space: nowrap;
|
|
550
546
|
}
|
|
551
547
|
|
|
552
|
-
.flowdrop-mt--1 {
|
|
553
|
-
margin-top: var(--fd-space-1);
|
|
554
|
-
}
|
|
555
|
-
|
|
556
548
|
.flowdrop-text--right {
|
|
557
549
|
text-align: right;
|
|
558
550
|
}
|
|
@@ -556,43 +556,43 @@
|
|
|
556
556
|
<p class="playground__sessions-hint">Click a session to load it</p>
|
|
557
557
|
{/if}
|
|
558
558
|
<div class="playground__sessions">
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
</div>
|
|
563
|
-
{:else}
|
|
564
|
-
{#each $sessions as session (session.id)}
|
|
565
|
-
<div
|
|
566
|
-
class="playground__session"
|
|
567
|
-
class:playground__session--active={$currentSession?.id === session.id}
|
|
568
|
-
role="button"
|
|
569
|
-
tabindex="0"
|
|
570
|
-
title="Click to load this session"
|
|
571
|
-
aria-label="Load session: {session.name}"
|
|
572
|
-
onclick={() => handleSelectSession(session.id)}
|
|
573
|
-
onkeydown={(e) => e.key === 'Enter' && handleSelectSession(session.id)}
|
|
574
|
-
>
|
|
575
|
-
<span class="playground__session-name" title={session.name}>
|
|
576
|
-
{session.name}
|
|
577
|
-
</span>
|
|
578
|
-
<button
|
|
579
|
-
type="button"
|
|
580
|
-
class="playground__session-menu"
|
|
581
|
-
class:playground__session-menu--delete={pendingDeleteId === session.id}
|
|
582
|
-
onclick={(e) => handleDeleteClick(e, session.id)}
|
|
583
|
-
title={pendingDeleteId === session.id
|
|
584
|
-
? 'Click to confirm delete'
|
|
585
|
-
: 'Delete session'}
|
|
586
|
-
>
|
|
587
|
-
{#if pendingDeleteId === session.id}
|
|
588
|
-
<Icon icon="mdi:check" />
|
|
589
|
-
{:else}
|
|
590
|
-
<Icon icon="mdi:dots-horizontal" />
|
|
591
|
-
{/if}
|
|
592
|
-
</button>
|
|
559
|
+
{#if $sessions.length === 0 && !$isLoading}
|
|
560
|
+
<div class="playground__sessions-empty">
|
|
561
|
+
<span>No sessions yet</span>
|
|
593
562
|
</div>
|
|
594
|
-
{
|
|
595
|
-
|
|
563
|
+
{:else}
|
|
564
|
+
{#each $sessions as session (session.id)}
|
|
565
|
+
<div
|
|
566
|
+
class="playground__session"
|
|
567
|
+
class:playground__session--active={$currentSession?.id === session.id}
|
|
568
|
+
role="button"
|
|
569
|
+
tabindex="0"
|
|
570
|
+
title="Click to load this session"
|
|
571
|
+
aria-label="Load session: {session.name}"
|
|
572
|
+
onclick={() => handleSelectSession(session.id)}
|
|
573
|
+
onkeydown={(e) => e.key === 'Enter' && handleSelectSession(session.id)}
|
|
574
|
+
>
|
|
575
|
+
<span class="playground__session-name" title={session.name}>
|
|
576
|
+
{session.name}
|
|
577
|
+
</span>
|
|
578
|
+
<button
|
|
579
|
+
type="button"
|
|
580
|
+
class="playground__session-menu"
|
|
581
|
+
class:playground__session-menu--delete={pendingDeleteId === session.id}
|
|
582
|
+
onclick={(e) => handleDeleteClick(e, session.id)}
|
|
583
|
+
title={pendingDeleteId === session.id
|
|
584
|
+
? 'Click to confirm delete'
|
|
585
|
+
: 'Delete session'}
|
|
586
|
+
>
|
|
587
|
+
{#if pendingDeleteId === session.id}
|
|
588
|
+
<Icon icon="mdi:check" />
|
|
589
|
+
{:else}
|
|
590
|
+
<Icon icon="mdi:dots-horizontal" />
|
|
591
|
+
{/if}
|
|
592
|
+
</button>
|
|
593
|
+
</div>
|
|
594
|
+
{/each}
|
|
595
|
+
{/if}
|
|
596
596
|
</div>
|
|
597
597
|
</div>
|
|
598
598
|
</div>
|
|
@@ -774,7 +774,10 @@
|
|
|
774
774
|
font-size: 0.875rem;
|
|
775
775
|
font-weight: 500;
|
|
776
776
|
cursor: pointer;
|
|
777
|
-
transition:
|
|
777
|
+
transition:
|
|
778
|
+
background-color 0.15s ease,
|
|
779
|
+
border-color 0.15s ease,
|
|
780
|
+
transform 0.1s ease;
|
|
778
781
|
box-sizing: border-box;
|
|
779
782
|
}
|
|
780
783
|
|
|
@@ -839,7 +842,9 @@
|
|
|
839
842
|
border-radius: var(--fd-radius-md);
|
|
840
843
|
border-left: 3px solid transparent;
|
|
841
844
|
cursor: pointer;
|
|
842
|
-
transition:
|
|
845
|
+
transition:
|
|
846
|
+
background-color 0.15s ease,
|
|
847
|
+
border-left-color 0.15s ease;
|
|
843
848
|
}
|
|
844
849
|
|
|
845
850
|
.playground__session:hover {
|
package/dist/editor/index.d.ts
CHANGED
|
@@ -63,7 +63,9 @@ export { default as MessageBubble } from '../components/playground/MessageBubble
|
|
|
63
63
|
export { mountWorkflowEditor, mountFlowDropApp, unmountFlowDropApp } from '../svelte-app.js';
|
|
64
64
|
export { nodeComponentRegistry, createNamespacedType, parseNamespacedType, BUILTIN_NODE_COMPONENTS, BUILTIN_NODE_TYPES, FLOWDROP_SOURCE, registerBuiltinNodes, areBuiltinsRegistered, isBuiltinType, getBuiltinTypes, resolveBuiltinAlias, registerFlowDropPlugin, unregisterFlowDropPlugin, registerCustomNode, createPlugin, isValidNamespace, getRegisteredPlugins, getPluginNodeCount } from '../registry/index.js';
|
|
65
65
|
export { EdgeStylingHelper, NodeOperationsHelper, WorkflowOperationsHelper, ConfigurationHelper } from '../helpers/workflowEditorHelper.js';
|
|
66
|
-
export { workflowStore, workflowActions, workflowId, workflowName, workflowNodes, workflowEdges, workflowMetadata, workflowChanged, workflowValidation, workflowMetadataChanged, connectedHandles, isDirtyStore, isDirty, markAsSaved, getWorkflow as getWorkflowFromStore, setOnDirtyStateChange, setOnWorkflowChange } from '../stores/workflowStore.js';
|
|
66
|
+
export { workflowStore, workflowActions, workflowId, workflowName, workflowNodes, workflowEdges, workflowMetadata, workflowChanged, workflowValidation, workflowMetadataChanged, connectedHandles, isDirtyStore, isDirty, markAsSaved, getWorkflow as getWorkflowFromStore, setOnDirtyStateChange, setOnWorkflowChange, setHistoryEnabled, isHistoryEnabled, setRestoringFromHistory } from '../stores/workflowStore.js';
|
|
67
|
+
export { historyStateStore, canUndo, canRedo, historyActions, setOnRestoreCallback, historyService, HistoryService } from '../stores/historyStore.js';
|
|
68
|
+
export type { HistoryEntry, HistoryState, PushOptions } from '../stores/historyStore.js';
|
|
67
69
|
export * from '../services/api.js';
|
|
68
70
|
export { showSuccess, showError, showWarning, showInfo, showLoading, dismissToast, dismissAllToasts, showPromise, showConfirmation, apiToasts, workflowToasts, pipelineToasts } from '../services/toastService.js';
|
|
69
71
|
export { NodeExecutionService, nodeExecutionService } from '../services/nodeExecutionService.js';
|
package/dist/editor/index.js
CHANGED
|
@@ -98,7 +98,11 @@ export { EdgeStylingHelper, NodeOperationsHelper, WorkflowOperationsHelper, Conf
|
|
|
98
98
|
// ============================================================================
|
|
99
99
|
export { workflowStore, workflowActions, workflowId, workflowName, workflowNodes, workflowEdges, workflowMetadata, workflowChanged, workflowValidation, workflowMetadataChanged, connectedHandles,
|
|
100
100
|
// Dirty state tracking
|
|
101
|
-
isDirtyStore, isDirty, markAsSaved, getWorkflow as getWorkflowFromStore, setOnDirtyStateChange, setOnWorkflowChange
|
|
101
|
+
isDirtyStore, isDirty, markAsSaved, getWorkflow as getWorkflowFromStore, setOnDirtyStateChange, setOnWorkflowChange,
|
|
102
|
+
// History control
|
|
103
|
+
setHistoryEnabled, isHistoryEnabled, setRestoringFromHistory } from '../stores/workflowStore.js';
|
|
104
|
+
// History Store and Service
|
|
105
|
+
export { historyStateStore, canUndo, canRedo, historyActions, setOnRestoreCallback, historyService, HistoryService } from '../stores/historyStore.js';
|
|
102
106
|
// ============================================================================
|
|
103
107
|
// Services
|
|
104
108
|
// ============================================================================
|
|
@@ -189,8 +189,7 @@ export class EdgeStylingHelper {
|
|
|
189
189
|
break;
|
|
190
190
|
case 'trigger':
|
|
191
191
|
// Trigger edges: solid dark line for control flow
|
|
192
|
-
edge.style =
|
|
193
|
-
'stroke: var(--fd-edge-trigger); stroke-width: var(--fd-edge-trigger-width);';
|
|
192
|
+
edge.style = 'stroke: var(--fd-edge-trigger); stroke-width: var(--fd-edge-trigger-width);';
|
|
194
193
|
edge.class = 'flowdrop--edge--trigger';
|
|
195
194
|
edge.markerEnd = {
|
|
196
195
|
type: MarkerType.ArrowClosed,
|
|
@@ -226,22 +226,22 @@ declare class NodeComponentRegistry {
|
|
|
226
226
|
*/
|
|
227
227
|
private notifyListeners;
|
|
228
228
|
/**
|
|
229
|
-
* Get
|
|
230
|
-
* Returns
|
|
229
|
+
* Get oneOf options for config forms.
|
|
230
|
+
* Returns array suitable for JSON Schema oneOf with const/title.
|
|
231
231
|
*
|
|
232
232
|
* @param filterFn - Optional filter function to limit which types are included
|
|
233
|
-
* @returns
|
|
233
|
+
* @returns Array of oneOf items with const (type value) and title (display name)
|
|
234
234
|
*
|
|
235
235
|
* @example
|
|
236
236
|
* ```typescript
|
|
237
|
-
* const
|
|
238
|
-
* // Use in configSchema: { type: "string",
|
|
237
|
+
* const oneOf = nodeComponentRegistry.getOneOfOptions();
|
|
238
|
+
* // Use in configSchema: { type: "string", oneOf }
|
|
239
239
|
* ```
|
|
240
240
|
*/
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
241
|
+
getOneOfOptions(filterFn?: (reg: NodeComponentRegistration) => boolean): Array<{
|
|
242
|
+
const: string;
|
|
243
|
+
title: string;
|
|
244
|
+
}>;
|
|
245
245
|
/**
|
|
246
246
|
* Get the status position for a node type.
|
|
247
247
|
*
|
|
@@ -215,24 +215,24 @@ class NodeComponentRegistry {
|
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
/**
|
|
218
|
-
* Get
|
|
219
|
-
* Returns
|
|
218
|
+
* Get oneOf options for config forms.
|
|
219
|
+
* Returns array suitable for JSON Schema oneOf with const/title.
|
|
220
220
|
*
|
|
221
221
|
* @param filterFn - Optional filter function to limit which types are included
|
|
222
|
-
* @returns
|
|
222
|
+
* @returns Array of oneOf items with const (type value) and title (display name)
|
|
223
223
|
*
|
|
224
224
|
* @example
|
|
225
225
|
* ```typescript
|
|
226
|
-
* const
|
|
227
|
-
* // Use in configSchema: { type: "string",
|
|
226
|
+
* const oneOf = nodeComponentRegistry.getOneOfOptions();
|
|
227
|
+
* // Use in configSchema: { type: "string", oneOf }
|
|
228
228
|
* ```
|
|
229
229
|
*/
|
|
230
|
-
|
|
230
|
+
getOneOfOptions(filterFn) {
|
|
231
231
|
const registrations = filterFn ? this.getAll().filter(filterFn) : this.getAll();
|
|
232
|
-
return {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
};
|
|
232
|
+
return registrations.map((r) => ({
|
|
233
|
+
const: r.type,
|
|
234
|
+
title: r.displayName
|
|
235
|
+
}));
|
|
236
236
|
}
|
|
237
237
|
/**
|
|
238
238
|
* Get the status position for a node type.
|