@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.
@@ -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
- <div class="flowdrop-config-sidebar__form">
644
- {#if selectedNodeForConfig().data.metadata?.configSchema}
645
- <!-- Debug: Log the config schema -->
646
- {@const configSchema = selectedNodeForConfig().data.metadata.configSchema}
647
- {@const nodeConfig = selectedNodeForConfig().data.config || {}}
648
- {@const configValues = (() => {
649
- // Create a config object that merges defaults with existing values
650
- const mergedConfig = {};
651
- if (configSchema.properties) {
652
- Object.entries(configSchema.properties).forEach(([key, field]) => {
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
- // Preserve hidden field values from original config if not collected from form
844
- if (
845
- currentNode.data.config &&
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
- // Handle nodeType switching if nodeType is in the config
862
- let nodeUpdates: Record<string, unknown> = {
863
- data: {
864
- ...currentNode.data,
865
- config: updatedConfig
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>