@d34dman/flowdrop 0.0.47 → 0.0.49
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/dist/components/App.svelte +11 -0
- package/dist/components/App.svelte.d.ts +2 -0
- package/dist/components/ConfigForm.svelte +31 -5
- package/dist/components/ConfigForm.svelte.d.ts +3 -1
- package/dist/components/NodeSidebar.svelte +1 -0
- package/dist/components/SchemaForm.svelte +4 -2
- package/dist/components/SettingsPanel.svelte +3 -3
- package/dist/components/form/FormAutocomplete.svelte +9 -4
- package/dist/components/form/FormCodeEditor.svelte +17 -15
- package/dist/components/form/FormField.svelte +32 -4
- package/dist/components/form/FormField.svelte.d.ts +11 -0
- package/dist/components/form/FormFieldLight.svelte +0 -1
- package/dist/components/form/FormTemplateEditor.svelte +300 -79
- package/dist/components/form/FormTemplateEditor.svelte.d.ts +11 -7
- package/dist/components/form/index.d.ts +1 -1
- package/dist/components/form/index.js +1 -1
- package/dist/components/form/templateAutocomplete.d.ts +2 -11
- package/dist/components/form/templateAutocomplete.js +49 -104
- package/dist/components/form/types.d.ts +0 -6
- package/dist/components/nodes/TerminalNode.svelte +27 -15
- package/dist/components/nodes/ToolNode.svelte +4 -6
- package/dist/services/apiVariableService.d.ts +116 -0
- package/dist/services/apiVariableService.js +338 -0
- package/dist/services/globalSave.js +6 -0
- package/dist/services/variableService.d.ts +50 -9
- package/dist/services/variableService.js +139 -44
- package/dist/svelte-app.d.ts +5 -0
- package/dist/svelte-app.js +7 -1
- package/dist/types/index.d.ts +138 -1
- package/dist/types/settings.js +4 -4
- package/dist/utils/colors.js +1 -0
- package/dist/utils/handlePositioning.d.ts +31 -0
- package/dist/utils/handlePositioning.js +35 -0
- package/dist/utils/icons.js +1 -0
- package/dist/utils/nodeTypes.js +3 -3
- package/package.json +8 -4
|
@@ -10,20 +10,20 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @module components/form/templateAutocomplete
|
|
12
12
|
*/
|
|
13
|
-
import { autocompletion } from
|
|
14
|
-
import { getChildVariables, getArrayIndexSuggestions, isArrayVariable, hasChildren } from
|
|
13
|
+
import { autocompletion } from '@codemirror/autocomplete';
|
|
14
|
+
import { getChildVariables, getArrayIndexSuggestions, isArrayVariable, hasChildren } from '../../services/variableService.js';
|
|
15
15
|
/**
|
|
16
16
|
* Icon type hints for different variable types in autocomplete dropdown.
|
|
17
17
|
*/
|
|
18
18
|
const TYPE_ICONS = {
|
|
19
|
-
string:
|
|
20
|
-
number:
|
|
21
|
-
integer:
|
|
22
|
-
float:
|
|
23
|
-
boolean:
|
|
24
|
-
array:
|
|
25
|
-
object:
|
|
26
|
-
mixed:
|
|
19
|
+
string: '𝑆',
|
|
20
|
+
number: '#',
|
|
21
|
+
integer: '#',
|
|
22
|
+
float: '#',
|
|
23
|
+
boolean: '☑',
|
|
24
|
+
array: '[]',
|
|
25
|
+
object: '{}',
|
|
26
|
+
mixed: '⋯'
|
|
27
27
|
};
|
|
28
28
|
/**
|
|
29
29
|
* Extracts the current variable path being typed inside {{ }}.
|
|
@@ -43,12 +43,12 @@ function extractVariablePath(text, pos) {
|
|
|
43
43
|
let searchPos = pos - 1;
|
|
44
44
|
while (searchPos >= 0) {
|
|
45
45
|
// Check for opening {{
|
|
46
|
-
if (text[searchPos] ===
|
|
46
|
+
if (text[searchPos] === '{' && searchPos > 0 && text[searchPos - 1] === '{') {
|
|
47
47
|
openBracePos = searchPos - 1;
|
|
48
48
|
break;
|
|
49
49
|
}
|
|
50
50
|
// Check for closing }} - means we're outside an expression
|
|
51
|
-
if (text[searchPos] ===
|
|
51
|
+
if (text[searchPos] === '}' && searchPos > 0 && text[searchPos - 1] === '}') {
|
|
52
52
|
return null;
|
|
53
53
|
}
|
|
54
54
|
searchPos--;
|
|
@@ -65,7 +65,8 @@ function extractVariablePath(text, pos) {
|
|
|
65
65
|
const content = text.slice(contentStart, pos).trimStart();
|
|
66
66
|
return {
|
|
67
67
|
path: content,
|
|
68
|
-
startPos: contentStart +
|
|
68
|
+
startPos: contentStart +
|
|
69
|
+
(text.slice(contentStart, pos).length - text.slice(contentStart, pos).trimStart().length),
|
|
69
70
|
isInsideExpression: true
|
|
70
71
|
};
|
|
71
72
|
}
|
|
@@ -77,35 +78,35 @@ function extractVariablePath(text, pos) {
|
|
|
77
78
|
*/
|
|
78
79
|
function getCompletionType(path) {
|
|
79
80
|
// Empty or only whitespace - show top-level variables
|
|
80
|
-
if (path.trim() ===
|
|
81
|
-
return { type:
|
|
81
|
+
if (path.trim() === '') {
|
|
82
|
+
return { type: 'top-level' };
|
|
82
83
|
}
|
|
83
84
|
// Ends with [ - show array indices
|
|
84
|
-
if (path.endsWith(
|
|
85
|
+
if (path.endsWith('[')) {
|
|
85
86
|
const parentPath = path.slice(0, -1);
|
|
86
|
-
return { type:
|
|
87
|
+
return { type: 'array-index', parentPath };
|
|
87
88
|
}
|
|
88
89
|
// Ends with . - show child properties
|
|
89
|
-
if (path.endsWith(
|
|
90
|
+
if (path.endsWith('.')) {
|
|
90
91
|
const parentPath = path.slice(0, -1);
|
|
91
|
-
return { type:
|
|
92
|
+
return { type: 'property', parentPath };
|
|
92
93
|
}
|
|
93
94
|
// Otherwise, we're typing a variable name - show matching options
|
|
94
|
-
const lastDotIndex = path.lastIndexOf(
|
|
95
|
-
const lastBracketIndex = path.lastIndexOf(
|
|
95
|
+
const lastDotIndex = path.lastIndexOf('.');
|
|
96
|
+
const lastBracketIndex = path.lastIndexOf('[');
|
|
96
97
|
const lastSeparator = Math.max(lastDotIndex, lastBracketIndex);
|
|
97
98
|
if (lastSeparator === -1) {
|
|
98
99
|
// Typing at top level
|
|
99
|
-
return { type:
|
|
100
|
+
return { type: 'top-level' };
|
|
100
101
|
}
|
|
101
102
|
// Extract parent path based on separator
|
|
102
103
|
if (lastDotIndex > lastBracketIndex) {
|
|
103
104
|
// Last separator was a dot
|
|
104
|
-
return { type:
|
|
105
|
+
return { type: 'property', parentPath: path.slice(0, lastDotIndex) };
|
|
105
106
|
}
|
|
106
107
|
else {
|
|
107
108
|
// Last separator was a bracket
|
|
108
|
-
return { type:
|
|
109
|
+
return { type: 'array-index', parentPath: path.slice(0, lastBracketIndex) };
|
|
109
110
|
}
|
|
110
111
|
}
|
|
111
112
|
/**
|
|
@@ -115,22 +116,22 @@ function getCompletionType(path) {
|
|
|
115
116
|
* @param prefix - Prefix to add to the completion label
|
|
116
117
|
* @returns A CodeMirror Completion object
|
|
117
118
|
*/
|
|
118
|
-
function variableToCompletion(variable, prefix =
|
|
119
|
+
function variableToCompletion(variable, prefix = '') {
|
|
119
120
|
const icon = TYPE_ICONS[variable.type] ?? TYPE_ICONS.mixed;
|
|
120
121
|
const hasChildProps = variable.properties && Object.keys(variable.properties).length > 0;
|
|
121
|
-
const isArray = variable.type ===
|
|
122
|
+
const isArray = variable.type === 'array';
|
|
122
123
|
// Add indicator if variable can be drilled into
|
|
123
|
-
let suffix =
|
|
124
|
+
let suffix = '';
|
|
124
125
|
if (hasChildProps)
|
|
125
|
-
suffix =
|
|
126
|
+
suffix = '.';
|
|
126
127
|
else if (isArray)
|
|
127
|
-
suffix =
|
|
128
|
+
suffix = '[';
|
|
128
129
|
return {
|
|
129
130
|
label: `${prefix}${variable.name}`,
|
|
130
|
-
displayLabel: `${icon} ${variable.label ?? variable.name}${suffix ?
|
|
131
|
+
displayLabel: `${icon} ${variable.label ?? variable.name}${suffix ? ' ' + suffix : ''}`,
|
|
131
132
|
detail: variable.type,
|
|
132
133
|
info: variable.description,
|
|
133
|
-
type:
|
|
134
|
+
type: 'variable',
|
|
134
135
|
boost: hasChildProps || isArray ? 1 : 0 // Boost drillable variables
|
|
135
136
|
};
|
|
136
137
|
}
|
|
@@ -149,7 +150,7 @@ function createTemplateCompletionSource(schema) {
|
|
|
149
150
|
if (!pathInfo) {
|
|
150
151
|
// Check if user just typed {{
|
|
151
152
|
const beforeCursor = text.slice(Math.max(0, pos - 2), pos);
|
|
152
|
-
if (beforeCursor ===
|
|
153
|
+
if (beforeCursor === '{{') {
|
|
153
154
|
// Show top-level variables
|
|
154
155
|
const options = Object.values(schema.variables).map((v) => variableToCompletion(v));
|
|
155
156
|
return {
|
|
@@ -165,42 +166,42 @@ function createTemplateCompletionSource(schema) {
|
|
|
165
166
|
let options = [];
|
|
166
167
|
let from = pos;
|
|
167
168
|
switch (completionType.type) {
|
|
168
|
-
case
|
|
169
|
+
case 'top-level': {
|
|
169
170
|
// Show all top-level variables
|
|
170
171
|
const currentWord = path.trim();
|
|
171
172
|
options = Object.values(schema.variables)
|
|
172
|
-
.filter((v) => currentWord ===
|
|
173
|
+
.filter((v) => currentWord === '' || v.name.toLowerCase().startsWith(currentWord.toLowerCase()))
|
|
173
174
|
.map((v) => variableToCompletion(v));
|
|
174
175
|
// Calculate from position for replacement
|
|
175
176
|
from = startPos + (path.length - path.trimStart().length);
|
|
176
177
|
break;
|
|
177
178
|
}
|
|
178
|
-
case
|
|
179
|
+
case 'property': {
|
|
179
180
|
// Show child properties of the parent
|
|
180
181
|
const children = getChildVariables(schema, completionType.parentPath);
|
|
181
|
-
const currentWord = path.slice(path.lastIndexOf(
|
|
182
|
+
const currentWord = path.slice(path.lastIndexOf('.') + 1);
|
|
182
183
|
options = children
|
|
183
|
-
.filter((v) => currentWord ===
|
|
184
|
+
.filter((v) => currentWord === '' || v.name.toLowerCase().startsWith(currentWord.toLowerCase()))
|
|
184
185
|
.map((v) => variableToCompletion(v));
|
|
185
186
|
// From should be right after the last dot
|
|
186
|
-
from = startPos + path.lastIndexOf(
|
|
187
|
+
from = startPos + path.lastIndexOf('.') + 1;
|
|
187
188
|
break;
|
|
188
189
|
}
|
|
189
|
-
case
|
|
190
|
+
case 'array-index': {
|
|
190
191
|
// Check if the parent is actually an array
|
|
191
192
|
if (isArrayVariable(schema, completionType.parentPath)) {
|
|
192
193
|
const indices = getArrayIndexSuggestions(5);
|
|
193
|
-
const currentIndex = path.slice(path.lastIndexOf(
|
|
194
|
+
const currentIndex = path.slice(path.lastIndexOf('[') + 1);
|
|
194
195
|
options = indices
|
|
195
|
-
.filter((idx) => currentIndex ===
|
|
196
|
+
.filter((idx) => currentIndex === '' || idx.startsWith(currentIndex))
|
|
196
197
|
.map((idx) => ({
|
|
197
198
|
label: idx,
|
|
198
|
-
displayLabel: idx ===
|
|
199
|
-
detail: idx ===
|
|
200
|
-
type:
|
|
199
|
+
displayLabel: idx === '*]' ? '* (all items)' : `[${idx}`,
|
|
200
|
+
detail: idx === '*]' ? 'Iterate all items' : `Index ${idx.slice(0, -1)}`,
|
|
201
|
+
type: 'keyword'
|
|
201
202
|
}));
|
|
202
203
|
// From should be right after the [
|
|
203
|
-
from = startPos + path.lastIndexOf(
|
|
204
|
+
from = startPos + path.lastIndexOf('[') + 1;
|
|
204
205
|
}
|
|
205
206
|
break;
|
|
206
207
|
}
|
|
@@ -234,13 +235,13 @@ export function createTemplateAutocomplete(schema) {
|
|
|
234
235
|
override: [createTemplateCompletionSource(schema)],
|
|
235
236
|
activateOnTyping: true,
|
|
236
237
|
defaultKeymap: true,
|
|
237
|
-
optionClass: () =>
|
|
238
|
+
optionClass: () => 'cm-template-autocomplete-option',
|
|
238
239
|
icons: false, // We use our own icons in displayLabel
|
|
239
240
|
addToOptions: [
|
|
240
241
|
{
|
|
241
242
|
render: (completion) => {
|
|
242
|
-
const el = document.createElement(
|
|
243
|
-
el.className =
|
|
243
|
+
const el = document.createElement('span');
|
|
244
|
+
el.className = 'cm-template-autocomplete-info';
|
|
244
245
|
if (completion.info) {
|
|
245
246
|
el.textContent = String(completion.info);
|
|
246
247
|
}
|
|
@@ -251,59 +252,3 @@ export function createTemplateAutocomplete(schema) {
|
|
|
251
252
|
]
|
|
252
253
|
});
|
|
253
254
|
}
|
|
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
|
-
}
|
|
@@ -231,12 +231,6 @@ export interface TemplateEditorFieldProps extends BaseFieldProps {
|
|
|
231
231
|
* @deprecated Use `variables.schema` instead
|
|
232
232
|
*/
|
|
233
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
|
-
*/
|
|
239
|
-
variableHints?: string[];
|
|
240
234
|
/** Placeholder variable example for the hint */
|
|
241
235
|
placeholderExample?: string;
|
|
242
236
|
/** Callback when value changes */
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import Icon from '@iconify/svelte';
|
|
15
15
|
import { getDataTypeColor, getCategoryColorToken } from '../../utils/colors.js';
|
|
16
16
|
import { getNodeIcon } from '../../utils/icons.js';
|
|
17
|
+
import { getCircleHandlePosition } from '../../utils/handlePositioning.js';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Terminal node variant types
|
|
@@ -316,13 +317,14 @@
|
|
|
316
317
|
<div class="flowdrop-terminal-node__circle-wrapper">
|
|
317
318
|
<!-- Input Handles (for end/exit variants) -->
|
|
318
319
|
{#if showInputs}
|
|
319
|
-
{#each inputPorts as port (port.id)}
|
|
320
|
+
{#each inputPorts as port, index (port.id)}
|
|
321
|
+
{@const pos = getCircleHandlePosition(index, inputPorts.length, 'left')}
|
|
320
322
|
<Handle
|
|
321
323
|
type="target"
|
|
322
324
|
position={Position.Left}
|
|
323
325
|
style="--fd-handle-fill: {getDataTypeColor(
|
|
324
326
|
port.dataType
|
|
325
|
-
)}; --fd-handle-border-color: var(--fd-handle-border); top:
|
|
327
|
+
)}; --fd-handle-border-color: var(--fd-handle-border); left: {pos.left}px; top: {pos.top}px; transform: translate(-50%, -50%); z-index: 30;"
|
|
326
328
|
id={`${props.data.nodeId}-input-${port.id}`}
|
|
327
329
|
/>
|
|
328
330
|
{/each}
|
|
@@ -337,14 +339,15 @@
|
|
|
337
339
|
|
|
338
340
|
<!-- Output Handles (for start variant) -->
|
|
339
341
|
{#if showOutputs}
|
|
340
|
-
{#each outputPorts as port (port.id)}
|
|
342
|
+
{#each outputPorts as port, index (port.id)}
|
|
343
|
+
{@const pos = getCircleHandlePosition(index, outputPorts.length, 'right')}
|
|
341
344
|
<Handle
|
|
342
345
|
type="source"
|
|
343
346
|
position={Position.Right}
|
|
344
347
|
id={`${props.data.nodeId}-output-${port.id}`}
|
|
345
348
|
style="--fd-handle-fill: {getDataTypeColor(
|
|
346
349
|
port.dataType
|
|
347
|
-
)}; --fd-handle-border-color: var(--fd-handle-border); top:
|
|
350
|
+
)}; --fd-handle-border-color: var(--fd-handle-border); left: {pos.left}px; top: {pos.top}px; transform: translate(-50%, -50%); z-index: 30;"
|
|
348
351
|
/>
|
|
349
352
|
{/each}
|
|
350
353
|
{/if}
|
|
@@ -614,25 +617,34 @@
|
|
|
614
617
|
}
|
|
615
618
|
}
|
|
616
619
|
|
|
617
|
-
/* Handle
|
|
618
|
-
:global(.flowdrop-terminal-node__circle-wrapper .svelte-flow__handle)
|
|
619
|
-
|
|
620
|
+
/* Handle styles - positioned along circle arc using cos/sin */
|
|
621
|
+
:global(.flowdrop-terminal-node__circle-wrapper .svelte-flow__handle) {
|
|
622
|
+
width: 16px !important;
|
|
623
|
+
height: 16px !important;
|
|
624
|
+
border-radius: 50% !important;
|
|
625
|
+
border: 2px solid var(--fd-handle-border) !important;
|
|
626
|
+
transition: all var(--fd-transition-normal) !important;
|
|
627
|
+
cursor: pointer !important;
|
|
620
628
|
z-index: 20 !important;
|
|
621
629
|
pointer-events: auto !important;
|
|
622
630
|
}
|
|
623
631
|
|
|
624
|
-
:global(.flowdrop-terminal-node__circle-wrapper .svelte-flow__handle
|
|
625
|
-
|
|
626
|
-
|
|
632
|
+
:global(.flowdrop-terminal-node__circle-wrapper .svelte-flow__handle:hover) {
|
|
633
|
+
transform: translate(-50%, -50%) scale(1.2) !important;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
:global(.flowdrop-terminal-node__circle-wrapper .svelte-flow__handle:focus) {
|
|
637
|
+
outline: 2px solid var(--fd-ring) !important;
|
|
638
|
+
outline-offset: 2px !important;
|
|
627
639
|
}
|
|
628
640
|
|
|
629
|
-
|
|
630
|
-
:global(.svelte-flow__node-terminal .svelte-flow__handle
|
|
631
|
-
|
|
641
|
+
/* Also keep node-level handle styles for fallback */
|
|
642
|
+
:global(.svelte-flow__node-terminal .svelte-flow__handle) {
|
|
643
|
+
z-index: 20 !important;
|
|
644
|
+
pointer-events: auto !important;
|
|
632
645
|
}
|
|
633
646
|
|
|
634
|
-
:global(.flowdrop-terminal-node__circle-wrapper .svelte-flow__handle:hover),
|
|
635
647
|
:global(.svelte-flow__node-terminal .svelte-flow__handle:hover) {
|
|
636
|
-
transform:
|
|
648
|
+
transform: translate(-50%, -50%) scale(1.2) !important;
|
|
637
649
|
}
|
|
638
650
|
</style>
|
|
@@ -230,7 +230,7 @@
|
|
|
230
230
|
.flowdrop-tool-node {
|
|
231
231
|
position: relative;
|
|
232
232
|
background-color: var(--fd-card);
|
|
233
|
-
border: 1.5px solid var(--fd-node-
|
|
233
|
+
border: 1.5px solid var(--fd-tool-node-color);
|
|
234
234
|
border-radius: var(--fd-radius-xl);
|
|
235
235
|
width: var(--fd-node-default-width);
|
|
236
236
|
min-height: var(--fd-node-tool-min-height);
|
|
@@ -246,7 +246,7 @@
|
|
|
246
246
|
|
|
247
247
|
.flowdrop-tool-node:hover {
|
|
248
248
|
box-shadow: var(--fd-shadow-lg);
|
|
249
|
-
border-color: var(--fd-node-
|
|
249
|
+
border-color: var(--fd-tool-node-color);
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
.flowdrop-tool-node--selected {
|
|
@@ -282,16 +282,14 @@
|
|
|
282
282
|
/* Light mode: mix tool color with white (95%) for subtle tint */
|
|
283
283
|
background-color: color-mix(in srgb, var(--fd-tool-node-color) 5%, white);
|
|
284
284
|
border-radius: var(--fd-radius-xl);
|
|
285
|
-
|
|
286
|
-
border: 1px solid color-mix(in srgb, var(--fd-tool-node-color) 40%, white);
|
|
285
|
+
border: none;
|
|
287
286
|
}
|
|
288
287
|
|
|
289
288
|
/* Dark mode header styles */
|
|
290
289
|
:global([data-theme='dark']) .flowdrop-tool-node__header {
|
|
291
290
|
/* Dark mode: mix tool color with dark background (15%) for subtle tint */
|
|
292
291
|
background-color: color-mix(in srgb, var(--fd-tool-node-color) 15%, #1a1a1e);
|
|
293
|
-
|
|
294
|
-
border-color: color-mix(in srgb, var(--fd-tool-node-color) 35%, #1a1a1e);
|
|
292
|
+
border: none;
|
|
295
293
|
}
|
|
296
294
|
|
|
297
295
|
.flowdrop-tool-node__header-content {
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Variable Service
|
|
3
|
+
* Handles fetching template variable schemas from REST endpoints at runtime.
|
|
4
|
+
* Enables dynamic variable suggestions from backend APIs for template editors.
|
|
5
|
+
*
|
|
6
|
+
* @module services/apiVariableService
|
|
7
|
+
*/
|
|
8
|
+
import type { VariableSchema, ApiVariablesConfig, AuthProvider } from '../types/index.js';
|
|
9
|
+
/**
|
|
10
|
+
* Context for variable API requests
|
|
11
|
+
*/
|
|
12
|
+
interface VariableContext {
|
|
13
|
+
/** Workflow ID */
|
|
14
|
+
workflowId?: string;
|
|
15
|
+
/** Node instance ID */
|
|
16
|
+
nodeId: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Result of a variable schema fetch operation
|
|
20
|
+
*/
|
|
21
|
+
export interface ApiVariableResult {
|
|
22
|
+
/** Whether the fetch was successful */
|
|
23
|
+
success: boolean;
|
|
24
|
+
/** The fetched variable schema (if successful) */
|
|
25
|
+
schema?: VariableSchema;
|
|
26
|
+
/** Error message (if failed) */
|
|
27
|
+
error?: string;
|
|
28
|
+
/** Whether the schema was loaded from cache */
|
|
29
|
+
fromCache?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Default cache TTL in milliseconds (5 minutes)
|
|
33
|
+
*/
|
|
34
|
+
export declare const DEFAULT_VARIABLE_CACHE_TTL: number;
|
|
35
|
+
/**
|
|
36
|
+
* Replaces {workflowId} and {nodeId} placeholders in URL template.
|
|
37
|
+
*
|
|
38
|
+
* @param template - The URL template string
|
|
39
|
+
* @param context - The variable context with workflowId and nodeId
|
|
40
|
+
* @returns The resolved URL with placeholders replaced
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const url = "/api/variables/{workflowId}/{nodeId}";
|
|
45
|
+
* const context = { workflowId: "wf-123", nodeId: "node-456" };
|
|
46
|
+
* resolveEndpointUrl(url, context);
|
|
47
|
+
* // Returns "/api/variables/wf-123/node-456"
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveEndpointUrl(template: string, context: VariableContext): string;
|
|
51
|
+
/**
|
|
52
|
+
* Fetches variable schema from a backend API endpoint.
|
|
53
|
+
*
|
|
54
|
+
* @param workflowId - The workflow ID (optional)
|
|
55
|
+
* @param nodeId - The node instance ID
|
|
56
|
+
* @param config - The API variables configuration
|
|
57
|
+
* @param authProvider - Optional auth provider for auth headers
|
|
58
|
+
* @returns A promise that resolves to the variable schema result
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const config: ApiVariablesConfig = {
|
|
63
|
+
* endpoint: {
|
|
64
|
+
* url: "/api/variables/{workflowId}/{nodeId}",
|
|
65
|
+
* method: "GET"
|
|
66
|
+
* },
|
|
67
|
+
* cacheTtl: 300000
|
|
68
|
+
* };
|
|
69
|
+
*
|
|
70
|
+
* const result = await fetchVariableSchema("wf-123", "node-456", config);
|
|
71
|
+
* if (result.success && result.schema) {
|
|
72
|
+
* // Use the fetched variable schema
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare function fetchVariableSchema(workflowId: string | undefined, nodeId: string, config: ApiVariablesConfig, authProvider?: AuthProvider): Promise<ApiVariableResult>;
|
|
77
|
+
/**
|
|
78
|
+
* Clears the variable schema cache.
|
|
79
|
+
* Can optionally clear only entries matching a specific pattern.
|
|
80
|
+
*
|
|
81
|
+
* @param pattern - Optional pattern to match cache keys (e.g., workflow ID or node ID)
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* // Clear all cache
|
|
86
|
+
* clearVariableCache();
|
|
87
|
+
*
|
|
88
|
+
* // Clear cache for a specific workflow
|
|
89
|
+
* clearVariableCache("wf-123");
|
|
90
|
+
*
|
|
91
|
+
* // Clear cache for a specific node
|
|
92
|
+
* clearVariableCache("node-456");
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export declare function clearVariableCache(pattern?: string): void;
|
|
96
|
+
/**
|
|
97
|
+
* Invalidates a specific variable cache entry.
|
|
98
|
+
*
|
|
99
|
+
* @param workflowId - The workflow ID (optional)
|
|
100
|
+
* @param nodeId - The node instance ID
|
|
101
|
+
*/
|
|
102
|
+
export declare function invalidateVariableCache(workflowId: string | undefined, nodeId: string): void;
|
|
103
|
+
/**
|
|
104
|
+
* Gets the current cache size (number of entries).
|
|
105
|
+
*
|
|
106
|
+
* @returns The number of cached variable schemas
|
|
107
|
+
*/
|
|
108
|
+
export declare function getVariableCacheSize(): number;
|
|
109
|
+
/**
|
|
110
|
+
* Gets all cache keys currently stored.
|
|
111
|
+
* Useful for debugging and monitoring.
|
|
112
|
+
*
|
|
113
|
+
* @returns Array of cache keys
|
|
114
|
+
*/
|
|
115
|
+
export declare function getVariableCacheKeys(): string[];
|
|
116
|
+
export {};
|