@d34dman/flowdrop 0.0.10 → 0.0.11
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 +20 -385
- package/dist/components/ConfigForm.svelte +299 -448
- package/dist/components/ConfigForm.svelte.d.ts +6 -29
- package/dist/components/PipelineStatus.svelte +5 -0
- package/dist/components/WorkflowEditor.svelte +23 -10
- package/dist/utils/performanceUtils.d.ts +30 -0
- package/dist/utils/performanceUtils.js +109 -0
- package/package.json +2 -2
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import WorkflowEditor from './WorkflowEditor.svelte';
|
|
11
11
|
import NodeSidebar from './NodeSidebar.svelte';
|
|
12
12
|
import ConfigSidebar from './ConfigSidebar.svelte';
|
|
13
|
+
import ConfigForm from './ConfigForm.svelte';
|
|
13
14
|
import Navbar from './Navbar.svelte';
|
|
14
15
|
import { api, setEndpointConfig } from '../services/api.js';
|
|
15
16
|
import type { NodeMetadata, Workflow, WorkflowNode, ConfigSchema } from '../types/index.js';
|
|
@@ -640,242 +641,29 @@
|
|
|
640
641
|
<!-- Configuration Form -->
|
|
641
642
|
<div class="flowdrop-config-sidebar__section">
|
|
642
643
|
<h3 class="flowdrop-config-sidebar__section-title">Configuration</h3>
|
|
643
|
-
<
|
|
644
|
-
{
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
const fieldConfig = field as any;
|
|
654
|
-
// Use existing value if available, otherwise use default
|
|
655
|
-
mergedConfig[key] =
|
|
656
|
-
nodeConfig[key] !== undefined ? nodeConfig[key] : fieldConfig.default;
|
|
657
|
-
});
|
|
658
|
-
}
|
|
659
|
-
return mergedConfig;
|
|
660
|
-
})()}
|
|
661
|
-
|
|
662
|
-
<!-- Render configuration fields based on schema -->
|
|
663
|
-
{#if configSchema.properties}
|
|
664
|
-
{#each Object.entries(configSchema.properties) as [key, field] (key)}
|
|
665
|
-
{@const fieldConfig = field as any}
|
|
666
|
-
{#if fieldConfig.format !== 'hidden'}
|
|
667
|
-
<div class="flowdrop-config-sidebar__field">
|
|
668
|
-
<label class="flowdrop-config-sidebar__field-label" for={key}>
|
|
669
|
-
{fieldConfig.title || fieldConfig.description || key}
|
|
670
|
-
</label>
|
|
671
|
-
{#if fieldConfig.enum && fieldConfig.multiple}
|
|
672
|
-
<!-- Checkboxes for enum with multiple selection -->
|
|
673
|
-
<div class="flowdrop-config-sidebar__checkbox-group">
|
|
674
|
-
{#each fieldConfig.enum as option (String(option))}
|
|
675
|
-
<label class="flowdrop-config-sidebar__checkbox-item">
|
|
676
|
-
<input
|
|
677
|
-
type="checkbox"
|
|
678
|
-
class="flowdrop-config-sidebar__checkbox"
|
|
679
|
-
value={String(option)}
|
|
680
|
-
checked={Array.isArray(configValues[key]) &&
|
|
681
|
-
configValues[key].includes(String(option))}
|
|
682
|
-
onchange={(e) => {
|
|
683
|
-
const checked = e.currentTarget.checked;
|
|
684
|
-
const currentValues = Array.isArray(configValues[key])
|
|
685
|
-
? [...configValues[key]]
|
|
686
|
-
: [];
|
|
687
|
-
if (checked) {
|
|
688
|
-
if (!currentValues.includes(String(option))) {
|
|
689
|
-
configValues[key] = [...currentValues, String(option)];
|
|
690
|
-
}
|
|
691
|
-
} else {
|
|
692
|
-
configValues[key] = currentValues.filter(
|
|
693
|
-
(v) => v !== String(option)
|
|
694
|
-
);
|
|
695
|
-
}
|
|
696
|
-
}}
|
|
697
|
-
/>
|
|
698
|
-
<span class="flowdrop-config-sidebar__checkbox-label">
|
|
699
|
-
{String(option)}
|
|
700
|
-
</span>
|
|
701
|
-
</label>
|
|
702
|
-
{/each}
|
|
703
|
-
</div>
|
|
704
|
-
{:else if fieldConfig.enum}
|
|
705
|
-
<!-- Select for enum with single selection -->
|
|
706
|
-
<select
|
|
707
|
-
id={key}
|
|
708
|
-
class="flowdrop-config-sidebar__select"
|
|
709
|
-
bind:value={configValues[key]}
|
|
710
|
-
>
|
|
711
|
-
{#each fieldConfig.enum as option (String(option))}
|
|
712
|
-
<option value={String(option)}>{String(option)}</option>
|
|
713
|
-
{/each}
|
|
714
|
-
</select>
|
|
715
|
-
{:else if fieldConfig.type === 'string' && fieldConfig.format === 'multiline'}
|
|
716
|
-
<!-- Textarea for multiline strings -->
|
|
717
|
-
<textarea
|
|
718
|
-
id={key}
|
|
719
|
-
class="flowdrop-config-sidebar__textarea"
|
|
720
|
-
bind:value={configValues[key]}
|
|
721
|
-
placeholder={String(fieldConfig.placeholder || '')}
|
|
722
|
-
rows="4"
|
|
723
|
-
></textarea>
|
|
724
|
-
{:else if fieldConfig.type === 'string'}
|
|
725
|
-
<input
|
|
726
|
-
id={key}
|
|
727
|
-
type="text"
|
|
728
|
-
class="flowdrop-config-sidebar__input"
|
|
729
|
-
bind:value={configValues[key]}
|
|
730
|
-
placeholder={String(fieldConfig.placeholder || '')}
|
|
731
|
-
/>
|
|
732
|
-
{:else if fieldConfig.type === 'number'}
|
|
733
|
-
<input
|
|
734
|
-
id={key}
|
|
735
|
-
type="number"
|
|
736
|
-
class="flowdrop-config-sidebar__input"
|
|
737
|
-
bind:value={configValues[key]}
|
|
738
|
-
placeholder={String(fieldConfig.placeholder || '')}
|
|
739
|
-
/>
|
|
740
|
-
{:else if fieldConfig.type === 'boolean'}
|
|
741
|
-
<input
|
|
742
|
-
id={key}
|
|
743
|
-
type="checkbox"
|
|
744
|
-
class="flowdrop-config-sidebar__checkbox"
|
|
745
|
-
checked={Boolean(configValues[key] || fieldConfig.default || false)}
|
|
746
|
-
onchange={(e) => {
|
|
747
|
-
configValues[key] = e.currentTarget.checked;
|
|
748
|
-
}}
|
|
749
|
-
/>
|
|
750
|
-
{:else if fieldConfig.type === 'select' || fieldConfig.options}
|
|
751
|
-
<select
|
|
752
|
-
id={key}
|
|
753
|
-
class="flowdrop-config-sidebar__select"
|
|
754
|
-
bind:value={configValues[key]}
|
|
755
|
-
>
|
|
756
|
-
{#if fieldConfig.options}
|
|
757
|
-
{#each fieldConfig.options as option (String(option.value))}
|
|
758
|
-
{@const optionConfig = option as any}
|
|
759
|
-
<option value={String(optionConfig.value)}
|
|
760
|
-
>{String(optionConfig.label)}</option
|
|
761
|
-
>
|
|
762
|
-
{/each}
|
|
763
|
-
{/if}
|
|
764
|
-
</select>
|
|
765
|
-
{:else}
|
|
766
|
-
<!-- Fallback for unknown field types -->
|
|
767
|
-
<input
|
|
768
|
-
id={key}
|
|
769
|
-
type="text"
|
|
770
|
-
class="flowdrop-config-sidebar__input"
|
|
771
|
-
bind:value={configValues[key]}
|
|
772
|
-
placeholder={String(fieldConfig.placeholder || '')}
|
|
773
|
-
/>
|
|
774
|
-
{/if}
|
|
775
|
-
{#if fieldConfig.description}
|
|
776
|
-
<p class="flowdrop-config-sidebar__field-description">
|
|
777
|
-
{String(fieldConfig.description)}
|
|
778
|
-
</p>
|
|
779
|
-
{/if}
|
|
780
|
-
</div>
|
|
781
|
-
{/if}
|
|
782
|
-
{/each}
|
|
783
|
-
{:else}
|
|
784
|
-
<!-- If no properties, show the raw schema for debugging -->
|
|
785
|
-
<div class="flowdrop-config-sidebar__debug">
|
|
786
|
-
<p><strong>Debug - Config Schema:</strong></p>
|
|
787
|
-
<pre>{JSON.stringify(configSchema, null, 2)}</pre>
|
|
788
|
-
</div>
|
|
789
|
-
{/if}
|
|
790
|
-
{:else}
|
|
791
|
-
<p class="flowdrop-config-sidebar__no-config">
|
|
792
|
-
No configuration options available for this node.
|
|
793
|
-
</p>
|
|
794
|
-
{/if}
|
|
795
|
-
</div>
|
|
796
|
-
</div>
|
|
797
|
-
</div>
|
|
798
|
-
|
|
799
|
-
<!-- Footer -->
|
|
800
|
-
<div class="flowdrop-config-sidebar__footer">
|
|
801
|
-
<button
|
|
802
|
-
class="flowdrop-config-sidebar__button flowdrop-config-sidebar__button--secondary"
|
|
803
|
-
onclick={closeConfigSidebar}
|
|
804
|
-
>
|
|
805
|
-
Cancel
|
|
806
|
-
</button>
|
|
807
|
-
<button
|
|
808
|
-
class="flowdrop-config-sidebar__button flowdrop-config-sidebar__button--primary"
|
|
809
|
-
onclick={() => {
|
|
810
|
-
// Get the current config values from the form
|
|
811
|
-
const currentNode = selectedNodeForConfig();
|
|
812
|
-
if (selectedNodeId && currentNode) {
|
|
813
|
-
// Collect the current form values
|
|
814
|
-
const form = document.querySelector('.flowdrop-config-sidebar__form');
|
|
815
|
-
const updatedConfig: Record<string, unknown> = {};
|
|
816
|
-
|
|
817
|
-
if (form) {
|
|
818
|
-
const inputs = form.querySelectorAll('input, select, textarea');
|
|
819
|
-
inputs.forEach((input: any) => {
|
|
820
|
-
if (input.id) {
|
|
821
|
-
if (input.type === 'checkbox') {
|
|
822
|
-
updatedConfig[input.id] = input.checked;
|
|
823
|
-
} else if (input.type === 'number') {
|
|
824
|
-
updatedConfig[input.id] = input.value
|
|
825
|
-
? Number(input.value)
|
|
826
|
-
: input.value;
|
|
827
|
-
} else if (input.type === 'hidden') {
|
|
828
|
-
// Parse hidden field values that might be JSON
|
|
829
|
-
try {
|
|
830
|
-
const parsed = JSON.parse(input.value);
|
|
831
|
-
updatedConfig[input.id] = parsed;
|
|
832
|
-
} catch {
|
|
833
|
-
// If not JSON, use raw value
|
|
834
|
-
updatedConfig[input.id] = input.value;
|
|
835
|
-
}
|
|
836
|
-
} else {
|
|
837
|
-
updatedConfig[input.id] = input.value;
|
|
838
|
-
}
|
|
644
|
+
<ConfigForm
|
|
645
|
+
node={selectedNodeForConfig()}
|
|
646
|
+
onSave={(updatedConfig) => {
|
|
647
|
+
const currentNode = selectedNodeForConfig();
|
|
648
|
+
if (selectedNodeId && currentNode) {
|
|
649
|
+
// Handle nodeType switching if nodeType is in the config
|
|
650
|
+
let nodeUpdates: Record<string, unknown> = {
|
|
651
|
+
data: {
|
|
652
|
+
...currentNode.data,
|
|
653
|
+
config: updatedConfig
|
|
839
654
|
}
|
|
840
|
-
}
|
|
841
|
-
}
|
|
655
|
+
};
|
|
842
656
|
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
currentNode.data.metadata?.configSchema?.properties
|
|
847
|
-
) {
|
|
848
|
-
Object.entries(currentNode.data.metadata.configSchema.properties).forEach(
|
|
849
|
-
([key, property]: [string, any]) => {
|
|
850
|
-
if (
|
|
851
|
-
property.format === 'hidden' &&
|
|
852
|
-
!(key in updatedConfig) &&
|
|
853
|
-
key in currentNode.data.config
|
|
854
|
-
) {
|
|
855
|
-
updatedConfig[key] = currentNode.data.config[key];
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
);
|
|
657
|
+
// NOTE: We do NOT change the node's type field anymore
|
|
658
|
+
// All nodes use 'universalNode' and UniversalNode handles internal switching
|
|
659
|
+
workflowActions.updateNode(selectedNodeId, nodeUpdates);
|
|
859
660
|
}
|
|
860
661
|
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
}
|
|
867
|
-
};
|
|
868
|
-
|
|
869
|
-
// NOTE: We do NOT change the node's type field anymore
|
|
870
|
-
// All nodes use 'universalNode' and UniversalNode handles internal switching
|
|
871
|
-
workflowActions.updateNode(selectedNodeId, nodeUpdates);
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
closeConfigSidebar();
|
|
875
|
-
}}
|
|
876
|
-
>
|
|
877
|
-
Save Changes
|
|
878
|
-
</button>
|
|
662
|
+
closeConfigSidebar();
|
|
663
|
+
}}
|
|
664
|
+
onCancel={closeConfigSidebar}
|
|
665
|
+
/>
|
|
666
|
+
</div>
|
|
879
667
|
</div>
|
|
880
668
|
</div>
|
|
881
669
|
</div>
|
|
@@ -1160,157 +948,4 @@
|
|
|
1160
948
|
color: #6b7280;
|
|
1161
949
|
line-height: 1.4;
|
|
1162
950
|
}
|
|
1163
|
-
|
|
1164
|
-
.flowdrop-config-sidebar__form {
|
|
1165
|
-
display: flex;
|
|
1166
|
-
flex-direction: column;
|
|
1167
|
-
gap: 1rem;
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
.flowdrop-config-sidebar__field {
|
|
1171
|
-
display: flex;
|
|
1172
|
-
flex-direction: column;
|
|
1173
|
-
gap: 0.5rem;
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
.flowdrop-config-sidebar__field-label {
|
|
1177
|
-
font-size: 0.875rem;
|
|
1178
|
-
font-weight: 500;
|
|
1179
|
-
color: #374151;
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
.flowdrop-config-sidebar__input,
|
|
1183
|
-
.flowdrop-config-sidebar__select {
|
|
1184
|
-
padding: 0.5rem;
|
|
1185
|
-
border: 1px solid #d1d5db;
|
|
1186
|
-
border-radius: 0.375rem;
|
|
1187
|
-
font-size: 0.875rem;
|
|
1188
|
-
transition:
|
|
1189
|
-
border-color 0.2s,
|
|
1190
|
-
box-shadow 0.2s;
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
.flowdrop-config-sidebar__input:focus,
|
|
1194
|
-
.flowdrop-config-sidebar__select:focus {
|
|
1195
|
-
outline: none;
|
|
1196
|
-
border-color: #3b82f6;
|
|
1197
|
-
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
.flowdrop-config-sidebar__checkbox-group {
|
|
1201
|
-
display: flex;
|
|
1202
|
-
flex-direction: column;
|
|
1203
|
-
gap: 0.5rem;
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
.flowdrop-config-sidebar__checkbox-item {
|
|
1207
|
-
display: flex;
|
|
1208
|
-
align-items: center;
|
|
1209
|
-
gap: 0.5rem;
|
|
1210
|
-
cursor: pointer;
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
.flowdrop-config-sidebar__checkbox {
|
|
1214
|
-
width: 1rem;
|
|
1215
|
-
height: 1rem;
|
|
1216
|
-
accent-color: #3b82f6;
|
|
1217
|
-
cursor: pointer;
|
|
1218
|
-
}
|
|
1219
|
-
|
|
1220
|
-
.flowdrop-config-sidebar__checkbox-label {
|
|
1221
|
-
font-size: 0.875rem;
|
|
1222
|
-
color: #374151;
|
|
1223
|
-
cursor: pointer;
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1226
|
-
.flowdrop-config-sidebar__textarea {
|
|
1227
|
-
width: 100%;
|
|
1228
|
-
padding: 0.5rem 0.75rem;
|
|
1229
|
-
border: 1px solid #d1d5db;
|
|
1230
|
-
border-radius: 0.375rem;
|
|
1231
|
-
font-size: 0.875rem;
|
|
1232
|
-
background-color: #ffffff;
|
|
1233
|
-
transition: all 0.2s ease-in-out;
|
|
1234
|
-
resize: vertical;
|
|
1235
|
-
min-height: 4rem;
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1238
|
-
.flowdrop-config-sidebar__textarea:focus {
|
|
1239
|
-
outline: none;
|
|
1240
|
-
border-color: #3b82f6;
|
|
1241
|
-
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
.flowdrop-config-sidebar__field-description {
|
|
1245
|
-
margin: 0;
|
|
1246
|
-
font-size: 0.75rem;
|
|
1247
|
-
color: #6b7280;
|
|
1248
|
-
line-height: 1.4;
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
|
-
.flowdrop-config-sidebar__no-config {
|
|
1252
|
-
text-align: center;
|
|
1253
|
-
color: #6b7280;
|
|
1254
|
-
font-style: italic;
|
|
1255
|
-
padding: 2rem 1rem;
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
.flowdrop-config-sidebar__footer {
|
|
1259
|
-
padding: 1rem;
|
|
1260
|
-
border-top: 1px solid #e5e7eb;
|
|
1261
|
-
background-color: #f9fafb;
|
|
1262
|
-
display: flex;
|
|
1263
|
-
gap: 0.75rem;
|
|
1264
|
-
justify-content: flex-end;
|
|
1265
|
-
height: 40px;
|
|
1266
|
-
align-items: center;
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
|
-
.flowdrop-config-sidebar__button {
|
|
1270
|
-
padding: 0.5rem 1rem;
|
|
1271
|
-
border-radius: 0.375rem;
|
|
1272
|
-
font-size: 0.875rem;
|
|
1273
|
-
font-weight: 500;
|
|
1274
|
-
cursor: pointer;
|
|
1275
|
-
transition: all 0.2s;
|
|
1276
|
-
border: 1px solid transparent;
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
.flowdrop-config-sidebar__button--secondary {
|
|
1280
|
-
background-color: #ffffff;
|
|
1281
|
-
border-color: #d1d5db;
|
|
1282
|
-
color: #374151;
|
|
1283
|
-
}
|
|
1284
|
-
|
|
1285
|
-
.flowdrop-config-sidebar__button--secondary:hover {
|
|
1286
|
-
background-color: #f9fafb;
|
|
1287
|
-
border-color: #9ca3af;
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
.flowdrop-config-sidebar__button--primary {
|
|
1291
|
-
background-color: #3b82f6;
|
|
1292
|
-
color: #ffffff;
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
.flowdrop-config-sidebar__button--primary:hover {
|
|
1296
|
-
background-color: #2563eb;
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
.flowdrop-config-sidebar__debug {
|
|
1300
|
-
background-color: #f3f4f6;
|
|
1301
|
-
border: 1px solid #d1d5db;
|
|
1302
|
-
border-radius: 0.375rem;
|
|
1303
|
-
padding: 1rem;
|
|
1304
|
-
margin: 1rem 0;
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
.flowdrop-config-sidebar__debug pre {
|
|
1308
|
-
background-color: #ffffff;
|
|
1309
|
-
border: 1px solid #e5e7eb;
|
|
1310
|
-
border-radius: 0.25rem;
|
|
1311
|
-
padding: 0.75rem;
|
|
1312
|
-
font-size: 0.75rem;
|
|
1313
|
-
overflow-x: auto;
|
|
1314
|
-
margin: 0.5rem 0 0 0;
|
|
1315
|
-
}
|
|
1316
951
|
</style>
|