@flowdrop/flowdrop 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ConfigForm.svelte +421 -0
- package/dist/components/NodeSidebar.svelte +29 -7
- package/dist/components/WorkflowEditor.svelte +16 -6
- package/dist/components/nodes/GatewayNode.svelte +8 -9
- package/dist/components/nodes/SimpleNode.svelte +80 -107
- package/dist/components/nodes/SquareNode.svelte +81 -107
- package/dist/components/nodes/TerminalNode.svelte +6 -7
- package/dist/components/nodes/WorkflowNode.svelte +54 -19
- package/dist/schemas/v1/workflow.schema.json +22 -107
- package/dist/stores/portCoordinateStore.svelte.js +25 -7
- package/dist/types/index.d.ts +17 -0
- package/dist/utils/portUtils.d.ts +24 -0
- package/dist/utils/portUtils.js +42 -0
- package/package.json +3 -3
|
@@ -25,9 +25,12 @@
|
|
|
25
25
|
WorkflowNode,
|
|
26
26
|
WorkflowEdge,
|
|
27
27
|
NodeUIExtensions,
|
|
28
|
+
NodePort,
|
|
29
|
+
DynamicPort,
|
|
28
30
|
ConfigEditOptions,
|
|
29
31
|
AuthProvider,
|
|
30
32
|
} from "../types/index.js";
|
|
33
|
+
import { dynamicPortToNodePort } from "../types/index.js";
|
|
31
34
|
import type { UISchemaElement } from "../types/uischema.js";
|
|
32
35
|
import {
|
|
33
36
|
FormField,
|
|
@@ -46,6 +49,11 @@
|
|
|
46
49
|
import { globalSaveWorkflow } from "../services/globalSave.js";
|
|
47
50
|
import { getAvailableVariables } from "../services/variableService.js";
|
|
48
51
|
import { logger } from "../utils/logger.js";
|
|
52
|
+
import {
|
|
53
|
+
getDataTypeColorToken,
|
|
54
|
+
getPortBackgroundColor,
|
|
55
|
+
} from "../utils/colors.js";
|
|
56
|
+
import { applyPortOrder } from "../utils/portUtils.js";
|
|
49
57
|
|
|
50
58
|
interface Props {
|
|
51
59
|
/** Optional workflow node (if provided, schema and values are derived from it) */
|
|
@@ -338,9 +346,118 @@
|
|
|
338
346
|
uiExtensionValues = {
|
|
339
347
|
hideUnconnectedHandles:
|
|
340
348
|
initialUIExtensions.hideUnconnectedHandles ?? false,
|
|
349
|
+
portOrder: initialUIExtensions.portOrder
|
|
350
|
+
? {
|
|
351
|
+
inputs: initialUIExtensions.portOrder.inputs
|
|
352
|
+
? [...initialUIExtensions.portOrder.inputs]
|
|
353
|
+
: undefined,
|
|
354
|
+
outputs: initialUIExtensions.portOrder.outputs
|
|
355
|
+
? [...initialUIExtensions.portOrder.outputs]
|
|
356
|
+
: undefined,
|
|
357
|
+
}
|
|
358
|
+
: undefined,
|
|
359
|
+
hiddenPorts: initialUIExtensions.hiddenPorts
|
|
360
|
+
? {
|
|
361
|
+
inputs: initialUIExtensions.hiddenPorts.inputs
|
|
362
|
+
? [...initialUIExtensions.hiddenPorts.inputs]
|
|
363
|
+
: undefined,
|
|
364
|
+
outputs: initialUIExtensions.hiddenPorts.outputs
|
|
365
|
+
? [...initialUIExtensions.hiddenPorts.outputs]
|
|
366
|
+
: undefined,
|
|
367
|
+
}
|
|
368
|
+
: undefined,
|
|
341
369
|
};
|
|
342
370
|
});
|
|
343
371
|
|
|
372
|
+
/**
|
|
373
|
+
* All input ports in current display order for the port management UI.
|
|
374
|
+
* Combines static metadata inputs + dynamic config inputs, sorted by portOrder.
|
|
375
|
+
*/
|
|
376
|
+
const allInputPortsForUI = $derived.by<NodePort[]>(() => {
|
|
377
|
+
if (!node) return [];
|
|
378
|
+
const staticInputs = node.data.metadata.inputs ?? [];
|
|
379
|
+
const dynInputs = (
|
|
380
|
+
(node.data.config?.dynamicInputs as DynamicPort[]) || []
|
|
381
|
+
).map((p) => dynamicPortToNodePort(p, "input"));
|
|
382
|
+
return applyPortOrder(
|
|
383
|
+
[...staticInputs, ...dynInputs],
|
|
384
|
+
uiExtensionValues.portOrder?.inputs,
|
|
385
|
+
);
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* All output ports in current display order for the port management UI.
|
|
390
|
+
* Combines static metadata outputs + dynamic config outputs, sorted by portOrder.
|
|
391
|
+
*/
|
|
392
|
+
const allOutputPortsForUI = $derived.by<NodePort[]>(() => {
|
|
393
|
+
if (!node) return [];
|
|
394
|
+
const staticOutputs = node.data.metadata.outputs ?? [];
|
|
395
|
+
const dynOutputs = (
|
|
396
|
+
(node.data.config?.dynamicOutputs as DynamicPort[]) || []
|
|
397
|
+
).map((p) => dynamicPortToNodePort(p, "output"));
|
|
398
|
+
return applyPortOrder(
|
|
399
|
+
[...staticOutputs, ...dynOutputs],
|
|
400
|
+
uiExtensionValues.portOrder?.outputs,
|
|
401
|
+
);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Move a port one position up or down in the display order.
|
|
406
|
+
*/
|
|
407
|
+
function movePort(
|
|
408
|
+
direction: "inputs" | "outputs",
|
|
409
|
+
portId: string,
|
|
410
|
+
delta: -1 | 1,
|
|
411
|
+
): void {
|
|
412
|
+
const list =
|
|
413
|
+
direction === "inputs" ? allInputPortsForUI : allOutputPortsForUI;
|
|
414
|
+
const idx = list.findIndex((p) => p.id === portId);
|
|
415
|
+
if (idx === -1) return;
|
|
416
|
+
const newIdx = idx + delta;
|
|
417
|
+
if (newIdx < 0 || newIdx >= list.length) return;
|
|
418
|
+
const newOrder = list.map((p) => p.id);
|
|
419
|
+
[newOrder[idx], newOrder[newIdx]] = [newOrder[newIdx], newOrder[idx]];
|
|
420
|
+
uiExtensionValues.portOrder = {
|
|
421
|
+
...uiExtensionValues.portOrder,
|
|
422
|
+
[direction]: newOrder,
|
|
423
|
+
};
|
|
424
|
+
handleFormBlur();
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Toggle manual visibility of a port. Required ports cannot be hidden.
|
|
429
|
+
*/
|
|
430
|
+
function togglePortHidden(
|
|
431
|
+
direction: "inputs" | "outputs",
|
|
432
|
+
portId: string,
|
|
433
|
+
): void {
|
|
434
|
+
const current = uiExtensionValues.hiddenPorts?.[direction] ?? [];
|
|
435
|
+
const isHidden = current.includes(portId);
|
|
436
|
+
const next = isHidden
|
|
437
|
+
? current.filter((id) => id !== portId)
|
|
438
|
+
: [...current, portId];
|
|
439
|
+
uiExtensionValues.hiddenPorts = {
|
|
440
|
+
...uiExtensionValues.hiddenPorts,
|
|
441
|
+
[direction]: next.length > 0 ? next : undefined,
|
|
442
|
+
};
|
|
443
|
+
handleFormBlur();
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Reset all port customizations (order + hidden) for a direction back to defaults.
|
|
448
|
+
*/
|
|
449
|
+
function resetPortCustomizations(direction: "inputs" | "outputs"): void {
|
|
450
|
+
const order = { ...uiExtensionValues.portOrder };
|
|
451
|
+
const hidden = { ...uiExtensionValues.hiddenPorts };
|
|
452
|
+
delete order[direction];
|
|
453
|
+
delete hidden[direction];
|
|
454
|
+
uiExtensionValues.portOrder =
|
|
455
|
+
Object.keys(order).length > 0 ? order : undefined;
|
|
456
|
+
uiExtensionValues.hiddenPorts =
|
|
457
|
+
Object.keys(hidden).length > 0 ? hidden : undefined;
|
|
458
|
+
handleFormBlur();
|
|
459
|
+
}
|
|
460
|
+
|
|
344
461
|
/**
|
|
345
462
|
* Check if a field is required based on schema
|
|
346
463
|
*/
|
|
@@ -708,6 +825,176 @@
|
|
|
708
825
|
}}
|
|
709
826
|
/>
|
|
710
827
|
</FormFieldWrapper>
|
|
828
|
+
|
|
829
|
+
<!-- Input Port Order & Visibility -->
|
|
830
|
+
{#if allInputPortsForUI.length > 0}
|
|
831
|
+
<div class="config-form__port-order">
|
|
832
|
+
<div class="config-form__port-order-header">
|
|
833
|
+
<span class="config-form__port-order-label">Input Ports</span>
|
|
834
|
+
{#if uiExtensionValues.portOrder?.inputs?.length || uiExtensionValues.hiddenPorts?.inputs?.length}
|
|
835
|
+
<button
|
|
836
|
+
type="button"
|
|
837
|
+
class="config-form__port-order-reset"
|
|
838
|
+
onclick={() => resetPortCustomizations("inputs")}
|
|
839
|
+
title="Reset to default order and visibility"
|
|
840
|
+
>
|
|
841
|
+
<Icon icon="heroicons:arrow-uturn-left" />
|
|
842
|
+
Reset
|
|
843
|
+
</button>
|
|
844
|
+
{/if}
|
|
845
|
+
</div>
|
|
846
|
+
<ul class="config-form__port-order-list">
|
|
847
|
+
{#each allInputPortsForUI as port, i (port.id)}
|
|
848
|
+
{@const isHidden =
|
|
849
|
+
uiExtensionValues.hiddenPorts?.inputs?.includes(port.id) ??
|
|
850
|
+
false}
|
|
851
|
+
{@const isRequired = port.required ?? false}
|
|
852
|
+
<li
|
|
853
|
+
class="config-form__port-order-item"
|
|
854
|
+
class:config-form__port-order-item--hidden={isHidden}
|
|
855
|
+
>
|
|
856
|
+
<span class="config-form__port-order-name">{port.name}</span
|
|
857
|
+
>
|
|
858
|
+
<span
|
|
859
|
+
class="config-form__port-order-badge"
|
|
860
|
+
style="background-color:{getPortBackgroundColor(
|
|
861
|
+
port.dataType,
|
|
862
|
+
15,
|
|
863
|
+
)};color:{getDataTypeColorToken(
|
|
864
|
+
port.dataType,
|
|
865
|
+
)};border:1px solid {getPortBackgroundColor(
|
|
866
|
+
port.dataType,
|
|
867
|
+
30,
|
|
868
|
+
)}"
|
|
869
|
+
>
|
|
870
|
+
{port.dataType}
|
|
871
|
+
</span>
|
|
872
|
+
<div class="config-form__port-order-actions">
|
|
873
|
+
<button
|
|
874
|
+
type="button"
|
|
875
|
+
disabled={isRequired}
|
|
876
|
+
title={isRequired
|
|
877
|
+
? "Required ports cannot be hidden"
|
|
878
|
+
: isHidden
|
|
879
|
+
? "Show port"
|
|
880
|
+
: "Hide port"}
|
|
881
|
+
class:active={isHidden}
|
|
882
|
+
onclick={() => togglePortHidden("inputs", port.id)}
|
|
883
|
+
>
|
|
884
|
+
<Icon
|
|
885
|
+
icon={isHidden
|
|
886
|
+
? "heroicons:eye-slash"
|
|
887
|
+
: "heroicons:eye"}
|
|
888
|
+
/>
|
|
889
|
+
</button>
|
|
890
|
+
<button
|
|
891
|
+
type="button"
|
|
892
|
+
disabled={i === 0 || allInputPortsForUI.length === 1}
|
|
893
|
+
onclick={() => movePort("inputs", port.id, -1)}
|
|
894
|
+
title="Move up"
|
|
895
|
+
>
|
|
896
|
+
<Icon icon="heroicons:chevron-up" />
|
|
897
|
+
</button>
|
|
898
|
+
<button
|
|
899
|
+
type="button"
|
|
900
|
+
disabled={i === allInputPortsForUI.length - 1 ||
|
|
901
|
+
allInputPortsForUI.length === 1}
|
|
902
|
+
onclick={() => movePort("inputs", port.id, 1)}
|
|
903
|
+
title="Move down"
|
|
904
|
+
>
|
|
905
|
+
<Icon icon="heroicons:chevron-down" />
|
|
906
|
+
</button>
|
|
907
|
+
</div>
|
|
908
|
+
</li>
|
|
909
|
+
{/each}
|
|
910
|
+
</ul>
|
|
911
|
+
</div>
|
|
912
|
+
{/if}
|
|
913
|
+
|
|
914
|
+
<!-- Output Port Order & Visibility -->
|
|
915
|
+
{#if allOutputPortsForUI.length > 0}
|
|
916
|
+
<div class="config-form__port-order">
|
|
917
|
+
<div class="config-form__port-order-header">
|
|
918
|
+
<span class="config-form__port-order-label">Output Ports</span>
|
|
919
|
+
{#if uiExtensionValues.portOrder?.outputs?.length || uiExtensionValues.hiddenPorts?.outputs?.length}
|
|
920
|
+
<button
|
|
921
|
+
type="button"
|
|
922
|
+
class="config-form__port-order-reset"
|
|
923
|
+
onclick={() => resetPortCustomizations("outputs")}
|
|
924
|
+
title="Reset to default order and visibility"
|
|
925
|
+
>
|
|
926
|
+
<Icon icon="heroicons:arrow-uturn-left" />
|
|
927
|
+
Reset
|
|
928
|
+
</button>
|
|
929
|
+
{/if}
|
|
930
|
+
</div>
|
|
931
|
+
<ul class="config-form__port-order-list">
|
|
932
|
+
{#each allOutputPortsForUI as port, i (port.id)}
|
|
933
|
+
{@const isHidden =
|
|
934
|
+
uiExtensionValues.hiddenPorts?.outputs?.includes(port.id) ??
|
|
935
|
+
false}
|
|
936
|
+
{@const isRequired = port.required ?? false}
|
|
937
|
+
<li
|
|
938
|
+
class="config-form__port-order-item"
|
|
939
|
+
class:config-form__port-order-item--hidden={isHidden}
|
|
940
|
+
>
|
|
941
|
+
<span class="config-form__port-order-name">{port.name}</span
|
|
942
|
+
>
|
|
943
|
+
<span
|
|
944
|
+
class="config-form__port-order-badge"
|
|
945
|
+
style="background-color:{getPortBackgroundColor(
|
|
946
|
+
port.dataType,
|
|
947
|
+
15,
|
|
948
|
+
)};color:{getDataTypeColorToken(
|
|
949
|
+
port.dataType,
|
|
950
|
+
)};border:1px solid {getPortBackgroundColor(
|
|
951
|
+
port.dataType,
|
|
952
|
+
30,
|
|
953
|
+
)}"
|
|
954
|
+
>
|
|
955
|
+
{port.dataType}
|
|
956
|
+
</span>
|
|
957
|
+
<div class="config-form__port-order-actions">
|
|
958
|
+
<button
|
|
959
|
+
type="button"
|
|
960
|
+
disabled={isRequired}
|
|
961
|
+
title={isRequired
|
|
962
|
+
? "Required ports cannot be hidden"
|
|
963
|
+
: isHidden
|
|
964
|
+
? "Show port"
|
|
965
|
+
: "Hide port"}
|
|
966
|
+
class:active={isHidden}
|
|
967
|
+
onclick={() => togglePortHidden("outputs", port.id)}
|
|
968
|
+
>
|
|
969
|
+
<Icon
|
|
970
|
+
icon={isHidden
|
|
971
|
+
? "heroicons:eye-slash"
|
|
972
|
+
: "heroicons:eye"}
|
|
973
|
+
/>
|
|
974
|
+
</button>
|
|
975
|
+
<button
|
|
976
|
+
type="button"
|
|
977
|
+
disabled={i === 0 || allOutputPortsForUI.length === 1}
|
|
978
|
+
onclick={() => movePort("outputs", port.id, -1)}
|
|
979
|
+
title="Move up"
|
|
980
|
+
>
|
|
981
|
+
<Icon icon="heroicons:chevron-up" />
|
|
982
|
+
</button>
|
|
983
|
+
<button
|
|
984
|
+
type="button"
|
|
985
|
+
disabled={i === allOutputPortsForUI.length - 1 ||
|
|
986
|
+
allOutputPortsForUI.length === 1}
|
|
987
|
+
onclick={() => movePort("outputs", port.id, 1)}
|
|
988
|
+
title="Move down"
|
|
989
|
+
>
|
|
990
|
+
<Icon icon="heroicons:chevron-down" />
|
|
991
|
+
</button>
|
|
992
|
+
</div>
|
|
993
|
+
</li>
|
|
994
|
+
{/each}
|
|
995
|
+
</ul>
|
|
996
|
+
</div>
|
|
997
|
+
{/if}
|
|
711
998
|
</div>
|
|
712
999
|
</div>
|
|
713
1000
|
{/if}
|
|
@@ -928,6 +1215,140 @@
|
|
|
928
1215
|
gap: var(--fd-space-xl);
|
|
929
1216
|
}
|
|
930
1217
|
|
|
1218
|
+
/* ============================================
|
|
1219
|
+
PORT ORDER & VISIBILITY
|
|
1220
|
+
============================================ */
|
|
1221
|
+
|
|
1222
|
+
.config-form__port-order {
|
|
1223
|
+
border-top: 1px solid var(--fd-border-muted);
|
|
1224
|
+
padding-top: var(--fd-space-md);
|
|
1225
|
+
margin-top: calc(var(--fd-space-xl) * -0.25);
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
.config-form__port-order-header {
|
|
1229
|
+
display: flex;
|
|
1230
|
+
align-items: center;
|
|
1231
|
+
justify-content: space-between;
|
|
1232
|
+
margin-bottom: var(--fd-space-xs);
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
.config-form__port-order-label {
|
|
1236
|
+
font-size: var(--fd-text-xs);
|
|
1237
|
+
font-weight: 600;
|
|
1238
|
+
color: var(--fd-muted-foreground);
|
|
1239
|
+
text-transform: uppercase;
|
|
1240
|
+
letter-spacing: 0.05em;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
.config-form__port-order-reset {
|
|
1244
|
+
background: none;
|
|
1245
|
+
border: none;
|
|
1246
|
+
font-size: var(--fd-text-xs);
|
|
1247
|
+
color: var(--fd-muted-foreground);
|
|
1248
|
+
cursor: pointer;
|
|
1249
|
+
display: inline-flex;
|
|
1250
|
+
align-items: center;
|
|
1251
|
+
gap: var(--fd-space-3xs);
|
|
1252
|
+
padding: 0;
|
|
1253
|
+
transition: color var(--fd-transition-fast);
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
.config-form__port-order-reset:hover {
|
|
1257
|
+
color: var(--fd-foreground);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
.config-form__port-order-reset :global(svg) {
|
|
1261
|
+
width: 0.75rem;
|
|
1262
|
+
height: 0.75rem;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
.config-form__port-order-list {
|
|
1266
|
+
list-style: none;
|
|
1267
|
+
margin: 0;
|
|
1268
|
+
padding: 0;
|
|
1269
|
+
display: flex;
|
|
1270
|
+
flex-direction: column;
|
|
1271
|
+
gap: var(--fd-space-3xs);
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
.config-form__port-order-item {
|
|
1275
|
+
display: flex;
|
|
1276
|
+
align-items: center;
|
|
1277
|
+
gap: var(--fd-space-xs);
|
|
1278
|
+
padding: var(--fd-space-3xs) var(--fd-space-xs);
|
|
1279
|
+
background: var(--fd-muted);
|
|
1280
|
+
border-radius: var(--fd-radius-sm);
|
|
1281
|
+
border: 1px solid var(--fd-border-muted);
|
|
1282
|
+
transition: opacity var(--fd-transition-fast);
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
.config-form__port-order-item--hidden {
|
|
1286
|
+
opacity: 0.4;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
.config-form__port-order-name {
|
|
1290
|
+
flex: 1;
|
|
1291
|
+
font-size: var(--fd-text-xs);
|
|
1292
|
+
font-weight: 500;
|
|
1293
|
+
color: var(--fd-foreground);
|
|
1294
|
+
min-width: 0;
|
|
1295
|
+
overflow: hidden;
|
|
1296
|
+
text-overflow: ellipsis;
|
|
1297
|
+
white-space: nowrap;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
.config-form__port-order-badge {
|
|
1301
|
+
padding: 0.125rem var(--fd-space-3xs);
|
|
1302
|
+
border-radius: var(--fd-radius-sm);
|
|
1303
|
+
font-size: 0.625rem;
|
|
1304
|
+
font-weight: 500;
|
|
1305
|
+
text-transform: uppercase;
|
|
1306
|
+
letter-spacing: 0.04em;
|
|
1307
|
+
flex-shrink: 0;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
.config-form__port-order-actions {
|
|
1311
|
+
display: flex;
|
|
1312
|
+
gap: var(--fd-space-3xs);
|
|
1313
|
+
flex-shrink: 0;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
.config-form__port-order-actions button {
|
|
1317
|
+
width: 1.25rem;
|
|
1318
|
+
height: 1.25rem;
|
|
1319
|
+
display: flex;
|
|
1320
|
+
align-items: center;
|
|
1321
|
+
justify-content: center;
|
|
1322
|
+
background: var(--fd-card);
|
|
1323
|
+
border: 1px solid var(--fd-border);
|
|
1324
|
+
border-radius: var(--fd-radius-sm);
|
|
1325
|
+
color: var(--fd-muted-foreground);
|
|
1326
|
+
cursor: pointer;
|
|
1327
|
+
padding: 0;
|
|
1328
|
+
transition: all var(--fd-transition-fast);
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
.config-form__port-order-actions button:hover:not(:disabled) {
|
|
1332
|
+
background: var(--fd-backdrop);
|
|
1333
|
+
color: var(--fd-foreground);
|
|
1334
|
+
border-color: var(--fd-border-strong);
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
.config-form__port-order-actions button:disabled {
|
|
1338
|
+
opacity: 0.3;
|
|
1339
|
+
cursor: not-allowed;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
.config-form__port-order-actions button.active {
|
|
1343
|
+
color: var(--fd-foreground);
|
|
1344
|
+
border-color: var(--fd-border-strong);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
.config-form__port-order-actions button :global(svg) {
|
|
1348
|
+
width: 0.75rem;
|
|
1349
|
+
height: 0.75rem;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
931
1352
|
/* ============================================
|
|
932
1353
|
DEBUG SECTION
|
|
933
1354
|
============================================ */
|
|
@@ -276,10 +276,22 @@
|
|
|
276
276
|
</div>
|
|
277
277
|
{:else}
|
|
278
278
|
<div class="flowdrop-hero__icon">
|
|
279
|
-
<svg
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
279
|
+
<svg
|
|
280
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
281
|
+
width="1em"
|
|
282
|
+
height="1em"
|
|
283
|
+
viewBox="0 0 24 24"
|
|
284
|
+
fill="none"
|
|
285
|
+
stroke="currentColor"
|
|
286
|
+
stroke-width="1.5"
|
|
287
|
+
stroke-linecap="round"
|
|
288
|
+
stroke-linejoin="round"
|
|
289
|
+
>
|
|
290
|
+
<path
|
|
291
|
+
d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"
|
|
292
|
+
/>
|
|
293
|
+
<polyline points="3.27 6.96 12 12.01 20.73 6.96" />
|
|
294
|
+
<line x1="12" y1="22.08" x2="12" y2="12" />
|
|
283
295
|
</svg>
|
|
284
296
|
</div>
|
|
285
297
|
<h3 class="flowdrop-hero__title">No node types available</h3>
|
|
@@ -299,9 +311,19 @@
|
|
|
299
311
|
<div class="flowdrop-hero">
|
|
300
312
|
<div class="flowdrop-hero__content">
|
|
301
313
|
<div class="flowdrop-hero__icon">
|
|
302
|
-
<svg
|
|
303
|
-
|
|
304
|
-
|
|
314
|
+
<svg
|
|
315
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
316
|
+
width="1em"
|
|
317
|
+
height="1em"
|
|
318
|
+
viewBox="0 0 24 24"
|
|
319
|
+
fill="none"
|
|
320
|
+
stroke="currentColor"
|
|
321
|
+
stroke-width="1.5"
|
|
322
|
+
stroke-linecap="round"
|
|
323
|
+
stroke-linejoin="round"
|
|
324
|
+
>
|
|
325
|
+
<circle cx="11" cy="11" r="8" />
|
|
326
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
305
327
|
</svg>
|
|
306
328
|
</div>
|
|
307
329
|
<h3 class="flowdrop-hero__title">No components found</h3>
|
|
@@ -859,12 +859,22 @@
|
|
|
859
859
|
description="Use the sidebar to add components to your workflow"
|
|
860
860
|
>
|
|
861
861
|
{#snippet icon()}
|
|
862
|
-
<svg
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
862
|
+
<svg
|
|
863
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
864
|
+
width="1em"
|
|
865
|
+
height="1em"
|
|
866
|
+
viewBox="0 0 24 24"
|
|
867
|
+
fill="none"
|
|
868
|
+
stroke="currentColor"
|
|
869
|
+
stroke-width="1.5"
|
|
870
|
+
stroke-linecap="round"
|
|
871
|
+
stroke-linejoin="round"
|
|
872
|
+
>
|
|
873
|
+
<circle cx="18" cy="5" r="3" />
|
|
874
|
+
<circle cx="6" cy="12" r="3" />
|
|
875
|
+
<circle cx="18" cy="19" r="3" />
|
|
876
|
+
<line x1="8.59" y1="13.51" x2="15.42" y2="17.49" />
|
|
877
|
+
<line x1="15.41" y1="6.51" x2="8.59" y2="10.49" />
|
|
868
878
|
</svg>
|
|
869
879
|
{/snippet}
|
|
870
880
|
</CanvasBanner>
|
|
@@ -57,12 +57,11 @@
|
|
|
57
57
|
* Get the hideUnconnectedHandles setting from extensions
|
|
58
58
|
* Merges node type defaults with instance overrides
|
|
59
59
|
*/
|
|
60
|
-
const hideUnconnectedHandles = $derived(
|
|
61
|
-
|
|
62
|
-
props.data.metadata?.extensions?.ui?.hideUnconnectedHandles ??
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
});
|
|
60
|
+
const hideUnconnectedHandles = $derived(
|
|
61
|
+
props.data.extensions?.ui?.hideUnconnectedHandles ??
|
|
62
|
+
props.data.metadata?.extensions?.ui?.hideUnconnectedHandles ??
|
|
63
|
+
false,
|
|
64
|
+
);
|
|
66
65
|
|
|
67
66
|
/**
|
|
68
67
|
* Check if a port should be visible based on connection state and settings
|
|
@@ -72,7 +71,7 @@
|
|
|
72
71
|
*/
|
|
73
72
|
function isPortVisible(port: NodePort, type: "input" | "output"): boolean {
|
|
74
73
|
// Always show if hideUnconnectedHandles is disabled
|
|
75
|
-
if (!hideUnconnectedHandles
|
|
74
|
+
if (!hideUnconnectedHandles) {
|
|
76
75
|
return true;
|
|
77
76
|
}
|
|
78
77
|
|
|
@@ -100,7 +99,7 @@
|
|
|
100
99
|
*/
|
|
101
100
|
function isBranchVisible(branchName: string): boolean {
|
|
102
101
|
// Always show if hideUnconnectedHandles is disabled
|
|
103
|
-
if (!hideUnconnectedHandles
|
|
102
|
+
if (!hideUnconnectedHandles) {
|
|
104
103
|
return true;
|
|
105
104
|
}
|
|
106
105
|
|
|
@@ -211,7 +210,7 @@
|
|
|
211
210
|
{#if visibleInputPorts.length > 0}
|
|
212
211
|
<div class="flowdrop-workflow-node__ports">
|
|
213
212
|
<div class="flowdrop-workflow-node__ports-list">
|
|
214
|
-
{#each visibleInputPorts as port
|
|
213
|
+
{#each visibleInputPorts as port (port.id)}
|
|
215
214
|
<div class="flowdrop-workflow-node__port">
|
|
216
215
|
<!-- Input Handle: centered in row, at node edge (ports have no padding) -->
|
|
217
216
|
<Handle
|