Flowfile 0.4.1__py3-none-any.whl → 0.5.3__py3-none-any.whl

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.
Files changed (332) hide show
  1. build_backends/main.py +25 -22
  2. build_backends/main_prd.py +10 -19
  3. flowfile/__init__.py +179 -73
  4. flowfile/__main__.py +10 -7
  5. flowfile/api.py +52 -59
  6. flowfile/web/__init__.py +14 -9
  7. flowfile/web/static/assets/AdminView-49392a9a.js +713 -0
  8. flowfile/web/static/assets/AdminView-f53bad23.css +129 -0
  9. flowfile/web/static/assets/CloudConnectionView-36bcd6df.css +72 -0
  10. flowfile/web/static/assets/{CloudConnectionManager-d3248f8d.js → CloudConnectionView-f13f202b.js} +11 -11
  11. flowfile/web/static/assets/{CloudStorageReader-d65bf041.js → CloudStorageReader-0023d4a5.js} +10 -8
  12. flowfile/web/static/assets/{CloudStorageReader-29d14fcc.css → CloudStorageReader-24c54524.css} +27 -27
  13. flowfile/web/static/assets/{CloudStorageWriter-b0ee067f.css → CloudStorageWriter-60547855.css} +26 -26
  14. flowfile/web/static/assets/{CloudStorageWriter-e83be3ed.js → CloudStorageWriter-8e781e11.js} +10 -8
  15. flowfile/web/static/assets/{ColumnSelector-47996a16.css → ColumnSelector-371637fb.css} +2 -2
  16. flowfile/web/static/assets/{ColumnSelector-cce661cf.js → ColumnSelector-8ad68ea9.js} +3 -5
  17. flowfile/web/static/assets/{ContextMenu-c13f91d0.css → ContextMenu-26d4dd27.css} +6 -6
  18. flowfile/web/static/assets/{ContextMenu-11a4652a.js → ContextMenu-31ee57f0.js} +3 -3
  19. flowfile/web/static/assets/{ContextMenu-160afb08.js → ContextMenu-69a74055.js} +3 -3
  20. flowfile/web/static/assets/{ContextMenu-cf18d2cc.js → ContextMenu-8e2051c6.js} +3 -3
  21. flowfile/web/static/assets/{ContextMenu-4c74eef1.css → ContextMenu-8ec1729e.css} +6 -6
  22. flowfile/web/static/assets/{ContextMenu-63cfa99b.css → ContextMenu-9b310c60.css} +6 -6
  23. flowfile/web/static/assets/{CrossJoin-d395d38c.js → CrossJoin-03df6938.js} +12 -10
  24. flowfile/web/static/assets/{CrossJoin-1119d18e.css → CrossJoin-71b4cc10.css} +20 -20
  25. flowfile/web/static/assets/CustomNode-59e99a86.css +32 -0
  26. flowfile/web/static/assets/{CustomNode-b812dc0b.js → CustomNode-8479239b.js} +36 -24
  27. flowfile/web/static/assets/{DatabaseConnectionSettings-7000bf2c.js → DatabaseConnectionSettings-869e3efd.js} +5 -4
  28. flowfile/web/static/assets/{DatabaseConnectionSettings-0c04b2e5.css → DatabaseConnectionSettings-e91df89a.css} +13 -13
  29. flowfile/web/static/assets/{DatabaseReader-ae61773c.css → DatabaseReader-36898a00.css} +24 -24
  30. flowfile/web/static/assets/{DatabaseReader-4f035d0c.js → DatabaseReader-c58b9552.js} +25 -15
  31. flowfile/web/static/assets/DatabaseView-6655afd6.css +57 -0
  32. flowfile/web/static/assets/{DatabaseManager-9662ec5b.js → DatabaseView-d26a9140.js} +11 -11
  33. flowfile/web/static/assets/{DatabaseWriter-2f570e53.css → DatabaseWriter-217a99f1.css} +19 -19
  34. flowfile/web/static/assets/{DatabaseWriter-f65dcd54.js → DatabaseWriter-4d05ddc7.js} +17 -10
  35. flowfile/web/static/assets/{designer-e3c150ec.css → DesignerView-a6d0ee84.css} +629 -538
  36. flowfile/web/static/assets/{designer-f3656d8c.js → DesignerView-e6f5c0e8.js} +1214 -3209
  37. flowfile/web/static/assets/{documentation-52b241e7.js → DocumentationView-2e78ef1b.js} +5 -5
  38. flowfile/web/static/assets/{documentation-12216a74.css → DocumentationView-fd46c656.css} +7 -7
  39. flowfile/web/static/assets/{ExploreData-2d0cf4db.css → ExploreData-10c5acc8.css} +13 -12
  40. flowfile/web/static/assets/{ExploreData-94c43dfc.js → ExploreData-7b54caca.js} +18 -9
  41. flowfile/web/static/assets/{ExternalSource-ac04b3cc.js → ExternalSource-3fa399b2.js} +9 -7
  42. flowfile/web/static/assets/{ExternalSource-e37b6275.css → ExternalSource-47ab05a3.css} +17 -17
  43. flowfile/web/static/assets/Filter-7494ea97.css +48 -0
  44. flowfile/web/static/assets/Filter-8cbbdbf3.js +287 -0
  45. flowfile/web/static/assets/{Formula-bb96803d.css → Formula-53d58c43.css} +7 -7
  46. flowfile/web/static/assets/{Formula-71472193.js → Formula-aac42b1e.js} +13 -11
  47. flowfile/web/static/assets/{FuzzyMatch-1010f966.css → FuzzyMatch-ad6361d6.css} +68 -69
  48. flowfile/web/static/assets/{FuzzyMatch-b317f631.js → FuzzyMatch-cd9bbfca.js} +12 -10
  49. flowfile/web/static/assets/{Pivot-cf333e3d.css → GraphSolver-c24dec17.css} +5 -5
  50. flowfile/web/static/assets/{GraphSolver-754a234f.js → GraphSolver-c7e6780e.js} +13 -11
  51. flowfile/web/static/assets/{GroupBy-6c6f9802.js → GroupBy-93c5d22b.js} +9 -7
  52. flowfile/web/static/assets/{GroupBy-b9505323.css → GroupBy-be7ac0bf.css} +10 -10
  53. flowfile/web/static/assets/{Join-fd79b451.css → Join-28b5e18f.css} +22 -22
  54. flowfile/web/static/assets/{Join-a1b800be.js → Join-a19b2de2.js} +13 -11
  55. flowfile/web/static/assets/LoginView-0df4ed0a.js +134 -0
  56. flowfile/web/static/assets/LoginView-d325d632.css +172 -0
  57. flowfile/web/static/assets/ManualInput-3702e677.css +293 -0
  58. flowfile/web/static/assets/{ManualInput-a9640276.js → ManualInput-8d3374b2.js} +170 -116
  59. flowfile/web/static/assets/{MultiSelect-97213888.js → MultiSelect-ad1b6243.js} +2 -2
  60. flowfile/web/static/assets/{MultiSelect.vue_vue_type_script_setup_true_lang-6ffe088a.js → MultiSelect.vue_vue_type_script_setup_true_lang-e278950d.js} +1 -1
  61. flowfile/web/static/assets/NodeDesigner-40b647c9.js +2610 -0
  62. flowfile/web/static/assets/NodeDesigner-5f53be3f.css +1429 -0
  63. flowfile/web/static/assets/{NumericInput-e638088a.js → NumericInput-7100234c.js} +2 -2
  64. flowfile/web/static/assets/{NumericInput.vue_vue_type_script_setup_true_lang-90eb2cba.js → NumericInput.vue_vue_type_script_setup_true_lang-5130219f.js} +5 -2
  65. flowfile/web/static/assets/{Output-ddc9079f.css → Output-35e97000.css} +6 -6
  66. flowfile/web/static/assets/{Output-76750610.js → Output-f5efd2aa.js} +60 -38
  67. flowfile/web/static/assets/{GraphSolver-f0cb7bfb.css → Pivot-0eda81b4.css} +5 -5
  68. flowfile/web/static/assets/{Pivot-7814803f.js → Pivot-d981d23c.js} +11 -9
  69. flowfile/web/static/assets/PivotValidation-0e905b1a.css +13 -0
  70. flowfile/web/static/assets/{PivotValidation-f92137d2.js → PivotValidation-39386e95.js} +3 -3
  71. flowfile/web/static/assets/PivotValidation-41b57ad6.css +13 -0
  72. flowfile/web/static/assets/{PivotValidation-76dd431a.js → PivotValidation-63de1f73.js} +3 -3
  73. flowfile/web/static/assets/{PolarsCode-650322d1.css → PolarsCode-2b1f1f23.css} +4 -4
  74. flowfile/web/static/assets/{PolarsCode-889c3008.js → PolarsCode-f9d69217.js} +18 -9
  75. flowfile/web/static/assets/PopOver-b22f049e.js +939 -0
  76. flowfile/web/static/assets/PopOver-d96599db.css +33 -0
  77. flowfile/web/static/assets/{Read-6b17491f.css → Read-36e7bd51.css} +12 -12
  78. flowfile/web/static/assets/{Read-637b72a7.js → Read-aec2e377.js} +83 -105
  79. flowfile/web/static/assets/{RecordCount-2b050c41.js → RecordCount-78ed6845.js} +6 -4
  80. flowfile/web/static/assets/{RecordId-81df7784.js → RecordId-2156e890.js} +8 -6
  81. flowfile/web/static/assets/{SQLQueryComponent-36cef432.css → SQLQueryComponent-1c2f26b4.css} +5 -5
  82. flowfile/web/static/assets/{SQLQueryComponent-88dcfe53.js → SQLQueryComponent-48c72f5b.js} +3 -3
  83. flowfile/web/static/assets/{Sample-258ad2a9.js → Sample-1352ca74.js} +6 -4
  84. flowfile/web/static/assets/SecretSelector-22b5ff89.js +113 -0
  85. flowfile/web/static/assets/SecretSelector-6329f743.css +43 -0
  86. flowfile/web/static/assets/{SecretManager-2a2cb7e2.js → SecretsView-17df66ee.js} +35 -36
  87. flowfile/web/static/assets/SecretsView-aa291340.css +38 -0
  88. flowfile/web/static/assets/{Select-850215fd.js → Select-0aee4c54.js} +9 -7
  89. flowfile/web/static/assets/{SettingsSection-55bae608.js → SettingsSection-0784e157.js} +3 -3
  90. flowfile/web/static/assets/{SettingsSection-71e6b7e3.css → SettingsSection-07fbbc39.css} +4 -4
  91. flowfile/web/static/assets/{SettingsSection-5c696bee.css → SettingsSection-26fe48d4.css} +4 -4
  92. flowfile/web/static/assets/{SettingsSection-2e4d03c4.css → SettingsSection-8f980839.css} +4 -4
  93. flowfile/web/static/assets/{SettingsSection-0e8d9123.js → SettingsSection-cd341bb6.js} +3 -3
  94. flowfile/web/static/assets/{SettingsSection-29b4fa6b.js → SettingsSection-f2002a6d.js} +3 -3
  95. flowfile/web/static/assets/{SingleSelect-bebd408b.js → SingleSelect-460cc0ea.js} +2 -2
  96. flowfile/web/static/assets/{SingleSelect.vue_vue_type_script_setup_true_lang-6093741c.js → SingleSelect.vue_vue_type_script_setup_true_lang-30741bb2.js} +1 -1
  97. flowfile/web/static/assets/{SliderInput-6a05ab61.js → SliderInput-5d926864.js} +7 -4
  98. flowfile/web/static/assets/SliderInput-f2e4f23c.css +4 -0
  99. flowfile/web/static/assets/{Sort-10ab48ed.js → Sort-3cdc971b.js} +9 -7
  100. flowfile/web/static/assets/{Unique-f9fb0809.css → Sort-8a871341.css} +10 -10
  101. flowfile/web/static/assets/{TextInput-df9d6259.js → TextInput-a2d0bfbd.js} +2 -2
  102. flowfile/web/static/assets/{TextInput.vue_vue_type_script_setup_true_lang-000e1178.js → TextInput.vue_vue_type_script_setup_true_lang-abad1ca2.js} +5 -2
  103. flowfile/web/static/assets/{TextToRows-5d2c1190.css → TextToRows-12afb4f4.css} +10 -10
  104. flowfile/web/static/assets/{TextToRows-6c2d93d8.js → TextToRows-918945f7.js} +11 -10
  105. flowfile/web/static/assets/{ToggleSwitch-0ff7ac52.js → ToggleSwitch-f0ef5196.js} +2 -2
  106. flowfile/web/static/assets/{ToggleSwitch.vue_vue_type_script_setup_true_lang-c6dc3029.js → ToggleSwitch.vue_vue_type_script_setup_true_lang-5605c793.js} +1 -1
  107. flowfile/web/static/assets/{UnavailableFields-5edd5322.css → UnavailableFields-54d2f518.css} +6 -6
  108. flowfile/web/static/assets/{UnavailableFields-1bab97cb.js → UnavailableFields-bdad6144.js} +4 -4
  109. flowfile/web/static/assets/{Union-af6c3d9b.css → Union-d6a8d7d5.css} +7 -7
  110. flowfile/web/static/assets/{Union-b563478a.js → Union-e8ab8c86.js} +8 -6
  111. flowfile/web/static/assets/{Unique-f90db5db.js → Unique-8cd4f976.js} +13 -22
  112. flowfile/web/static/assets/{Sort-3643d625.css → Unique-9fb2f567.css} +10 -10
  113. flowfile/web/static/assets/{Unpivot-1e422df3.css → Unpivot-710a2948.css} +7 -7
  114. flowfile/web/static/assets/{Unpivot-bcb0025f.js → Unpivot-8da14095.js} +10 -8
  115. flowfile/web/static/assets/{UnpivotValidation-c4e73b04.js → UnpivotValidation-6f7d89ff.js} +3 -3
  116. flowfile/web/static/assets/UnpivotValidation-d5ca3b7b.css +13 -0
  117. flowfile/web/static/assets/{VueGraphicWalker-bb8535e2.js → VueGraphicWalker-3fb312e1.js} +4 -4
  118. flowfile/web/static/assets/{VueGraphicWalker-ed5ab88b.css → VueGraphicWalker-430f0b86.css} +1 -1
  119. flowfile/web/static/assets/{api-4c8e3822.js → api-24483f0d.js} +1 -1
  120. flowfile/web/static/assets/{api-2d6adc4f.js → api-8b81fa73.js} +1 -1
  121. flowfile/web/static/assets/{dropDown-35135ba8.css → dropDown-3d8dc5fa.css} +40 -40
  122. flowfile/web/static/assets/{dropDown-1bca8a74.js → dropDown-ac0fda9d.js} +3 -3
  123. flowfile/web/static/assets/{fullEditor-2985687e.js → fullEditor-5497a84a.js} +11 -10
  124. flowfile/web/static/assets/{fullEditor-178376bb.css → fullEditor-a0be62b3.css} +74 -62
  125. flowfile/web/static/assets/{genericNodeSettings-924759c7.css → genericNodeSettings-3b2507ea.css} +10 -10
  126. flowfile/web/static/assets/{genericNodeSettings-0476ba4e.js → genericNodeSettings-99014e1d.js} +5 -5
  127. flowfile/web/static/assets/index-07dda503.js +38 -0
  128. flowfile/web/static/assets/index-3ba44389.js +2696 -0
  129. flowfile/web/static/assets/{index-50508d4d.css → index-e6289dd0.css} +1945 -569
  130. flowfile/web/static/assets/{index-246f201c.js → index-fb6493ae.js} +41626 -40869
  131. flowfile/web/static/assets/node.types-2c15bb7e.js +82 -0
  132. flowfile/web/static/assets/nodeInput-0eb13f1a.js +2 -0
  133. flowfile/web/static/assets/{outputCsv-d686eeaf.js → outputCsv-8f8ba42d.js} +3 -3
  134. flowfile/web/static/assets/outputCsv-b9a072af.css +2499 -0
  135. flowfile/web/static/assets/{outputExcel-8809ea2f.js → outputExcel-393f4fef.js} +3 -3
  136. flowfile/web/static/assets/{outputExcel-b41305c0.css → outputExcel-f5d272b2.css} +26 -26
  137. flowfile/web/static/assets/{outputParquet-53ba645a.js → outputParquet-07c81f65.js} +4 -4
  138. flowfile/web/static/assets/outputParquet-54597c3c.css +4 -0
  139. flowfile/web/static/assets/{readCsv-053bf97b.js → readCsv-07f6d9ad.js} +21 -20
  140. flowfile/web/static/assets/{readCsv-bca3ed53.css → readCsv-3bfac4c3.css} +15 -15
  141. flowfile/web/static/assets/{readExcel-e1b381ea.css → readExcel-3db6b763.css} +13 -13
  142. flowfile/web/static/assets/{readExcel-ad531eab.js → readExcel-ed69bc8f.js} +10 -12
  143. flowfile/web/static/assets/{readParquet-cee068e2.css → readParquet-c5244ad5.css} +4 -4
  144. flowfile/web/static/assets/{readParquet-58e899a1.js → readParquet-e3ed4528.js} +4 -7
  145. flowfile/web/static/assets/secrets.api-002e7d7e.js +65 -0
  146. flowfile/web/static/assets/{selectDynamic-b38de2ba.js → selectDynamic-80b92899.js} +5 -5
  147. flowfile/web/static/assets/{selectDynamic-aa913ff4.css → selectDynamic-f2fb394f.css} +21 -20
  148. flowfile/web/static/assets/{vue-codemirror.esm-db9b8936.js → vue-codemirror.esm-0965f39f.js} +31 -637
  149. flowfile/web/static/assets/{vue-content-loader.es-b5f3ac30.js → vue-content-loader.es-c506ad97.js} +1 -1
  150. flowfile/web/static/index.html +2 -2
  151. {flowfile-0.4.1.dist-info → flowfile-0.5.3.dist-info}/METADATA +4 -4
  152. flowfile-0.5.3.dist-info/RECORD +402 -0
  153. {flowfile-0.4.1.dist-info → flowfile-0.5.3.dist-info}/WHEEL +1 -1
  154. {flowfile-0.4.1.dist-info → flowfile-0.5.3.dist-info}/entry_points.txt +1 -0
  155. flowfile_core/__init__.py +13 -3
  156. flowfile_core/auth/jwt.py +51 -16
  157. flowfile_core/auth/models.py +32 -7
  158. flowfile_core/auth/password.py +89 -0
  159. flowfile_core/auth/secrets.py +8 -6
  160. flowfile_core/configs/__init__.py +9 -7
  161. flowfile_core/configs/flow_logger.py +15 -14
  162. flowfile_core/configs/node_store/__init__.py +72 -4
  163. flowfile_core/configs/node_store/nodes.py +155 -172
  164. flowfile_core/configs/node_store/user_defined_node_registry.py +108 -27
  165. flowfile_core/configs/settings.py +28 -15
  166. flowfile_core/database/connection.py +7 -6
  167. flowfile_core/database/init_db.py +96 -2
  168. flowfile_core/database/models.py +3 -1
  169. flowfile_core/fileExplorer/__init__.py +17 -0
  170. flowfile_core/fileExplorer/funcs.py +123 -57
  171. flowfile_core/fileExplorer/utils.py +10 -11
  172. flowfile_core/flowfile/_extensions/real_time_interface.py +10 -8
  173. flowfile_core/flowfile/analytics/analytics_processor.py +27 -24
  174. flowfile_core/flowfile/analytics/graphic_walker.py +11 -12
  175. flowfile_core/flowfile/analytics/utils.py +1 -1
  176. flowfile_core/flowfile/code_generator/code_generator.py +391 -279
  177. flowfile_core/flowfile/connection_manager/_connection_manager.py +6 -5
  178. flowfile_core/flowfile/connection_manager/models.py +1 -1
  179. flowfile_core/flowfile/database_connection_manager/db_connections.py +60 -44
  180. flowfile_core/flowfile/database_connection_manager/models.py +1 -1
  181. flowfile_core/flowfile/extensions.py +17 -12
  182. flowfile_core/flowfile/flow_data_engine/cloud_storage_reader.py +34 -32
  183. flowfile_core/flowfile/flow_data_engine/create/funcs.py +152 -103
  184. flowfile_core/flowfile/flow_data_engine/flow_data_engine.py +526 -477
  185. flowfile_core/flowfile/flow_data_engine/flow_file_column/interface.py +2 -2
  186. flowfile_core/flowfile/flow_data_engine/flow_file_column/main.py +92 -52
  187. flowfile_core/flowfile/flow_data_engine/flow_file_column/polars_type.py +12 -11
  188. flowfile_core/flowfile/flow_data_engine/flow_file_column/type_registry.py +6 -6
  189. flowfile_core/flowfile/flow_data_engine/flow_file_column/utils.py +26 -30
  190. flowfile_core/flowfile/flow_data_engine/fuzzy_matching/prepare_for_fuzzy_match.py +43 -32
  191. flowfile_core/flowfile/flow_data_engine/join/__init__.py +1 -1
  192. flowfile_core/flowfile/flow_data_engine/join/utils.py +11 -9
  193. flowfile_core/flowfile/flow_data_engine/join/verify_integrity.py +15 -11
  194. flowfile_core/flowfile/flow_data_engine/pivot_table.py +5 -7
  195. flowfile_core/flowfile/flow_data_engine/polars_code_parser.py +95 -82
  196. flowfile_core/flowfile/flow_data_engine/read_excel_tables.py +66 -65
  197. flowfile_core/flowfile/flow_data_engine/sample_data.py +27 -21
  198. flowfile_core/flowfile/flow_data_engine/subprocess_operations/__init__.py +1 -1
  199. flowfile_core/flowfile/flow_data_engine/subprocess_operations/models.py +13 -11
  200. flowfile_core/flowfile/flow_data_engine/subprocess_operations/subprocess_operations.py +360 -191
  201. flowfile_core/flowfile/flow_data_engine/threaded_processes.py +8 -8
  202. flowfile_core/flowfile/flow_data_engine/utils.py +101 -67
  203. flowfile_core/flowfile/flow_graph.py +1011 -561
  204. flowfile_core/flowfile/flow_graph_utils.py +31 -49
  205. flowfile_core/flowfile/flow_node/flow_node.py +332 -232
  206. flowfile_core/flowfile/flow_node/models.py +54 -41
  207. flowfile_core/flowfile/flow_node/schema_callback.py +14 -19
  208. flowfile_core/flowfile/graph_tree/graph_tree.py +41 -41
  209. flowfile_core/flowfile/handler.py +82 -32
  210. flowfile_core/flowfile/manage/compatibility_enhancements.py +493 -47
  211. flowfile_core/flowfile/manage/io_flowfile.py +391 -0
  212. flowfile_core/flowfile/node_designer/__init__.py +15 -13
  213. flowfile_core/flowfile/node_designer/_type_registry.py +34 -37
  214. flowfile_core/flowfile/node_designer/custom_node.py +162 -36
  215. flowfile_core/flowfile/node_designer/ui_components.py +136 -35
  216. flowfile_core/flowfile/schema_callbacks.py +77 -54
  217. flowfile_core/flowfile/setting_generator/__init__.py +0 -1
  218. flowfile_core/flowfile/setting_generator/setting_generator.py +6 -5
  219. flowfile_core/flowfile/setting_generator/settings.py +72 -55
  220. flowfile_core/flowfile/sources/external_sources/base_class.py +12 -10
  221. flowfile_core/flowfile/sources/external_sources/custom_external_sources/external_source.py +27 -17
  222. flowfile_core/flowfile/sources/external_sources/custom_external_sources/sample_users.py +9 -9
  223. flowfile_core/flowfile/sources/external_sources/factory.py +0 -1
  224. flowfile_core/flowfile/sources/external_sources/sql_source/models.py +45 -31
  225. flowfile_core/flowfile/sources/external_sources/sql_source/sql_source.py +198 -73
  226. flowfile_core/flowfile/sources/external_sources/sql_source/utils.py +250 -196
  227. flowfile_core/flowfile/util/calculate_layout.py +9 -13
  228. flowfile_core/flowfile/util/execution_orderer.py +25 -17
  229. flowfile_core/flowfile/util/node_skipper.py +4 -4
  230. flowfile_core/flowfile/utils.py +19 -21
  231. flowfile_core/main.py +26 -19
  232. flowfile_core/routes/auth.py +284 -11
  233. flowfile_core/routes/cloud_connections.py +25 -25
  234. flowfile_core/routes/logs.py +21 -29
  235. flowfile_core/routes/public.py +3 -3
  236. flowfile_core/routes/routes.py +77 -43
  237. flowfile_core/routes/secrets.py +25 -27
  238. flowfile_core/routes/user_defined_components.py +483 -4
  239. flowfile_core/run_lock.py +0 -1
  240. flowfile_core/schemas/__init__.py +4 -6
  241. flowfile_core/schemas/analysis_schemas/graphic_walker_schemas.py +55 -55
  242. flowfile_core/schemas/cloud_storage_schemas.py +59 -55
  243. flowfile_core/schemas/input_schema.py +398 -154
  244. flowfile_core/schemas/output_model.py +50 -35
  245. flowfile_core/schemas/schemas.py +207 -67
  246. flowfile_core/schemas/transform_schema.py +1360 -435
  247. flowfile_core/schemas/yaml_types.py +117 -0
  248. flowfile_core/secret_manager/secret_manager.py +17 -13
  249. flowfile_core/{flowfile/node_designer/data_types.py → types.py} +33 -3
  250. flowfile_core/utils/arrow_reader.py +7 -6
  251. flowfile_core/utils/excel_file_manager.py +3 -3
  252. flowfile_core/utils/fileManager.py +7 -7
  253. flowfile_core/utils/fl_executor.py +8 -10
  254. flowfile_core/utils/utils.py +4 -4
  255. flowfile_core/utils/validate_setup.py +5 -4
  256. flowfile_frame/__init__.py +107 -50
  257. flowfile_frame/adapters.py +2 -9
  258. flowfile_frame/adding_expr.py +73 -32
  259. flowfile_frame/cloud_storage/frame_helpers.py +27 -23
  260. flowfile_frame/cloud_storage/secret_manager.py +12 -26
  261. flowfile_frame/config.py +2 -5
  262. flowfile_frame/expr.py +311 -218
  263. flowfile_frame/expr.pyi +160 -159
  264. flowfile_frame/expr_name.py +23 -23
  265. flowfile_frame/flow_frame.py +581 -489
  266. flowfile_frame/flow_frame.pyi +123 -104
  267. flowfile_frame/flow_frame_methods.py +236 -252
  268. flowfile_frame/group_frame.py +50 -20
  269. flowfile_frame/join.py +2 -2
  270. flowfile_frame/lazy.py +129 -87
  271. flowfile_frame/lazy_methods.py +83 -30
  272. flowfile_frame/list_name_space.py +55 -50
  273. flowfile_frame/selectors.py +148 -68
  274. flowfile_frame/series.py +9 -7
  275. flowfile_frame/utils.py +19 -21
  276. flowfile_worker/__init__.py +12 -4
  277. flowfile_worker/configs.py +11 -19
  278. flowfile_worker/create/__init__.py +14 -27
  279. flowfile_worker/create/funcs.py +143 -94
  280. flowfile_worker/create/models.py +139 -68
  281. flowfile_worker/create/pl_types.py +14 -15
  282. flowfile_worker/create/read_excel_tables.py +34 -41
  283. flowfile_worker/create/utils.py +22 -19
  284. flowfile_worker/external_sources/s3_source/main.py +18 -51
  285. flowfile_worker/external_sources/s3_source/models.py +34 -27
  286. flowfile_worker/external_sources/sql_source/main.py +8 -5
  287. flowfile_worker/external_sources/sql_source/models.py +13 -9
  288. flowfile_worker/flow_logger.py +10 -8
  289. flowfile_worker/funcs.py +214 -155
  290. flowfile_worker/main.py +11 -17
  291. flowfile_worker/models.py +35 -28
  292. flowfile_worker/process_manager.py +2 -3
  293. flowfile_worker/routes.py +121 -93
  294. flowfile_worker/secrets.py +9 -6
  295. flowfile_worker/spawner.py +80 -49
  296. flowfile_worker/utils.py +3 -2
  297. shared/__init__.py +2 -7
  298. shared/storage_config.py +25 -13
  299. test_utils/postgres/commands.py +3 -2
  300. test_utils/postgres/fixtures.py +9 -9
  301. test_utils/s3/commands.py +1 -1
  302. test_utils/s3/data_generator.py +3 -4
  303. test_utils/s3/demo_data_generator.py +4 -7
  304. test_utils/s3/fixtures.py +7 -5
  305. tools/migrate/README.md +56 -0
  306. tools/migrate/__init__.py +12 -0
  307. tools/migrate/__main__.py +118 -0
  308. tools/migrate/legacy_schemas.py +682 -0
  309. tools/migrate/migrate.py +610 -0
  310. tools/migrate/tests/__init__.py +0 -0
  311. tools/migrate/tests/conftest.py +21 -0
  312. tools/migrate/tests/test_migrate.py +622 -0
  313. tools/migrate/tests/test_migration_e2e.py +1009 -0
  314. tools/migrate/tests/test_node_migrations.py +843 -0
  315. flowfile/web/static/assets/CloudConnectionManager-2dfdce2f.css +0 -86
  316. flowfile/web/static/assets/CustomNode-74a37f74.css +0 -32
  317. flowfile/web/static/assets/DatabaseManager-30fa27e5.css +0 -64
  318. flowfile/web/static/assets/Filter-812dcbca.js +0 -164
  319. flowfile/web/static/assets/Filter-f62091b3.css +0 -20
  320. flowfile/web/static/assets/ManualInput-3246a08d.css +0 -96
  321. flowfile/web/static/assets/PivotValidation-891ddfb0.css +0 -13
  322. flowfile/web/static/assets/PivotValidation-c46cd420.css +0 -13
  323. flowfile/web/static/assets/SliderInput-b8fb6a8c.css +0 -4
  324. flowfile/web/static/assets/UnpivotValidation-0d240eeb.css +0 -13
  325. flowfile/web/static/assets/outputCsv-9cc59e0b.css +0 -2499
  326. flowfile/web/static/assets/outputParquet-cf8cf3f2.css +0 -4
  327. flowfile/web/static/assets/secretApi-538058f3.js +0 -46
  328. flowfile/web/static/assets/vue-codemirror-bccfde04.css +0 -32
  329. flowfile-0.4.1.dist-info/RECORD +0 -376
  330. flowfile_core/flowfile/manage/open_flowfile.py +0 -143
  331. {flowfile-0.4.1.dist-info → flowfile-0.5.3.dist-info}/licenses/LICENSE +0 -0
  332. /flowfile_core/flowfile/manage/manage_flowfile.py → /tools/__init__.py +0 -0
@@ -0,0 +1,2610 @@
1
+ import { d as defineComponent, o as openBlock, c as createElementBlock, b as createBaseVNode, F as Fragment, D as renderList, n as normalizeClass, t as toDisplayString, s as unref, i as _export_sfc, w as withModifiers, f as createCommentVNode, r as ref, q as createTextVNode, e as createStaticVNode, m as createVNode, C as onMounted, j as axios, S as reactive, A as computed, B as watch, g as withDirectives, v as vModelText, U as isRef, x as createBlock } from "./index-fb6493ae.js";
2
+ import { T, k as keymap, a as acceptCompletion, i as indentMore, b as indentLess, c as EditorState, d as autocompletion, P as Prec, E as EditorView } from "./vue-codemirror.esm-0965f39f.js";
3
+ import { g as getImageUrl, _ as __vite_glob_0_0, a as __vite_glob_0_1, b as __vite_glob_0_2, c as __vite_glob_0_3, d as __vite_glob_0_4, e as __vite_glob_0_5, h as __vite_glob_0_6, i as __vite_glob_0_7, j as __vite_glob_0_8, k as __vite_glob_0_9, l as __vite_glob_0_10, m as __vite_glob_0_11, n as __vite_glob_0_12, q as __vite_glob_0_13, r as __vite_glob_0_14, s as __vite_glob_0_15, t as __vite_glob_0_16, u as __vite_glob_0_17, v as __vite_glob_0_18, w as __vite_glob_0_19, x as __vite_glob_0_20, y as __vite_glob_0_21, z as __vite_glob_0_22, A as __vite_glob_0_23, B as __vite_glob_0_24, C as __vite_glob_0_25, D as __vite_glob_0_26, E as __vite_glob_0_27, F as __vite_glob_0_28, G as __vite_glob_0_29, H as __vite_glob_0_30, I as __vite_glob_0_31, J as __vite_glob_0_32, K as __vite_glob_0_33, L as getDefaultIconUrl, M as getCustomIconUrl, p as python, o as oneDark } from "./index-3ba44389.js";
4
+ const STORAGE_KEY = "nodeDesigner_state";
5
+ const availableComponents = [
6
+ { type: "TextInput", label: "Text Input", icon: "fa-solid fa-font" },
7
+ { type: "NumericInput", label: "Numeric Input", icon: "fa-solid fa-hashtag" },
8
+ { type: "ToggleSwitch", label: "Toggle Switch", icon: "fa-solid fa-toggle-on" },
9
+ { type: "SingleSelect", label: "Single Select", icon: "fa-solid fa-list" },
10
+ { type: "MultiSelect", label: "Multi Select", icon: "fa-solid fa-list-check" },
11
+ { type: "ColumnSelector", label: "Column Selector", icon: "fa-solid fa-table-columns" },
12
+ { type: "SliderInput", label: "Slider", icon: "fa-solid fa-sliders" },
13
+ { type: "SecretSelector", label: "Secret Selector", icon: "fa-solid fa-key" }
14
+ ];
15
+ const defaultProcessCode = `def process(self, *inputs: pl.LazyFrame) -> pl.LazyFrame:
16
+ # Get the first input LazyFrame
17
+ lf = inputs[0]
18
+
19
+ # Your transformation logic here
20
+ # Example: lf = lf.filter(pl.col("column") > 0)
21
+
22
+ return lf`;
23
+ const defaultNodeMetadata = {
24
+ node_name: "",
25
+ node_category: "Custom",
26
+ title: "",
27
+ intro: "",
28
+ number_of_inputs: 1,
29
+ number_of_outputs: 1,
30
+ node_icon: "user-defined-icon.png"
31
+ };
32
+ function getComponentIcon(type) {
33
+ const comp = availableComponents.find((c) => c.type === type);
34
+ return (comp == null ? void 0 : comp.icon) || "fa-solid fa-puzzle-piece";
35
+ }
36
+ const _hoisted_1$a = { class: "panel component-palette" };
37
+ const _hoisted_2$a = { class: "panel-content" };
38
+ const _hoisted_3$9 = ["onDragstart"];
39
+ const _sfc_main$a = /* @__PURE__ */ defineComponent({
40
+ __name: "ComponentPalette",
41
+ emits: ["dragstart"],
42
+ setup(__props, { emit: __emit }) {
43
+ const emit = __emit;
44
+ function handleDragStart(event, component) {
45
+ var _a;
46
+ (_a = event.dataTransfer) == null ? void 0 : _a.setData("component_type", component.type);
47
+ emit("dragstart", event, component);
48
+ }
49
+ return (_ctx, _cache) => {
50
+ return openBlock(), createElementBlock("div", _hoisted_1$a, [
51
+ _cache[0] || (_cache[0] = createBaseVNode("div", { class: "panel-header" }, [
52
+ createBaseVNode("h3", null, "Components")
53
+ ], -1)),
54
+ createBaseVNode("div", _hoisted_2$a, [
55
+ (openBlock(true), createElementBlock(Fragment, null, renderList(unref(availableComponents), (comp) => {
56
+ return openBlock(), createElementBlock("div", {
57
+ key: comp.type,
58
+ class: "component-item",
59
+ draggable: "true",
60
+ onDragstart: ($event) => handleDragStart($event, comp)
61
+ }, [
62
+ createBaseVNode("i", {
63
+ class: normalizeClass(comp.icon)
64
+ }, null, 2),
65
+ createBaseVNode("span", null, toDisplayString(comp.label), 1)
66
+ ], 40, _hoisted_3$9);
67
+ }), 128))
68
+ ])
69
+ ]);
70
+ };
71
+ }
72
+ });
73
+ const ComponentPalette_vue_vue_type_style_index_0_scoped_7eeb4ea6_lang = "";
74
+ const ComponentPalette = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["__scopeId", "data-v-7eeb4ea6"]]);
75
+ const _hoisted_1$9 = { class: "section-header" };
76
+ const _hoisted_2$9 = { class: "section-fields" };
77
+ const _hoisted_3$8 = { class: "section-field" };
78
+ const _hoisted_4$7 = ["value"];
79
+ const _hoisted_5$5 = { class: "section-field" };
80
+ const _hoisted_6$5 = ["value"];
81
+ const _hoisted_7$5 = ["onClick"];
82
+ const _hoisted_8$5 = { class: "component-preview" };
83
+ const _hoisted_9$5 = { class: "component-label" };
84
+ const _hoisted_10$5 = { class: "component-type" };
85
+ const _hoisted_11$5 = ["onClick"];
86
+ const _hoisted_12$4 = {
87
+ key: 0,
88
+ class: "drop-zone"
89
+ };
90
+ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
91
+ __name: "SectionCard",
92
+ props: {
93
+ section: {},
94
+ isSelected: { type: Boolean },
95
+ selectedComponentIndex: {}
96
+ },
97
+ emits: ["select", "remove", "selectComponent", "removeComponent", "drop", "updateName", "updateTitle"],
98
+ setup(__props, { emit: __emit }) {
99
+ const emit = __emit;
100
+ function handleNameChange(event) {
101
+ const target = event.target;
102
+ emit("updateName", target.value);
103
+ }
104
+ function handleTitleChange(event) {
105
+ const target = event.target;
106
+ emit("updateTitle", target.value);
107
+ }
108
+ function handleDrop(event) {
109
+ emit("drop", event);
110
+ }
111
+ return (_ctx, _cache) => {
112
+ return openBlock(), createElementBlock("div", {
113
+ class: normalizeClass(["section-card", { selected: _ctx.isSelected }]),
114
+ onClick: _cache[4] || (_cache[4] = ($event) => emit("select"))
115
+ }, [
116
+ createBaseVNode("div", _hoisted_1$9, [
117
+ createBaseVNode("div", _hoisted_2$9, [
118
+ createBaseVNode("div", _hoisted_3$8, [
119
+ _cache[5] || (_cache[5] = createBaseVNode("label", null, "Variable Name", -1)),
120
+ createBaseVNode("input", {
121
+ value: _ctx.section.name,
122
+ type: "text",
123
+ class: "section-name-input",
124
+ placeholder: "section_name",
125
+ onClick: _cache[0] || (_cache[0] = withModifiers(() => {
126
+ }, ["stop"])),
127
+ onInput: handleNameChange
128
+ }, null, 40, _hoisted_4$7)
129
+ ]),
130
+ createBaseVNode("div", _hoisted_5$5, [
131
+ _cache[6] || (_cache[6] = createBaseVNode("label", null, "Display Title", -1)),
132
+ createBaseVNode("input", {
133
+ value: _ctx.section.title,
134
+ type: "text",
135
+ class: "section-title-input",
136
+ placeholder: "Section Title",
137
+ onClick: _cache[1] || (_cache[1] = withModifiers(() => {
138
+ }, ["stop"])),
139
+ onInput: handleTitleChange
140
+ }, null, 40, _hoisted_6$5)
141
+ ])
142
+ ]),
143
+ createBaseVNode("button", {
144
+ class: "btn-icon",
145
+ onClick: _cache[2] || (_cache[2] = withModifiers(($event) => emit("remove"), ["stop"]))
146
+ }, _cache[7] || (_cache[7] = [
147
+ createBaseVNode("i", { class: "fa-solid fa-trash" }, null, -1)
148
+ ]))
149
+ ]),
150
+ createBaseVNode("div", {
151
+ class: "section-components",
152
+ onDragover: _cache[3] || (_cache[3] = withModifiers(() => {
153
+ }, ["prevent"])),
154
+ onDrop: handleDrop
155
+ }, [
156
+ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.section.components, (component, compIndex) => {
157
+ return openBlock(), createElementBlock("div", {
158
+ key: compIndex,
159
+ class: normalizeClass(["component-card", { selected: _ctx.isSelected && _ctx.selectedComponentIndex === compIndex }]),
160
+ onClick: withModifiers(($event) => emit("selectComponent", compIndex), ["stop"])
161
+ }, [
162
+ createBaseVNode("div", _hoisted_8$5, [
163
+ createBaseVNode("i", {
164
+ class: normalizeClass(unref(getComponentIcon)(component.component_type))
165
+ }, null, 2),
166
+ createBaseVNode("span", _hoisted_9$5, toDisplayString(component.label || component.component_type), 1),
167
+ createBaseVNode("span", _hoisted_10$5, "(" + toDisplayString(component.component_type) + ")", 1)
168
+ ]),
169
+ createBaseVNode("button", {
170
+ class: "btn-icon btn-remove",
171
+ onClick: withModifiers(($event) => emit("removeComponent", compIndex), ["stop"])
172
+ }, _cache[8] || (_cache[8] = [
173
+ createBaseVNode("i", { class: "fa-solid fa-times" }, null, -1)
174
+ ]), 8, _hoisted_11$5)
175
+ ], 10, _hoisted_7$5);
176
+ }), 128)),
177
+ _ctx.section.components.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_12$4, _cache[9] || (_cache[9] = [
178
+ createBaseVNode("i", { class: "fa-solid fa-plus" }, null, -1),
179
+ createBaseVNode("span", null, "Drop components here", -1)
180
+ ]))) : createCommentVNode("", true)
181
+ ], 32)
182
+ ], 2);
183
+ };
184
+ }
185
+ });
186
+ const SectionCard_vue_vue_type_style_index_0_scoped_17318956_lang = "";
187
+ const SectionCard = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["__scopeId", "data-v-17318956"]]);
188
+ function toSnakeCase(str) {
189
+ return str.replace(/\s+/g, "_").replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase().replace(/[^a-z0-9_]/g, "");
190
+ }
191
+ function toPascalCase(str) {
192
+ return str.split(/[\s_-]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
193
+ }
194
+ function useCodeGeneration() {
195
+ const showPreviewModal = ref(false);
196
+ const generatedCode = ref("");
197
+ function generateCode(nodeMetadata, sections, processCode) {
198
+ const nodeName = toPascalCase(nodeMetadata.node_name || "MyCustomNode");
199
+ const nodeSettingsName = `${nodeName}Settings`;
200
+ const imports = /* @__PURE__ */ new Set();
201
+ imports.add("CustomNodeBase");
202
+ imports.add("Section");
203
+ imports.add("NodeSettings");
204
+ sections.forEach((section) => {
205
+ section.components.forEach((comp) => {
206
+ imports.add(comp.component_type);
207
+ if (comp.options_source === "incoming_columns") {
208
+ imports.add("IncomingColumns");
209
+ }
210
+ });
211
+ });
212
+ let sectionsCode = "";
213
+ sections.forEach((section) => {
214
+ const sectionName = section.name || toSnakeCase(section.title || "section");
215
+ const sectionTitle = section.title || section.name || "Section";
216
+ sectionsCode += `
217
+ # ${sectionTitle}
218
+ `;
219
+ sectionsCode += `${sectionName} = Section(
220
+ `;
221
+ sectionsCode += ` title="${sectionTitle}",
222
+ `;
223
+ section.components.forEach((comp) => {
224
+ const fieldName = toSnakeCase(comp.field_name);
225
+ sectionsCode += ` ${fieldName}=${comp.component_type}(
226
+ `;
227
+ sectionsCode += ` label="${comp.label || fieldName}",
228
+ `;
229
+ if (comp.component_type === "TextInput") {
230
+ if (comp.default)
231
+ sectionsCode += ` default="${comp.default}",
232
+ `;
233
+ if (comp.placeholder)
234
+ sectionsCode += ` placeholder="${comp.placeholder}",
235
+ `;
236
+ } else if (comp.component_type === "NumericInput") {
237
+ if (comp.default !== void 0)
238
+ sectionsCode += ` default=${comp.default},
239
+ `;
240
+ if (comp.min_value !== void 0)
241
+ sectionsCode += ` min_value=${comp.min_value},
242
+ `;
243
+ if (comp.max_value !== void 0)
244
+ sectionsCode += ` max_value=${comp.max_value},
245
+ `;
246
+ } else if (comp.component_type === "ToggleSwitch") {
247
+ sectionsCode += ` default=${comp.default ? "True" : "False"},
248
+ `;
249
+ if (comp.description)
250
+ sectionsCode += ` description="${comp.description}",
251
+ `;
252
+ } else if (comp.component_type === "SingleSelect" || comp.component_type === "MultiSelect") {
253
+ if (comp.options_source === "incoming_columns") {
254
+ sectionsCode += ` options=IncomingColumns,
255
+ `;
256
+ } else if (comp.options_string) {
257
+ const options = comp.options_string.split(",").map((o) => `"${o.trim()}"`).join(", ");
258
+ sectionsCode += ` options=[${options}],
259
+ `;
260
+ }
261
+ } else if (comp.component_type === "ColumnSelector") {
262
+ if (comp.required)
263
+ sectionsCode += ` required=True,
264
+ `;
265
+ if (comp.multiple)
266
+ sectionsCode += ` multiple=True,
267
+ `;
268
+ if (comp.data_types && comp.data_types !== "ALL") {
269
+ sectionsCode += ` data_types="${comp.data_types}",
270
+ `;
271
+ }
272
+ } else if (comp.component_type === "SliderInput") {
273
+ sectionsCode += ` min_value=${comp.min_value ?? 0},
274
+ `;
275
+ sectionsCode += ` max_value=${comp.max_value ?? 100},
276
+ `;
277
+ if (comp.step)
278
+ sectionsCode += ` step=${comp.step},
279
+ `;
280
+ } else if (comp.component_type === "SecretSelector") {
281
+ if (comp.required)
282
+ sectionsCode += ` required=True,
283
+ `;
284
+ if (comp.description)
285
+ sectionsCode += ` description="${comp.description}",
286
+ `;
287
+ if (comp.name_prefix)
288
+ sectionsCode += ` name_prefix="${comp.name_prefix}",
289
+ `;
290
+ }
291
+ sectionsCode += ` ),
292
+ `;
293
+ });
294
+ sectionsCode += `)
295
+ `;
296
+ });
297
+ let settingsCode = `
298
+ class ${nodeSettingsName}(NodeSettings):
299
+ `;
300
+ sections.forEach((section) => {
301
+ const sectionName = section.name || toSnakeCase(section.title || "section");
302
+ settingsCode += ` ${sectionName}: Section = ${sectionName}
303
+ `;
304
+ });
305
+ if (sections.length === 0) {
306
+ settingsCode += ` pass
307
+ `;
308
+ }
309
+ let processBody = processCode;
310
+ const defMatch = processBody.match(/def\s+process\s*\([^)]*\)\s*->\s*[^:]+:\n?/);
311
+ if (defMatch) {
312
+ processBody = processBody.substring(defMatch[0].length);
313
+ }
314
+ const lines = processBody.split("\n");
315
+ const nonEmptyLines = lines.filter((line) => line.trim().length > 0);
316
+ let minIndent = 0;
317
+ if (nonEmptyLines.length > 0) {
318
+ minIndent = Math.min(
319
+ ...nonEmptyLines.map((line) => {
320
+ const match = line.match(/^(\s*)/);
321
+ return match ? match[1].length : 0;
322
+ })
323
+ );
324
+ }
325
+ const reindentedLines = lines.map((line) => {
326
+ if (line.trim().length === 0) {
327
+ return "";
328
+ }
329
+ const dedented = line.length >= minIndent ? line.substring(minIndent) : line.trimStart();
330
+ return " " + dedented;
331
+ });
332
+ processBody = reindentedLines.join("\n");
333
+ const nodeCode = `
334
+
335
+ class ${nodeName}(CustomNodeBase):
336
+ node_name: str = "${nodeMetadata.node_name}"
337
+ node_category: str = "${nodeMetadata.node_category}"
338
+ node_icon: str = "${nodeMetadata.node_icon || "user-defined-icon.png"}"
339
+ title: str = "${nodeMetadata.title || nodeMetadata.node_name}"
340
+ intro: str = "${nodeMetadata.intro || "A custom node for data processing"}"
341
+ number_of_inputs: int = ${nodeMetadata.number_of_inputs}
342
+ number_of_outputs: int = ${nodeMetadata.number_of_outputs}
343
+ settings_schema: ${nodeSettingsName} = ${nodeSettingsName}()
344
+
345
+ def process(self, *inputs: pl.LazyFrame) -> pl.LazyFrame:
346
+ ${processBody}
347
+ `;
348
+ const secretStrImport = processCode.includes("SecretStr") ? "from pydantic import SecretStr\n" : "";
349
+ const fullCode = `# Auto-generated custom node
350
+ # Generated by Node Designer
351
+
352
+ import polars as pl
353
+ ${secretStrImport}from flowfile_core.flowfile.node_designer import (
354
+ ${Array.from(imports).join(", ")}
355
+ )
356
+ ${sectionsCode}${settingsCode}${nodeCode}`;
357
+ return fullCode;
358
+ }
359
+ function previewCode(nodeMetadata, sections, processCode) {
360
+ generatedCode.value = generateCode(nodeMetadata, sections, processCode);
361
+ showPreviewModal.value = true;
362
+ }
363
+ function closePreview() {
364
+ showPreviewModal.value = false;
365
+ }
366
+ function copyCode() {
367
+ navigator.clipboard.writeText(generatedCode.value);
368
+ alert("Code copied to clipboard!");
369
+ }
370
+ return {
371
+ showPreviewModal,
372
+ generatedCode,
373
+ generateCode,
374
+ previewCode,
375
+ closePreview,
376
+ copyCode,
377
+ toSnakeCase,
378
+ toPascalCase
379
+ };
380
+ }
381
+ const _hoisted_1$8 = { class: "panel property-editor" };
382
+ const _hoisted_2$8 = { class: "panel-content" };
383
+ const _hoisted_3$7 = {
384
+ key: 0,
385
+ class: "property-form"
386
+ };
387
+ const _hoisted_4$6 = { class: "component-type-badge" };
388
+ const _hoisted_5$4 = { class: "property-group" };
389
+ const _hoisted_6$4 = { class: "property-row" };
390
+ const _hoisted_7$4 = ["value"];
391
+ const _hoisted_8$4 = { class: "property-row" };
392
+ const _hoisted_9$4 = ["value"];
393
+ const _hoisted_10$4 = {
394
+ key: 0,
395
+ class: "property-group"
396
+ };
397
+ const _hoisted_11$4 = { class: "property-row" };
398
+ const _hoisted_12$3 = ["value"];
399
+ const _hoisted_13$3 = { class: "property-row" };
400
+ const _hoisted_14$3 = ["value"];
401
+ const _hoisted_15$3 = {
402
+ key: 1,
403
+ class: "property-group"
404
+ };
405
+ const _hoisted_16$3 = { class: "property-row" };
406
+ const _hoisted_17$2 = ["value"];
407
+ const _hoisted_18$2 = { class: "property-row" };
408
+ const _hoisted_19$1 = ["value"];
409
+ const _hoisted_20 = { class: "property-row" };
410
+ const _hoisted_21 = ["value"];
411
+ const _hoisted_22 = {
412
+ key: 2,
413
+ class: "property-group"
414
+ };
415
+ const _hoisted_23 = { class: "property-row checkbox-row" };
416
+ const _hoisted_24 = ["checked"];
417
+ const _hoisted_25 = { class: "property-row" };
418
+ const _hoisted_26 = ["value"];
419
+ const _hoisted_27 = {
420
+ key: 3,
421
+ class: "property-group"
422
+ };
423
+ const _hoisted_28 = { class: "property-row" };
424
+ const _hoisted_29 = ["value"];
425
+ const _hoisted_30 = {
426
+ key: 0,
427
+ class: "property-row"
428
+ };
429
+ const _hoisted_31 = ["value"];
430
+ const _hoisted_32 = {
431
+ key: 4,
432
+ class: "property-group"
433
+ };
434
+ const _hoisted_33 = { class: "property-row" };
435
+ const _hoisted_34 = ["value"];
436
+ const _hoisted_35 = {
437
+ key: 0,
438
+ class: "property-row"
439
+ };
440
+ const _hoisted_36 = ["value"];
441
+ const _hoisted_37 = {
442
+ key: 5,
443
+ class: "property-group"
444
+ };
445
+ const _hoisted_38 = { class: "property-row checkbox-row" };
446
+ const _hoisted_39 = ["checked"];
447
+ const _hoisted_40 = { class: "property-row checkbox-row" };
448
+ const _hoisted_41 = ["checked"];
449
+ const _hoisted_42 = { class: "property-row" };
450
+ const _hoisted_43 = ["value"];
451
+ const _hoisted_44 = {
452
+ key: 6,
453
+ class: "property-group"
454
+ };
455
+ const _hoisted_45 = { class: "property-row" };
456
+ const _hoisted_46 = ["value"];
457
+ const _hoisted_47 = { class: "property-row" };
458
+ const _hoisted_48 = ["value"];
459
+ const _hoisted_49 = { class: "property-row" };
460
+ const _hoisted_50 = ["value"];
461
+ const _hoisted_51 = {
462
+ key: 7,
463
+ class: "property-group"
464
+ };
465
+ const _hoisted_52 = { class: "property-row checkbox-row" };
466
+ const _hoisted_53 = ["checked"];
467
+ const _hoisted_54 = { class: "property-row" };
468
+ const _hoisted_55 = ["value"];
469
+ const _hoisted_56 = { class: "property-row" };
470
+ const _hoisted_57 = ["value"];
471
+ const _hoisted_58 = {
472
+ key: 1,
473
+ class: "no-selection"
474
+ };
475
+ const _sfc_main$8 = /* @__PURE__ */ defineComponent({
476
+ __name: "PropertyEditor",
477
+ props: {
478
+ component: {},
479
+ sectionName: {}
480
+ },
481
+ emits: ["update", "insert-variable"],
482
+ setup(__props, { emit: __emit }) {
483
+ const props = __props;
484
+ const emit = __emit;
485
+ function updateField(field, value) {
486
+ emit("update", field, value);
487
+ }
488
+ function getTypeForComponent(componentType, multiple) {
489
+ switch (componentType) {
490
+ case "TextInput":
491
+ return "str";
492
+ case "NumericInput":
493
+ case "SliderInput":
494
+ return "float";
495
+ case "ToggleSwitch":
496
+ return "bool";
497
+ case "SingleSelect":
498
+ return "str";
499
+ case "MultiSelect":
500
+ return "list[str]";
501
+ case "ColumnSelector":
502
+ return multiple ? "list[str]" : "str";
503
+ case "SecretSelector":
504
+ return "SecretStr";
505
+ default:
506
+ return "Any";
507
+ }
508
+ }
509
+ function insertVariable() {
510
+ if (!props.component || !props.sectionName)
511
+ return;
512
+ const fieldName = toSnakeCase(props.component.field_name);
513
+ const sectionName = toSnakeCase(props.sectionName);
514
+ const pyType = getTypeForComponent(props.component.component_type, props.component.multiple);
515
+ let code;
516
+ if (props.component.component_type === "SecretSelector") {
517
+ code = ` ${fieldName}: ${pyType} = self.settings_schema.${sectionName}.${fieldName}.secret_value`;
518
+ } else {
519
+ code = ` ${fieldName}: ${pyType} = self.settings_schema.${sectionName}.${fieldName}.value`;
520
+ }
521
+ emit("insert-variable", code);
522
+ }
523
+ return (_ctx, _cache) => {
524
+ return openBlock(), createElementBlock("div", _hoisted_1$8, [
525
+ _cache[60] || (_cache[60] = createBaseVNode("div", { class: "panel-header" }, [
526
+ createBaseVNode("h3", null, "Properties")
527
+ ], -1)),
528
+ createBaseVNode("div", _hoisted_2$8, [
529
+ _ctx.component ? (openBlock(), createElementBlock("div", _hoisted_3$7, [
530
+ createBaseVNode("div", _hoisted_4$6, [
531
+ createBaseVNode("i", {
532
+ class: normalizeClass(unref(getComponentIcon)(_ctx.component.component_type))
533
+ }, null, 2),
534
+ createBaseVNode("span", null, toDisplayString(_ctx.component.component_type), 1)
535
+ ]),
536
+ createBaseVNode("div", _hoisted_5$4, [
537
+ _cache[24] || (_cache[24] = createBaseVNode("div", { class: "property-group-title" }, "Basic", -1)),
538
+ createBaseVNode("div", _hoisted_6$4, [
539
+ _cache[22] || (_cache[22] = createBaseVNode("label", { class: "property-label" }, [
540
+ createTextVNode("Field Name "),
541
+ createBaseVNode("span", { class: "required" }, "*")
542
+ ], -1)),
543
+ createBaseVNode("input", {
544
+ value: _ctx.component.field_name,
545
+ type: "text",
546
+ class: "property-input",
547
+ placeholder: "field_name",
548
+ onInput: _cache[0] || (_cache[0] = ($event) => updateField("field_name", $event.target.value))
549
+ }, null, 40, _hoisted_7$4)
550
+ ]),
551
+ createBaseVNode("div", _hoisted_8$4, [
552
+ _cache[23] || (_cache[23] = createBaseVNode("label", { class: "property-label" }, "Label", -1)),
553
+ createBaseVNode("input", {
554
+ value: _ctx.component.label,
555
+ type: "text",
556
+ class: "property-input",
557
+ placeholder: "Display Label",
558
+ onInput: _cache[1] || (_cache[1] = ($event) => updateField("label", $event.target.value))
559
+ }, null, 40, _hoisted_9$4)
560
+ ])
561
+ ]),
562
+ _ctx.component.component_type === "TextInput" ? (openBlock(), createElementBlock("div", _hoisted_10$4, [
563
+ _cache[27] || (_cache[27] = createBaseVNode("div", { class: "property-group-title" }, "Text Options", -1)),
564
+ createBaseVNode("div", _hoisted_11$4, [
565
+ _cache[25] || (_cache[25] = createBaseVNode("label", { class: "property-label" }, "Default Value", -1)),
566
+ createBaseVNode("input", {
567
+ value: _ctx.component.default,
568
+ type: "text",
569
+ class: "property-input",
570
+ placeholder: "Default value",
571
+ onInput: _cache[2] || (_cache[2] = ($event) => updateField("default", $event.target.value))
572
+ }, null, 40, _hoisted_12$3)
573
+ ]),
574
+ createBaseVNode("div", _hoisted_13$3, [
575
+ _cache[26] || (_cache[26] = createBaseVNode("label", { class: "property-label" }, "Placeholder", -1)),
576
+ createBaseVNode("input", {
577
+ value: _ctx.component.placeholder,
578
+ type: "text",
579
+ class: "property-input",
580
+ placeholder: "Placeholder text",
581
+ onInput: _cache[3] || (_cache[3] = ($event) => updateField("placeholder", $event.target.value))
582
+ }, null, 40, _hoisted_14$3)
583
+ ])
584
+ ])) : createCommentVNode("", true),
585
+ _ctx.component.component_type === "NumericInput" ? (openBlock(), createElementBlock("div", _hoisted_15$3, [
586
+ _cache[31] || (_cache[31] = createBaseVNode("div", { class: "property-group-title" }, "Number Options", -1)),
587
+ createBaseVNode("div", _hoisted_16$3, [
588
+ _cache[28] || (_cache[28] = createBaseVNode("label", { class: "property-label" }, "Default Value", -1)),
589
+ createBaseVNode("input", {
590
+ value: _ctx.component.default,
591
+ type: "number",
592
+ class: "property-input",
593
+ onInput: _cache[4] || (_cache[4] = ($event) => updateField("default", Number($event.target.value)))
594
+ }, null, 40, _hoisted_17$2)
595
+ ]),
596
+ createBaseVNode("div", _hoisted_18$2, [
597
+ _cache[29] || (_cache[29] = createBaseVNode("label", { class: "property-label" }, "Min Value", -1)),
598
+ createBaseVNode("input", {
599
+ value: _ctx.component.min_value,
600
+ type: "number",
601
+ class: "property-input",
602
+ onInput: _cache[5] || (_cache[5] = ($event) => updateField("min_value", Number($event.target.value)))
603
+ }, null, 40, _hoisted_19$1)
604
+ ]),
605
+ createBaseVNode("div", _hoisted_20, [
606
+ _cache[30] || (_cache[30] = createBaseVNode("label", { class: "property-label" }, "Max Value", -1)),
607
+ createBaseVNode("input", {
608
+ value: _ctx.component.max_value,
609
+ type: "number",
610
+ class: "property-input",
611
+ onInput: _cache[6] || (_cache[6] = ($event) => updateField("max_value", Number($event.target.value)))
612
+ }, null, 40, _hoisted_21)
613
+ ])
614
+ ])) : createCommentVNode("", true),
615
+ _ctx.component.component_type === "ToggleSwitch" ? (openBlock(), createElementBlock("div", _hoisted_22, [
616
+ _cache[34] || (_cache[34] = createBaseVNode("div", { class: "property-group-title" }, "Toggle Options", -1)),
617
+ createBaseVNode("div", _hoisted_23, [
618
+ _cache[32] || (_cache[32] = createBaseVNode("label", { class: "property-label" }, "Default Value", -1)),
619
+ createBaseVNode("input", {
620
+ checked: _ctx.component.default,
621
+ type: "checkbox",
622
+ class: "property-checkbox",
623
+ onChange: _cache[7] || (_cache[7] = ($event) => updateField("default", $event.target.checked))
624
+ }, null, 40, _hoisted_24)
625
+ ]),
626
+ createBaseVNode("div", _hoisted_25, [
627
+ _cache[33] || (_cache[33] = createBaseVNode("label", { class: "property-label" }, "Description", -1)),
628
+ createBaseVNode("input", {
629
+ value: _ctx.component.description,
630
+ type: "text",
631
+ class: "property-input",
632
+ placeholder: "Toggle description",
633
+ onInput: _cache[8] || (_cache[8] = ($event) => updateField("description", $event.target.value))
634
+ }, null, 40, _hoisted_26)
635
+ ])
636
+ ])) : createCommentVNode("", true),
637
+ _ctx.component.component_type === "SingleSelect" ? (openBlock(), createElementBlock("div", _hoisted_27, [
638
+ _cache[38] || (_cache[38] = createBaseVNode("div", { class: "property-group-title" }, "Select Options", -1)),
639
+ createBaseVNode("div", _hoisted_28, [
640
+ _cache[36] || (_cache[36] = createBaseVNode("label", { class: "property-label" }, "Options Source", -1)),
641
+ createBaseVNode("select", {
642
+ value: _ctx.component.options_source,
643
+ class: "property-input",
644
+ onChange: _cache[9] || (_cache[9] = ($event) => updateField("options_source", $event.target.value))
645
+ }, _cache[35] || (_cache[35] = [
646
+ createBaseVNode("option", { value: "static" }, "Static Options", -1),
647
+ createBaseVNode("option", { value: "incoming_columns" }, "Incoming Columns", -1)
648
+ ]), 40, _hoisted_29)
649
+ ]),
650
+ _ctx.component.options_source === "static" ? (openBlock(), createElementBlock("div", _hoisted_30, [
651
+ _cache[37] || (_cache[37] = createBaseVNode("label", { class: "property-label" }, "Options (comma-separated)", -1)),
652
+ createBaseVNode("input", {
653
+ value: _ctx.component.options_string,
654
+ type: "text",
655
+ class: "property-input",
656
+ placeholder: "option1, option2, option3",
657
+ onInput: _cache[10] || (_cache[10] = ($event) => updateField("options_string", $event.target.value))
658
+ }, null, 40, _hoisted_31)
659
+ ])) : createCommentVNode("", true)
660
+ ])) : createCommentVNode("", true),
661
+ _ctx.component.component_type === "MultiSelect" ? (openBlock(), createElementBlock("div", _hoisted_32, [
662
+ _cache[42] || (_cache[42] = createBaseVNode("div", { class: "property-group-title" }, "Select Options", -1)),
663
+ createBaseVNode("div", _hoisted_33, [
664
+ _cache[40] || (_cache[40] = createBaseVNode("label", { class: "property-label" }, "Options Source", -1)),
665
+ createBaseVNode("select", {
666
+ value: _ctx.component.options_source,
667
+ class: "property-input",
668
+ onChange: _cache[11] || (_cache[11] = ($event) => updateField("options_source", $event.target.value))
669
+ }, _cache[39] || (_cache[39] = [
670
+ createBaseVNode("option", { value: "static" }, "Static Options", -1),
671
+ createBaseVNode("option", { value: "incoming_columns" }, "Incoming Columns", -1)
672
+ ]), 40, _hoisted_34)
673
+ ]),
674
+ _ctx.component.options_source === "static" ? (openBlock(), createElementBlock("div", _hoisted_35, [
675
+ _cache[41] || (_cache[41] = createBaseVNode("label", { class: "property-label" }, "Options (comma-separated)", -1)),
676
+ createBaseVNode("input", {
677
+ value: _ctx.component.options_string,
678
+ type: "text",
679
+ class: "property-input",
680
+ placeholder: "option1, option2, option3",
681
+ onInput: _cache[12] || (_cache[12] = ($event) => updateField("options_string", $event.target.value))
682
+ }, null, 40, _hoisted_36)
683
+ ])) : createCommentVNode("", true)
684
+ ])) : createCommentVNode("", true),
685
+ _ctx.component.component_type === "ColumnSelector" ? (openBlock(), createElementBlock("div", _hoisted_37, [
686
+ _cache[47] || (_cache[47] = createBaseVNode("div", { class: "property-group-title" }, "Column Options", -1)),
687
+ createBaseVNode("div", _hoisted_38, [
688
+ _cache[43] || (_cache[43] = createBaseVNode("label", { class: "property-label" }, "Required", -1)),
689
+ createBaseVNode("input", {
690
+ checked: _ctx.component.required,
691
+ type: "checkbox",
692
+ class: "property-checkbox",
693
+ onChange: _cache[13] || (_cache[13] = ($event) => updateField("required", $event.target.checked))
694
+ }, null, 40, _hoisted_39)
695
+ ]),
696
+ createBaseVNode("div", _hoisted_40, [
697
+ _cache[44] || (_cache[44] = createBaseVNode("label", { class: "property-label" }, "Multiple Selection", -1)),
698
+ createBaseVNode("input", {
699
+ checked: _ctx.component.multiple,
700
+ type: "checkbox",
701
+ class: "property-checkbox",
702
+ onChange: _cache[14] || (_cache[14] = ($event) => updateField("multiple", $event.target.checked))
703
+ }, null, 40, _hoisted_41)
704
+ ]),
705
+ createBaseVNode("div", _hoisted_42, [
706
+ _cache[46] || (_cache[46] = createBaseVNode("label", { class: "property-label" }, "Data Types Filter", -1)),
707
+ createBaseVNode("select", {
708
+ value: _ctx.component.data_types,
709
+ class: "property-input",
710
+ onChange: _cache[15] || (_cache[15] = ($event) => updateField("data_types", $event.target.value))
711
+ }, _cache[45] || (_cache[45] = [
712
+ createBaseVNode("option", { value: "ALL" }, "All Types", -1),
713
+ createBaseVNode("option", { value: "numeric" }, "Numeric", -1),
714
+ createBaseVNode("option", { value: "string" }, "String", -1),
715
+ createBaseVNode("option", { value: "temporal" }, "Temporal", -1)
716
+ ]), 40, _hoisted_43)
717
+ ])
718
+ ])) : createCommentVNode("", true),
719
+ _ctx.component.component_type === "SliderInput" ? (openBlock(), createElementBlock("div", _hoisted_44, [
720
+ _cache[51] || (_cache[51] = createBaseVNode("div", { class: "property-group-title" }, "Slider Options", -1)),
721
+ createBaseVNode("div", _hoisted_45, [
722
+ _cache[48] || (_cache[48] = createBaseVNode("label", { class: "property-label" }, [
723
+ createTextVNode("Min Value "),
724
+ createBaseVNode("span", { class: "required" }, "*")
725
+ ], -1)),
726
+ createBaseVNode("input", {
727
+ value: _ctx.component.min_value,
728
+ type: "number",
729
+ class: "property-input",
730
+ onInput: _cache[16] || (_cache[16] = ($event) => updateField("min_value", Number($event.target.value)))
731
+ }, null, 40, _hoisted_46)
732
+ ]),
733
+ createBaseVNode("div", _hoisted_47, [
734
+ _cache[49] || (_cache[49] = createBaseVNode("label", { class: "property-label" }, [
735
+ createTextVNode("Max Value "),
736
+ createBaseVNode("span", { class: "required" }, "*")
737
+ ], -1)),
738
+ createBaseVNode("input", {
739
+ value: _ctx.component.max_value,
740
+ type: "number",
741
+ class: "property-input",
742
+ onInput: _cache[17] || (_cache[17] = ($event) => updateField("max_value", Number($event.target.value)))
743
+ }, null, 40, _hoisted_48)
744
+ ]),
745
+ createBaseVNode("div", _hoisted_49, [
746
+ _cache[50] || (_cache[50] = createBaseVNode("label", { class: "property-label" }, "Step", -1)),
747
+ createBaseVNode("input", {
748
+ value: _ctx.component.step,
749
+ type: "number",
750
+ class: "property-input",
751
+ onInput: _cache[18] || (_cache[18] = ($event) => updateField("step", Number($event.target.value)))
752
+ }, null, 40, _hoisted_50)
753
+ ])
754
+ ])) : createCommentVNode("", true),
755
+ _ctx.component.component_type === "SecretSelector" ? (openBlock(), createElementBlock("div", _hoisted_51, [
756
+ _cache[56] || (_cache[56] = createBaseVNode("div", { class: "property-group-title" }, "Secret Options", -1)),
757
+ createBaseVNode("div", _hoisted_52, [
758
+ _cache[52] || (_cache[52] = createBaseVNode("label", { class: "property-label" }, "Required", -1)),
759
+ createBaseVNode("input", {
760
+ checked: _ctx.component.required,
761
+ type: "checkbox",
762
+ class: "property-checkbox",
763
+ onChange: _cache[19] || (_cache[19] = ($event) => updateField("required", $event.target.checked))
764
+ }, null, 40, _hoisted_53)
765
+ ]),
766
+ createBaseVNode("div", _hoisted_54, [
767
+ _cache[53] || (_cache[53] = createBaseVNode("label", { class: "property-label" }, "Description", -1)),
768
+ createBaseVNode("input", {
769
+ value: _ctx.component.description,
770
+ type: "text",
771
+ class: "property-input",
772
+ placeholder: "Help text for the user",
773
+ onInput: _cache[20] || (_cache[20] = ($event) => updateField("description", $event.target.value))
774
+ }, null, 40, _hoisted_55)
775
+ ]),
776
+ createBaseVNode("div", _hoisted_56, [
777
+ _cache[54] || (_cache[54] = createBaseVNode("label", { class: "property-label" }, "Name Prefix Filter", -1)),
778
+ createBaseVNode("input", {
779
+ value: _ctx.component.name_prefix,
780
+ type: "text",
781
+ class: "property-input",
782
+ placeholder: "e.g. API_KEY_",
783
+ onInput: _cache[21] || (_cache[21] = ($event) => updateField("name_prefix", $event.target.value))
784
+ }, null, 40, _hoisted_57),
785
+ _cache[55] || (_cache[55] = createBaseVNode("span", { class: "field-hint" }, "Only show secrets starting with this prefix", -1))
786
+ ])
787
+ ])) : createCommentVNode("", true),
788
+ createBaseVNode("div", { class: "action-section" }, [
789
+ createBaseVNode("button", {
790
+ class: "action-btn",
791
+ onClick: insertVariable
792
+ }, _cache[57] || (_cache[57] = [
793
+ createBaseVNode("i", { class: "fa-solid fa-code" }, null, -1),
794
+ createTextVNode(" Insert Variable ")
795
+ ])),
796
+ _cache[58] || (_cache[58] = createBaseVNode("span", { class: "field-hint" }, "Add typed variable to process method", -1))
797
+ ])
798
+ ])) : (openBlock(), createElementBlock("div", _hoisted_58, _cache[59] || (_cache[59] = [
799
+ createBaseVNode("i", { class: "fa-solid fa-mouse-pointer" }, null, -1),
800
+ createBaseVNode("p", null, "Select a component to edit its properties", -1)
801
+ ])))
802
+ ])
803
+ ]);
804
+ };
805
+ }
806
+ });
807
+ const PropertyEditor_vue_vue_type_style_index_0_scoped_7ea3df75_lang = "";
808
+ const PropertyEditor = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["__scopeId", "data-v-7ea3df75"]]);
809
+ const _hoisted_1$7 = { class: "modal-header" };
810
+ const _hoisted_2$7 = { class: "modal-actions" };
811
+ const _sfc_main$7 = /* @__PURE__ */ defineComponent({
812
+ __name: "ProcessCodeHelpModal",
813
+ props: {
814
+ show: { type: Boolean }
815
+ },
816
+ emits: ["close"],
817
+ setup(__props, { emit: __emit }) {
818
+ const emit = __emit;
819
+ return (_ctx, _cache) => {
820
+ return _ctx.show ? (openBlock(), createElementBlock("div", {
821
+ key: 0,
822
+ class: "modal-overlay",
823
+ onClick: _cache[3] || (_cache[3] = ($event) => emit("close"))
824
+ }, [
825
+ createBaseVNode("div", {
826
+ class: "modal-container modal-large",
827
+ onClick: _cache[2] || (_cache[2] = withModifiers(() => {
828
+ }, ["stop"]))
829
+ }, [
830
+ createBaseVNode("div", _hoisted_1$7, [
831
+ _cache[5] || (_cache[5] = createBaseVNode("h3", { class: "modal-title" }, [
832
+ createBaseVNode("i", { class: "fa-solid fa-circle-question" }),
833
+ createTextVNode(" Process Method Help ")
834
+ ], -1)),
835
+ createBaseVNode("button", {
836
+ class: "modal-close",
837
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
838
+ }, _cache[4] || (_cache[4] = [
839
+ createBaseVNode("i", { class: "fa-solid fa-times" }, null, -1)
840
+ ]))
841
+ ]),
842
+ _cache[6] || (_cache[6] = createStaticVNode('<div class="modal-content" data-v-5991e8aa><div class="help-section" data-v-5991e8aa><h4 data-v-5991e8aa>Overview</h4><p data-v-5991e8aa> The process method is where you write your data transformation logic. It receives input LazyFrames from connected nodes and returns a transformed LazyFrame. </p></div><div class="help-section" data-v-5991e8aa><h4 data-v-5991e8aa>Method Signature</h4><pre class="help-code" data-v-5991e8aa><code data-v-5991e8aa>def process(self, *inputs: pl.LazyFrame) -&gt; pl.LazyFrame:</code></pre><ul class="help-list" data-v-5991e8aa><li data-v-5991e8aa><code data-v-5991e8aa>inputs</code> - Tuple of input LazyFrames from connected nodes</li><li data-v-5991e8aa><code data-v-5991e8aa>inputs[0]</code> - First input (most common)</li><li data-v-5991e8aa><code data-v-5991e8aa>inputs[1]</code> - Second input (for joins, etc.)</li></ul></div><div class="help-section" data-v-5991e8aa><h4 data-v-5991e8aa>Accessing Settings</h4><p data-v-5991e8aa>Access user-configured values from your UI components:</p><pre class="help-code" data-v-5991e8aa><code data-v-5991e8aa>self.settings_schema.section_name.component_name.value</code></pre><p class="help-note" data-v-5991e8aa><i class="fa-solid fa-lightbulb" data-v-5991e8aa></i> Use autocomplete by typing <code data-v-5991e8aa>self.</code> to navigate the settings schema. </p></div><div class="help-section" data-v-5991e8aa><h4 data-v-5991e8aa>Working with Secrets</h4><p data-v-5991e8aa>For SecretSelector components, access the decrypted value:</p><pre class="help-code" data-v-5991e8aa><code data-v-5991e8aa># Get the SecretStr object\nsecret = self.settings_schema.section.api_key.secret_value\n\n# Get the actual decrypted string value\napi_key = secret.get_secret_value()</code></pre></div><div class="help-section" data-v-5991e8aa><h4 data-v-5991e8aa>Common Patterns</h4><div class="pattern-grid" data-v-5991e8aa><div class="pattern-item" data-v-5991e8aa><h5 data-v-5991e8aa>Filter Rows</h5><pre class="help-code-small" data-v-5991e8aa><code data-v-5991e8aa>lf = inputs[0]\nreturn lf.filter(pl.col(&quot;column&quot;) &gt; 10)</code></pre></div><div class="pattern-item" data-v-5991e8aa><h5 data-v-5991e8aa>Select Columns</h5><pre class="help-code-small" data-v-5991e8aa><code data-v-5991e8aa>lf = inputs[0]\nreturn lf.select([&quot;col1&quot;, &quot;col2&quot;])</code></pre></div><div class="pattern-item" data-v-5991e8aa><h5 data-v-5991e8aa>Add New Column</h5><pre class="help-code-small" data-v-5991e8aa><code data-v-5991e8aa>lf = inputs[0]\nreturn lf.with_columns(\n pl.col(&quot;a&quot;).alias(&quot;new_col&quot;)\n)</code></pre></div><div class="pattern-item" data-v-5991e8aa><h5 data-v-5991e8aa>Group &amp; Aggregate</h5><pre class="help-code-small" data-v-5991e8aa><code data-v-5991e8aa>lf = inputs[0]\nreturn lf.group_by(&quot;category&quot;).agg(\n pl.col(&quot;value&quot;).sum()\n)</code></pre></div></div></div><div class="help-section" data-v-5991e8aa><h4 data-v-5991e8aa>Using Settings in Code</h4><pre class="help-code" data-v-5991e8aa><code data-v-5991e8aa># Example: Using a TextInput value\ncolumn_name = self.settings_schema.options.column_name.value\nlf = inputs[0]\nreturn lf.select(pl.col(column_name))\n\n# Example: Using a ColumnSelector value\nselected_columns = self.settings_schema.columns.selected.value\nreturn lf.select(selected_columns)</code></pre></div></div>', 1)),
843
+ createBaseVNode("div", _hoisted_2$7, [
844
+ createBaseVNode("button", {
845
+ class: "btn btn-primary",
846
+ onClick: _cache[1] || (_cache[1] = ($event) => emit("close"))
847
+ }, "Close")
848
+ ])
849
+ ])
850
+ ])) : createCommentVNode("", true);
851
+ };
852
+ }
853
+ });
854
+ const ProcessCodeHelpModal_vue_vue_type_style_index_0_scoped_5991e8aa_lang = "";
855
+ const ProcessCodeHelpModal = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-5991e8aa"]]);
856
+ const _hoisted_1$6 = { class: "code-editor-section" };
857
+ const _hoisted_2$6 = { class: "code-editor-header" };
858
+ const _hoisted_3$6 = { class: "code-editor-wrapper" };
859
+ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
860
+ __name: "ProcessCodeEditor",
861
+ props: {
862
+ modelValue: {},
863
+ extensions: {}
864
+ },
865
+ emits: ["update:modelValue"],
866
+ setup(__props, { emit: __emit }) {
867
+ const emit = __emit;
868
+ const showHelp = ref(false);
869
+ return (_ctx, _cache) => {
870
+ return openBlock(), createElementBlock("div", _hoisted_1$6, [
871
+ createBaseVNode("div", _hoisted_2$6, [
872
+ _cache[4] || (_cache[4] = createBaseVNode("h4", null, "Process Method", -1)),
873
+ createBaseVNode("button", {
874
+ class: "help-btn",
875
+ title: "Show help",
876
+ onClick: _cache[0] || (_cache[0] = ($event) => showHelp.value = true)
877
+ }, _cache[3] || (_cache[3] = [
878
+ createBaseVNode("i", { class: "fa-solid fa-circle-question" }, null, -1),
879
+ createBaseVNode("span", null, "Help", -1)
880
+ ]))
881
+ ]),
882
+ _cache[5] || (_cache[5] = createBaseVNode("p", { class: "code-hint" }, [
883
+ createTextVNode(" Write your data transformation logic. Access settings via "),
884
+ createBaseVNode("code", null, "self.settings_schema.section_name.component_name.value")
885
+ ], -1)),
886
+ createBaseVNode("div", _hoisted_3$6, [
887
+ createVNode(unref(T), {
888
+ "model-value": _ctx.modelValue,
889
+ placeholder: "# Write your process logic here...",
890
+ style: { height: "300px" },
891
+ autofocus: false,
892
+ "indent-with-tab": false,
893
+ "tab-size": 4,
894
+ extensions: _ctx.extensions,
895
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => emit("update:modelValue", $event))
896
+ }, null, 8, ["model-value", "extensions"])
897
+ ]),
898
+ createVNode(ProcessCodeHelpModal, {
899
+ show: showHelp.value,
900
+ onClose: _cache[2] || (_cache[2] = ($event) => showHelp.value = false)
901
+ }, null, 8, ["show"])
902
+ ]);
903
+ };
904
+ }
905
+ });
906
+ const ProcessCodeEditor_vue_vue_type_style_index_0_scoped_7bd9927f_lang = "";
907
+ const ProcessCodeEditor = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__scopeId", "data-v-7bd9927f"]]);
908
+ const _hoisted_1$5 = { class: "modal-header" };
909
+ const _hoisted_2$5 = { class: "modal-content" };
910
+ const _hoisted_3$5 = { class: "code-preview" };
911
+ const _hoisted_4$5 = { class: "modal-actions" };
912
+ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
913
+ __name: "CodePreviewModal",
914
+ props: {
915
+ show: { type: Boolean },
916
+ code: {}
917
+ },
918
+ emits: ["close"],
919
+ setup(__props, { emit: __emit }) {
920
+ const emit = __emit;
921
+ function copyCode() {
922
+ navigator.clipboard.writeText(arguments[0]);
923
+ alert("Code copied to clipboard!");
924
+ }
925
+ return (_ctx, _cache) => {
926
+ return _ctx.show ? (openBlock(), createElementBlock("div", {
927
+ key: 0,
928
+ class: "modal-overlay",
929
+ onClick: _cache[3] || (_cache[3] = ($event) => emit("close"))
930
+ }, [
931
+ createBaseVNode("div", {
932
+ class: "modal-container modal-large",
933
+ onClick: _cache[2] || (_cache[2] = withModifiers(() => {
934
+ }, ["stop"]))
935
+ }, [
936
+ createBaseVNode("div", _hoisted_1$5, [
937
+ _cache[5] || (_cache[5] = createBaseVNode("h3", { class: "modal-title" }, "Generated Python Code", -1)),
938
+ createBaseVNode("button", {
939
+ class: "modal-close",
940
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
941
+ }, _cache[4] || (_cache[4] = [
942
+ createBaseVNode("i", { class: "fa-solid fa-times" }, null, -1)
943
+ ]))
944
+ ]),
945
+ createBaseVNode("div", _hoisted_2$5, [
946
+ createBaseVNode("div", _hoisted_3$5, [
947
+ createBaseVNode("pre", null, [
948
+ createBaseVNode("code", null, toDisplayString(_ctx.code), 1)
949
+ ])
950
+ ])
951
+ ]),
952
+ createBaseVNode("div", _hoisted_4$5, [
953
+ createBaseVNode("button", {
954
+ class: "btn btn-secondary",
955
+ onClick: copyCode
956
+ }, _cache[6] || (_cache[6] = [
957
+ createBaseVNode("i", { class: "fa-solid fa-copy" }, null, -1),
958
+ createTextVNode(" Copy Code ")
959
+ ])),
960
+ createBaseVNode("button", {
961
+ class: "btn btn-primary",
962
+ onClick: _cache[1] || (_cache[1] = ($event) => emit("close"))
963
+ }, "Close")
964
+ ])
965
+ ])
966
+ ])) : createCommentVNode("", true);
967
+ };
968
+ }
969
+ });
970
+ const CodePreviewModal_vue_vue_type_style_index_0_scoped_9323159f_lang = "";
971
+ const CodePreviewModal = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-9323159f"]]);
972
+ const _hoisted_1$4 = { class: "modal-header modal-header-error" };
973
+ const _hoisted_2$4 = { class: "modal-content" };
974
+ const _hoisted_3$4 = { class: "validation-errors-list" };
975
+ const _hoisted_4$4 = { class: "modal-actions" };
976
+ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
977
+ __name: "ValidationModal",
978
+ props: {
979
+ show: { type: Boolean },
980
+ errors: {}
981
+ },
982
+ emits: ["close"],
983
+ setup(__props, { emit: __emit }) {
984
+ const emit = __emit;
985
+ return (_ctx, _cache) => {
986
+ return _ctx.show ? (openBlock(), createElementBlock("div", {
987
+ key: 0,
988
+ class: "modal-overlay",
989
+ onClick: _cache[3] || (_cache[3] = ($event) => emit("close"))
990
+ }, [
991
+ createBaseVNode("div", {
992
+ class: "modal-container",
993
+ onClick: _cache[2] || (_cache[2] = withModifiers(() => {
994
+ }, ["stop"]))
995
+ }, [
996
+ createBaseVNode("div", _hoisted_1$4, [
997
+ _cache[5] || (_cache[5] = createBaseVNode("h3", { class: "modal-title" }, [
998
+ createBaseVNode("i", { class: "fa-solid fa-triangle-exclamation" }),
999
+ createTextVNode(" Validation Errors ")
1000
+ ], -1)),
1001
+ createBaseVNode("button", {
1002
+ class: "modal-close",
1003
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
1004
+ }, _cache[4] || (_cache[4] = [
1005
+ createBaseVNode("i", { class: "fa-solid fa-times" }, null, -1)
1006
+ ]))
1007
+ ]),
1008
+ createBaseVNode("div", _hoisted_2$4, [
1009
+ _cache[7] || (_cache[7] = createBaseVNode("p", { class: "validation-intro" }, "Please fix the following issues before saving:", -1)),
1010
+ createBaseVNode("ul", _hoisted_3$4, [
1011
+ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.errors, (error, index) => {
1012
+ return openBlock(), createElementBlock("li", {
1013
+ key: index,
1014
+ class: "validation-error-item"
1015
+ }, [
1016
+ _cache[6] || (_cache[6] = createBaseVNode("i", { class: "fa-solid fa-circle-xmark" }, null, -1)),
1017
+ createTextVNode(" " + toDisplayString(error.message), 1)
1018
+ ]);
1019
+ }), 128))
1020
+ ])
1021
+ ]),
1022
+ createBaseVNode("div", _hoisted_4$4, [
1023
+ createBaseVNode("button", {
1024
+ class: "btn btn-primary",
1025
+ onClick: _cache[1] || (_cache[1] = ($event) => emit("close"))
1026
+ }, "OK")
1027
+ ])
1028
+ ])
1029
+ ])) : createCommentVNode("", true);
1030
+ };
1031
+ }
1032
+ });
1033
+ const ValidationModal_vue_vue_type_style_index_0_scoped_a56bfe3f_lang = "";
1034
+ const ValidationModal = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-a56bfe3f"]]);
1035
+ const _hoisted_1$3 = { class: "modal-header" };
1036
+ const _hoisted_2$3 = { class: "modal-title" };
1037
+ const _hoisted_3$3 = { class: "modal-content" };
1038
+ const _hoisted_4$3 = {
1039
+ key: 0,
1040
+ class: "node-code-view"
1041
+ };
1042
+ const _hoisted_5$3 = {
1043
+ key: 0,
1044
+ class: "loading-indicator"
1045
+ };
1046
+ const _hoisted_6$3 = {
1047
+ key: 1,
1048
+ class: "empty-nodes"
1049
+ };
1050
+ const _hoisted_7$3 = {
1051
+ key: 2,
1052
+ class: "nodes-grid"
1053
+ };
1054
+ const _hoisted_8$3 = ["onClick"];
1055
+ const _hoisted_9$3 = { class: "node-card-header" };
1056
+ const _hoisted_10$3 = { class: "node-name" };
1057
+ const _hoisted_11$3 = { class: "node-card-body" };
1058
+ const _hoisted_12$2 = { class: "node-category" };
1059
+ const _hoisted_13$2 = { class: "node-description" };
1060
+ const _hoisted_14$2 = { class: "node-card-footer" };
1061
+ const _hoisted_15$2 = { class: "node-file" };
1062
+ const _hoisted_16$2 = { class: "modal-actions" };
1063
+ const _hoisted_17$1 = { class: "modal-header modal-header-error" };
1064
+ const _hoisted_18$1 = { class: "modal-content" };
1065
+ const _hoisted_19 = { class: "modal-actions" };
1066
+ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
1067
+ __name: "NodeBrowserModal",
1068
+ props: {
1069
+ show: { type: Boolean },
1070
+ nodes: {},
1071
+ loading: { type: Boolean },
1072
+ viewingNodeCode: {},
1073
+ viewingNodeName: {},
1074
+ showDeleteConfirm: { type: Boolean },
1075
+ readOnlyExtensions: {}
1076
+ },
1077
+ emits: ["close", "viewNode", "back", "confirmDelete", "cancelDelete", "delete"],
1078
+ setup(__props, { emit: __emit }) {
1079
+ const emit = __emit;
1080
+ return (_ctx, _cache) => {
1081
+ return openBlock(), createElementBlock(Fragment, null, [
1082
+ _ctx.show ? (openBlock(), createElementBlock("div", {
1083
+ key: 0,
1084
+ class: "modal-overlay",
1085
+ onClick: _cache[5] || (_cache[5] = ($event) => emit("close"))
1086
+ }, [
1087
+ createBaseVNode("div", {
1088
+ class: "modal-container modal-large",
1089
+ onClick: _cache[4] || (_cache[4] = withModifiers(() => {
1090
+ }, ["stop"]))
1091
+ }, [
1092
+ createBaseVNode("div", _hoisted_1$3, [
1093
+ createBaseVNode("h3", _hoisted_2$3, [
1094
+ _cache[11] || (_cache[11] = createBaseVNode("i", { class: "fa-solid fa-folder-open" }, null, -1)),
1095
+ createTextVNode(" " + toDisplayString(_ctx.viewingNodeCode ? _ctx.viewingNodeName : "Browse Custom Nodes"), 1)
1096
+ ]),
1097
+ createBaseVNode("button", {
1098
+ class: "modal-close",
1099
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
1100
+ }, _cache[12] || (_cache[12] = [
1101
+ createBaseVNode("i", { class: "fa-solid fa-times" }, null, -1)
1102
+ ]))
1103
+ ]),
1104
+ createBaseVNode("div", _hoisted_3$3, [
1105
+ _ctx.viewingNodeCode ? (openBlock(), createElementBlock("div", _hoisted_4$3, [
1106
+ createVNode(unref(T), {
1107
+ "model-value": _ctx.viewingNodeCode,
1108
+ style: { height: "auto", maxHeight: "calc(80vh - 180px)" },
1109
+ autofocus: false,
1110
+ "indent-with-tab": false,
1111
+ "tab-size": 4,
1112
+ extensions: _ctx.readOnlyExtensions
1113
+ }, null, 8, ["model-value", "extensions"])
1114
+ ])) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
1115
+ _ctx.loading ? (openBlock(), createElementBlock("div", _hoisted_5$3, _cache[13] || (_cache[13] = [
1116
+ createBaseVNode("i", { class: "fa-solid fa-spinner fa-spin" }, null, -1),
1117
+ createTextVNode(" Loading custom nodes... ")
1118
+ ]))) : _ctx.nodes.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_6$3, _cache[14] || (_cache[14] = [
1119
+ createBaseVNode("i", { class: "fa-solid fa-folder-open" }, null, -1),
1120
+ createBaseVNode("p", null, "No custom nodes found", -1),
1121
+ createBaseVNode("p", { class: "empty-hint" }, "Save a node to see it here", -1)
1122
+ ]))) : (openBlock(), createElementBlock("div", _hoisted_7$3, [
1123
+ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.nodes, (node) => {
1124
+ return openBlock(), createElementBlock("div", {
1125
+ key: node.file_name,
1126
+ class: "node-card",
1127
+ onClick: ($event) => emit("viewNode", node.file_name)
1128
+ }, [
1129
+ createBaseVNode("div", _hoisted_9$3, [
1130
+ _cache[15] || (_cache[15] = createBaseVNode("i", { class: "fa-solid fa-puzzle-piece" }, null, -1)),
1131
+ createBaseVNode("span", _hoisted_10$3, toDisplayString(node.node_name || node.file_name), 1)
1132
+ ]),
1133
+ createBaseVNode("div", _hoisted_11$3, [
1134
+ createBaseVNode("span", _hoisted_12$2, toDisplayString(node.node_category), 1),
1135
+ createBaseVNode("p", _hoisted_13$2, toDisplayString(node.intro || "No description"), 1)
1136
+ ]),
1137
+ createBaseVNode("div", _hoisted_14$2, [
1138
+ createBaseVNode("span", _hoisted_15$2, toDisplayString(node.file_name), 1)
1139
+ ])
1140
+ ], 8, _hoisted_8$3);
1141
+ }), 128))
1142
+ ]))
1143
+ ], 64))
1144
+ ]),
1145
+ createBaseVNode("div", _hoisted_16$2, [
1146
+ _ctx.viewingNodeCode ? (openBlock(), createElementBlock("button", {
1147
+ key: 0,
1148
+ class: "btn btn-secondary",
1149
+ onClick: _cache[1] || (_cache[1] = ($event) => emit("back"))
1150
+ }, _cache[16] || (_cache[16] = [
1151
+ createBaseVNode("i", { class: "fa-solid fa-arrow-left" }, null, -1),
1152
+ createTextVNode(" Back ")
1153
+ ]))) : createCommentVNode("", true),
1154
+ _ctx.viewingNodeCode ? (openBlock(), createElementBlock("button", {
1155
+ key: 1,
1156
+ class: "btn btn-danger",
1157
+ onClick: _cache[2] || (_cache[2] = ($event) => emit("confirmDelete"))
1158
+ }, _cache[17] || (_cache[17] = [
1159
+ createBaseVNode("i", { class: "fa-solid fa-trash" }, null, -1),
1160
+ createTextVNode(" Delete ")
1161
+ ]))) : createCommentVNode("", true),
1162
+ createBaseVNode("button", {
1163
+ class: "btn btn-secondary",
1164
+ onClick: _cache[3] || (_cache[3] = ($event) => emit("close"))
1165
+ }, toDisplayString(_ctx.viewingNodeCode ? "Close" : "Cancel"), 1)
1166
+ ])
1167
+ ])
1168
+ ])) : createCommentVNode("", true),
1169
+ _ctx.showDeleteConfirm ? (openBlock(), createElementBlock("div", {
1170
+ key: 1,
1171
+ class: "modal-overlay",
1172
+ onClick: _cache[10] || (_cache[10] = ($event) => emit("cancelDelete"))
1173
+ }, [
1174
+ createBaseVNode("div", {
1175
+ class: "modal-container",
1176
+ onClick: _cache[9] || (_cache[9] = withModifiers(() => {
1177
+ }, ["stop"]))
1178
+ }, [
1179
+ createBaseVNode("div", _hoisted_17$1, [
1180
+ _cache[19] || (_cache[19] = createBaseVNode("h3", { class: "modal-title" }, [
1181
+ createBaseVNode("i", { class: "fa-solid fa-triangle-exclamation" }),
1182
+ createTextVNode(" Confirm Delete ")
1183
+ ], -1)),
1184
+ createBaseVNode("button", {
1185
+ class: "modal-close",
1186
+ onClick: _cache[6] || (_cache[6] = ($event) => emit("cancelDelete"))
1187
+ }, _cache[18] || (_cache[18] = [
1188
+ createBaseVNode("i", { class: "fa-solid fa-times" }, null, -1)
1189
+ ]))
1190
+ ]),
1191
+ createBaseVNode("div", _hoisted_18$1, [
1192
+ createBaseVNode("p", null, [
1193
+ _cache[20] || (_cache[20] = createTextVNode(" Are you sure you want to delete ")),
1194
+ createBaseVNode("strong", null, toDisplayString(_ctx.viewingNodeName), 1),
1195
+ _cache[21] || (_cache[21] = createTextVNode("? "))
1196
+ ]),
1197
+ _cache[22] || (_cache[22] = createBaseVNode("p", { class: "delete-warning" }, "This action cannot be undone.", -1))
1198
+ ]),
1199
+ createBaseVNode("div", _hoisted_19, [
1200
+ createBaseVNode("button", {
1201
+ class: "btn btn-secondary",
1202
+ onClick: _cache[7] || (_cache[7] = ($event) => emit("cancelDelete"))
1203
+ }, "Cancel"),
1204
+ createBaseVNode("button", {
1205
+ class: "btn btn-danger",
1206
+ onClick: _cache[8] || (_cache[8] = ($event) => emit("delete"))
1207
+ }, _cache[23] || (_cache[23] = [
1208
+ createBaseVNode("i", { class: "fa-solid fa-trash" }, null, -1),
1209
+ createTextVNode(" Delete ")
1210
+ ]))
1211
+ ])
1212
+ ])
1213
+ ])) : createCommentVNode("", true)
1214
+ ], 64);
1215
+ };
1216
+ }
1217
+ });
1218
+ const NodeBrowserModal_vue_vue_type_style_index_0_scoped_ab27c047_lang = "";
1219
+ const NodeBrowserModal = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-ab27c047"]]);
1220
+ const _hoisted_1$2 = { class: "modal-header" };
1221
+ const _hoisted_2$2 = { class: "modal-content" };
1222
+ const _hoisted_3$2 = { class: "help-tabs" };
1223
+ const _hoisted_4$2 = ["onClick"];
1224
+ const _hoisted_5$2 = { class: "help-tab-content" };
1225
+ const _hoisted_6$2 = {
1226
+ key: 0,
1227
+ class: "tab-panel"
1228
+ };
1229
+ const _hoisted_7$2 = {
1230
+ key: 1,
1231
+ class: "tab-panel"
1232
+ };
1233
+ const _hoisted_8$2 = {
1234
+ key: 2,
1235
+ class: "tab-panel"
1236
+ };
1237
+ const _hoisted_9$2 = {
1238
+ key: 3,
1239
+ class: "tab-panel"
1240
+ };
1241
+ const _hoisted_10$2 = {
1242
+ key: 4,
1243
+ class: "tab-panel"
1244
+ };
1245
+ const _hoisted_11$2 = { class: "modal-actions" };
1246
+ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
1247
+ __name: "NodeDesignerHelpModal",
1248
+ props: {
1249
+ show: { type: Boolean }
1250
+ },
1251
+ emits: ["close"],
1252
+ setup(__props, { emit: __emit }) {
1253
+ const emit = __emit;
1254
+ const activeTab = ref("overview");
1255
+ const tabs = [
1256
+ { id: "overview", label: "Overview", icon: "fa-solid fa-house" },
1257
+ { id: "layout", label: "Layout", icon: "fa-solid fa-table-columns" },
1258
+ { id: "components", label: "Components", icon: "fa-solid fa-puzzle-piece" },
1259
+ { id: "code", label: "Code", icon: "fa-solid fa-code" },
1260
+ { id: "tips", label: "Tips", icon: "fa-solid fa-lightbulb" }
1261
+ ];
1262
+ return (_ctx, _cache) => {
1263
+ return _ctx.show ? (openBlock(), createElementBlock("div", {
1264
+ key: 0,
1265
+ class: "modal-overlay",
1266
+ onClick: _cache[3] || (_cache[3] = ($event) => emit("close"))
1267
+ }, [
1268
+ createBaseVNode("div", {
1269
+ class: "modal-container modal-xl",
1270
+ onClick: _cache[2] || (_cache[2] = withModifiers(() => {
1271
+ }, ["stop"]))
1272
+ }, [
1273
+ createBaseVNode("div", _hoisted_1$2, [
1274
+ _cache[5] || (_cache[5] = createBaseVNode("h3", { class: "modal-title" }, [
1275
+ createBaseVNode("i", { class: "fa-solid fa-circle-question" }),
1276
+ createTextVNode(" Node Designer Guide ")
1277
+ ], -1)),
1278
+ createBaseVNode("button", {
1279
+ class: "modal-close",
1280
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
1281
+ }, _cache[4] || (_cache[4] = [
1282
+ createBaseVNode("i", { class: "fa-solid fa-times" }, null, -1)
1283
+ ]))
1284
+ ]),
1285
+ createBaseVNode("div", _hoisted_2$2, [
1286
+ createBaseVNode("div", _hoisted_3$2, [
1287
+ (openBlock(), createElementBlock(Fragment, null, renderList(tabs, (tab) => {
1288
+ return createBaseVNode("button", {
1289
+ key: tab.id,
1290
+ class: normalizeClass(["help-tab", { active: activeTab.value === tab.id }]),
1291
+ onClick: ($event) => activeTab.value = tab.id
1292
+ }, [
1293
+ createBaseVNode("i", {
1294
+ class: normalizeClass(tab.icon)
1295
+ }, null, 2),
1296
+ createTextVNode(" " + toDisplayString(tab.label), 1)
1297
+ ], 10, _hoisted_4$2);
1298
+ }), 64))
1299
+ ]),
1300
+ createBaseVNode("div", _hoisted_5$2, [
1301
+ activeTab.value === "overview" ? (openBlock(), createElementBlock("div", _hoisted_6$2, _cache[6] || (_cache[6] = [
1302
+ createStaticVNode('<h4 data-v-865a257f>What is the Node Designer?</h4><p data-v-865a257f> The Node Designer allows you to create custom data transformation nodes without writing boilerplate code. Design your node&#39;s UI visually, then write only the transformation logic. </p><div class="feature-grid" data-v-865a257f><div class="feature-card" data-v-865a257f><div class="feature-icon" data-v-865a257f><i class="fa-solid fa-palette" data-v-865a257f></i></div><h5 data-v-865a257f>Visual UI Design</h5><p data-v-865a257f>Drag and drop components to create your node&#39;s settings interface</p></div><div class="feature-card" data-v-865a257f><div class="feature-icon" data-v-865a257f><i class="fa-solid fa-code" data-v-865a257f></i></div><h5 data-v-865a257f>Python Processing</h5><p data-v-865a257f>Write Polars transformation code with full autocomplete support</p></div><div class="feature-card" data-v-865a257f><div class="feature-icon" data-v-865a257f><i class="fa-solid fa-plug" data-v-865a257f></i></div><h5 data-v-865a257f>Instant Integration</h5><p data-v-865a257f>Your custom nodes appear immediately in the flow editor</p></div></div><h4 data-v-865a257f>Quick Start</h4><ol class="steps-list" data-v-865a257f><li data-v-865a257f><strong data-v-865a257f>Set metadata</strong> - Name your node and choose a category</li><li data-v-865a257f><strong data-v-865a257f>Add sections</strong> - Create UI sections to organize your settings</li><li data-v-865a257f><strong data-v-865a257f>Add components</strong> - Drag components from the palette into sections </li><li data-v-865a257f><strong data-v-865a257f>Configure properties</strong> - Select a component to edit its properties </li><li data-v-865a257f><strong data-v-865a257f>Write process code</strong> - Implement your transformation logic</li><li data-v-865a257f><strong data-v-865a257f>Save</strong> - Your node is ready to use!</li></ol>', 5)
1303
+ ]))) : createCommentVNode("", true),
1304
+ activeTab.value === "layout" ? (openBlock(), createElementBlock("div", _hoisted_7$2, _cache[7] || (_cache[7] = [
1305
+ createStaticVNode('<h4 data-v-865a257f>Page Layout</h4><div class="layout-diagram" data-v-865a257f><div class="layout-box palette" data-v-865a257f><span class="layout-label" data-v-865a257f>Component Palette</span><p data-v-865a257f>Drag components from here</p></div><div class="layout-box canvas" data-v-865a257f><span class="layout-label" data-v-865a257f>Design Canvas</span><p data-v-865a257f>Build your node UI here</p></div><div class="layout-box properties" data-v-865a257f><span class="layout-label" data-v-865a257f>Properties</span><p data-v-865a257f>Edit selected component</p></div></div><h4 data-v-865a257f>Component Palette (Left)</h4><p data-v-865a257f> Contains all available UI components. Drag them into a section on the Design Canvas to add them to your node. </p><h4 data-v-865a257f>Design Canvas (Center)</h4><ul class="help-list" data-v-865a257f><li data-v-865a257f><strong data-v-865a257f>Node Metadata</strong> - Set your node&#39;s name, category, title, description, and number of inputs/outputs </li><li data-v-865a257f><strong data-v-865a257f>UI Sections</strong> - Organize your components into collapsible sections </li><li data-v-865a257f><strong data-v-865a257f>Process Method</strong> - Write your Python transformation code</li></ul><h4 data-v-865a257f>Property Editor (Right)</h4><p data-v-865a257f> When you select a component, its properties appear here. Configure labels, defaults, validation rules, and more. </p>', 8)
1306
+ ]))) : createCommentVNode("", true),
1307
+ activeTab.value === "components" ? (openBlock(), createElementBlock("div", _hoisted_8$2, _cache[8] || (_cache[8] = [
1308
+ createStaticVNode('<h4 data-v-865a257f>Available Components</h4><div class="component-list" data-v-865a257f><div class="component-item" data-v-865a257f><div class="component-icon" data-v-865a257f><i class="fa-solid fa-font" data-v-865a257f></i></div><div class="component-info" data-v-865a257f><h5 data-v-865a257f>Text Input</h5><p data-v-865a257f>Single-line text entry for strings, names, or patterns</p><code data-v-865a257f>value: str</code></div></div><div class="component-item" data-v-865a257f><div class="component-icon" data-v-865a257f><i class="fa-solid fa-hashtag" data-v-865a257f></i></div><div class="component-info" data-v-865a257f><h5 data-v-865a257f>Numeric Input</h5><p data-v-865a257f>Number entry with optional min/max validation</p><code data-v-865a257f>value: int | float</code></div></div><div class="component-item" data-v-865a257f><div class="component-icon" data-v-865a257f><i class="fa-solid fa-toggle-on" data-v-865a257f></i></div><div class="component-info" data-v-865a257f><h5 data-v-865a257f>Toggle Switch</h5><p data-v-865a257f>Boolean on/off switch for feature flags</p><code data-v-865a257f>value: bool</code></div></div><div class="component-item" data-v-865a257f><div class="component-icon" data-v-865a257f><i class="fa-solid fa-list" data-v-865a257f></i></div><div class="component-info" data-v-865a257f><h5 data-v-865a257f>Single Select</h5><p data-v-865a257f>Dropdown to select one option from a list</p><code data-v-865a257f>value: str</code></div></div><div class="component-item" data-v-865a257f><div class="component-icon" data-v-865a257f><i class="fa-solid fa-list-check" data-v-865a257f></i></div><div class="component-info" data-v-865a257f><h5 data-v-865a257f>Multi Select</h5><p data-v-865a257f>Select multiple options from a list</p><code data-v-865a257f>value: list[str]</code></div></div><div class="component-item" data-v-865a257f><div class="component-icon" data-v-865a257f><i class="fa-solid fa-table-columns" data-v-865a257f></i></div><div class="component-info" data-v-865a257f><h5 data-v-865a257f>Column Selector</h5><p data-v-865a257f>Select columns from input data (single or multiple)</p><code data-v-865a257f>value: str | list[str]</code></div></div><div class="component-item" data-v-865a257f><div class="component-icon" data-v-865a257f><i class="fa-solid fa-sliders" data-v-865a257f></i></div><div class="component-info" data-v-865a257f><h5 data-v-865a257f>Slider</h5><p data-v-865a257f>Numeric slider with min/max/step</p><code data-v-865a257f>value: int | float</code></div></div><div class="component-item" data-v-865a257f><div class="component-icon" data-v-865a257f><i class="fa-solid fa-key" data-v-865a257f></i></div><div class="component-info" data-v-865a257f><h5 data-v-865a257f>Secret Selector</h5><p data-v-865a257f>Securely access stored secrets (API keys, passwords)</p><code data-v-865a257f>secret_value: SecretStr</code></div></div></div>', 2)
1309
+ ]))) : createCommentVNode("", true),
1310
+ activeTab.value === "code" ? (openBlock(), createElementBlock("div", _hoisted_9$2, _cache[9] || (_cache[9] = [
1311
+ createStaticVNode('<h4 data-v-865a257f>Process Method</h4><p data-v-865a257f>The process method receives input data and returns transformed output:</p><pre class="help-code" data-v-865a257f><code data-v-865a257f>def process(self, *inputs: pl.LazyFrame) -&gt; pl.LazyFrame:\n lf = inputs[0] # First input\n # Your transformation logic here\n return lf</code></pre><h4 data-v-865a257f>Accessing Settings</h4><p data-v-865a257f>Access user-configured values from your UI components:</p><pre class="help-code" data-v-865a257f><code data-v-865a257f># Pattern: self.settings_schema.section_name.component_name.value\ncolumn = self.settings_schema.options.column_name.value\nthreshold = self.settings_schema.filters.min_value.value</code></pre><h4 data-v-865a257f>Working with Secrets</h4><pre class="help-code" data-v-865a257f><code data-v-865a257f># Get SecretStr, then extract the actual value\napi_key: SecretStr = self.settings_schema.auth.api_key.secret_value\nactual_key = api_key.get_secret_value()</code></pre><h4 data-v-865a257f>Keyboard Shortcuts</h4><div class="shortcuts-grid" data-v-865a257f><div class="shortcut" data-v-865a257f><kbd data-v-865a257f>Tab</kbd><span data-v-865a257f>Accept autocomplete / Indent</span></div><div class="shortcut" data-v-865a257f><kbd data-v-865a257f>Shift</kbd>+<kbd data-v-865a257f>Tab</kbd><span data-v-865a257f>Outdent selected lines</span></div><div class="shortcut" data-v-865a257f><kbd data-v-865a257f>Arrow Up/Down</kbd><span data-v-865a257f>Navigate autocomplete suggestions</span></div><div class="shortcut" data-v-865a257f><kbd data-v-865a257f>Escape</kbd><span data-v-865a257f>Close autocomplete menu</span></div><div class="shortcut" data-v-865a257f><kbd data-v-865a257f>Shift</kbd>+<kbd data-v-865a257f>Arrow</kbd><span data-v-865a257f>Extend selection</span></div><div class="shortcut" data-v-865a257f><kbd data-v-865a257f>Ctrl</kbd>+<kbd data-v-865a257f>Shift</kbd>+<kbd data-v-865a257f>Arrow</kbd><span data-v-865a257f>Select by word</span></div></div>', 10)
1312
+ ]))) : createCommentVNode("", true),
1313
+ activeTab.value === "tips" ? (openBlock(), createElementBlock("div", _hoisted_10$2, _cache[10] || (_cache[10] = [
1314
+ createStaticVNode('<h4 data-v-865a257f>Best Practices</h4><div class="tip-card" data-v-865a257f><div class="tip-icon success" data-v-865a257f><i class="fa-solid fa-check" data-v-865a257f></i></div><div class="tip-content" data-v-865a257f><h5 data-v-865a257f>Use descriptive names</h5><p data-v-865a257f> Choose clear variable names in sections (e.g., &quot;filters&quot;, &quot;options&quot;) and components (e.g., &quot;column_name&quot;, &quot;threshold&quot;) </p></div></div><div class="tip-card" data-v-865a257f><div class="tip-icon success" data-v-865a257f><i class="fa-solid fa-check" data-v-865a257f></i></div><div class="tip-content" data-v-865a257f><h5 data-v-865a257f>Group related settings</h5><p data-v-865a257f> Use sections to organize related components together. This creates a better user experience. </p></div></div><div class="tip-card" data-v-865a257f><div class="tip-icon success" data-v-865a257f><i class="fa-solid fa-check" data-v-865a257f></i></div><div class="tip-content" data-v-865a257f><h5 data-v-865a257f>Use Column Selector for dynamic columns</h5><p data-v-865a257f> Instead of hardcoding column names, use ColumnSelector to let users pick columns from their data. </p></div></div><div class="tip-card" data-v-865a257f><div class="tip-icon warning" data-v-865a257f><i class="fa-solid fa-exclamation" data-v-865a257f></i></div><div class="tip-content" data-v-865a257f><h5 data-v-865a257f>Keep process code simple</h5><p data-v-865a257f> Focus on transformation logic. Complex operations should be broken into multiple nodes. </p></div></div><div class="tip-card" data-v-865a257f><div class="tip-icon warning" data-v-865a257f><i class="fa-solid fa-exclamation" data-v-865a257f></i></div><div class="tip-content" data-v-865a257f><h5 data-v-865a257f>Use secrets for sensitive data</h5><p data-v-865a257f> Never hardcode API keys or passwords. Use the Secret Selector component for secure credential access. </p></div></div><h4 data-v-865a257f>Common Patterns</h4><pre class="help-code" data-v-865a257f><code data-v-865a257f># Filter rows\nreturn lf.filter(pl.col(column) &gt; threshold)\n\n# Select and rename\nreturn lf.select([\n pl.col(old_name).alias(new_name)\n])\n\n# Add computed column\nreturn lf.with_columns(\n (pl.col(&quot;a&quot;) + pl.col(&quot;b&quot;)).alias(&quot;sum&quot;)\n)\n\n# Group and aggregate\nreturn lf.group_by(group_col).agg(\n pl.col(value_col).sum().alias(&quot;total&quot;)\n)</code></pre>', 8)
1315
+ ]))) : createCommentVNode("", true)
1316
+ ])
1317
+ ]),
1318
+ createBaseVNode("div", _hoisted_11$2, [
1319
+ createBaseVNode("button", {
1320
+ class: "btn btn-primary",
1321
+ onClick: _cache[1] || (_cache[1] = ($event) => emit("close"))
1322
+ }, "Close")
1323
+ ])
1324
+ ])
1325
+ ])) : createCommentVNode("", true);
1326
+ };
1327
+ }
1328
+ });
1329
+ const NodeDesignerHelpModal_vue_vue_type_style_index_0_scoped_865a257f_lang = "";
1330
+ const NodeDesignerHelpModal = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-865a257f"]]);
1331
+ const _hoisted_1$1 = { class: "icon-selector" };
1332
+ const _hoisted_2$1 = { class: "icon-selector-content" };
1333
+ const _hoisted_3$1 = ["src", "alt"];
1334
+ const _hoisted_4$1 = { class: "icon-name" };
1335
+ const _hoisted_5$1 = {
1336
+ key: 0,
1337
+ class: "icon-dropdown"
1338
+ };
1339
+ const _hoisted_6$1 = { class: "upload-section" };
1340
+ const _hoisted_7$1 = { class: "upload-btn" };
1341
+ const _hoisted_8$1 = {
1342
+ key: 0,
1343
+ class: "icons-section"
1344
+ };
1345
+ const _hoisted_9$1 = { class: "icons-grid" };
1346
+ const _hoisted_10$1 = ["onClick"];
1347
+ const _hoisted_11$1 = ["src", "alt"];
1348
+ const _hoisted_12$1 = { class: "icon-filename" };
1349
+ const _hoisted_13$1 = ["onClick"];
1350
+ const _hoisted_14$1 = { class: "icons-section" };
1351
+ const _hoisted_15$1 = { class: "icons-grid" };
1352
+ const _hoisted_16$1 = ["src"];
1353
+ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1354
+ __name: "IconSelector",
1355
+ props: {
1356
+ modelValue: {}
1357
+ },
1358
+ emits: ["update:modelValue"],
1359
+ setup(__props, { emit: __emit }) {
1360
+ const props = __props;
1361
+ const emit = __emit;
1362
+ const showDropdown = ref(false);
1363
+ const customIcons = ref([]);
1364
+ const loading = ref(false);
1365
+ function toggleDropdown() {
1366
+ showDropdown.value = !showDropdown.value;
1367
+ if (showDropdown.value) {
1368
+ loadIcons();
1369
+ }
1370
+ }
1371
+ async function loadIcons() {
1372
+ loading.value = true;
1373
+ try {
1374
+ const response = await axios.get("/user_defined_components/list-icons");
1375
+ customIcons.value = response.data;
1376
+ } catch (error) {
1377
+ console.error("Failed to load icons:", error);
1378
+ } finally {
1379
+ loading.value = false;
1380
+ }
1381
+ }
1382
+ function selectIcon(iconName) {
1383
+ emit("update:modelValue", iconName);
1384
+ showDropdown.value = false;
1385
+ }
1386
+ async function handleFileUpload(event) {
1387
+ var _a, _b, _c;
1388
+ const target = event.target;
1389
+ const file = (_a = target.files) == null ? void 0 : _a[0];
1390
+ if (!file)
1391
+ return;
1392
+ const formData = new FormData();
1393
+ formData.append("file", file);
1394
+ try {
1395
+ const response = await axios.post("/user_defined_components/upload-icon", formData, {
1396
+ headers: {
1397
+ "Content-Type": "multipart/form-data"
1398
+ }
1399
+ });
1400
+ emit("update:modelValue", response.data.file_name);
1401
+ await loadIcons();
1402
+ } catch (error) {
1403
+ const errorMsg = ((_c = (_b = error.response) == null ? void 0 : _b.data) == null ? void 0 : _c.detail) || error.message || "Failed to upload icon";
1404
+ alert(`Error uploading icon: ${errorMsg}`);
1405
+ }
1406
+ target.value = "";
1407
+ }
1408
+ async function deleteIcon(iconName) {
1409
+ var _a, _b;
1410
+ if (!confirm(`Are you sure you want to delete "${iconName}"?`))
1411
+ return;
1412
+ try {
1413
+ await axios.delete(`/user_defined_components/delete-icon/${iconName}`);
1414
+ if (props.modelValue === iconName) {
1415
+ emit("update:modelValue", "user-defined-icon.png");
1416
+ }
1417
+ await loadIcons();
1418
+ } catch (error) {
1419
+ const errorMsg = ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.detail) || error.message || "Failed to delete icon";
1420
+ alert(`Error deleting icon: ${errorMsg}`);
1421
+ }
1422
+ }
1423
+ function getDisplayUrl(iconName) {
1424
+ return getImageUrl(iconName);
1425
+ }
1426
+ function getCustomIconUrl$1(iconName) {
1427
+ return getCustomIconUrl(iconName);
1428
+ }
1429
+ function getBuiltinIconUrl(iconName) {
1430
+ return new URL((/* @__PURE__ */ Object.assign({ "../../features/designer/assets/icons/Output2.png": __vite_glob_0_0, "../../features/designer/assets/icons/airbyte.png": __vite_glob_0_1, "../../features/designer/assets/icons/cloud_storage_reader.png": __vite_glob_0_2, "../../features/designer/assets/icons/cloud_storage_writer.png": __vite_glob_0_3, "../../features/designer/assets/icons/cross_join.png": __vite_glob_0_4, "../../features/designer/assets/icons/database_reader.svg": __vite_glob_0_5, "../../features/designer/assets/icons/database_writer.svg": __vite_glob_0_6, "../../features/designer/assets/icons/explore_data.png": __vite_glob_0_7, "../../features/designer/assets/icons/external_source.png": __vite_glob_0_8, "../../features/designer/assets/icons/filter.png": __vite_glob_0_9, "../../features/designer/assets/icons/formula.png": __vite_glob_0_10, "../../features/designer/assets/icons/fuzzy_match.png": __vite_glob_0_11, "../../features/designer/assets/icons/google_sheet.png": __vite_glob_0_12, "../../features/designer/assets/icons/graph_solver.png": __vite_glob_0_13, "../../features/designer/assets/icons/group_by.png": __vite_glob_0_14, "../../features/designer/assets/icons/input_data.png": __vite_glob_0_15, "../../features/designer/assets/icons/join.png": __vite_glob_0_16, "../../features/designer/assets/icons/manual_input.png": __vite_glob_0_17, "../../features/designer/assets/icons/old_join.png": __vite_glob_0_18, "../../features/designer/assets/icons/output.png": __vite_glob_0_19, "../../features/designer/assets/icons/pivot.png": __vite_glob_0_20, "../../features/designer/assets/icons/polars_code.png": __vite_glob_0_21, "../../features/designer/assets/icons/record_count.png": __vite_glob_0_22, "../../features/designer/assets/icons/record_id.png": __vite_glob_0_23, "../../features/designer/assets/icons/sample.png": __vite_glob_0_24, "../../features/designer/assets/icons/select.png": __vite_glob_0_25, "../../features/designer/assets/icons/sort.png": __vite_glob_0_26, "../../features/designer/assets/icons/summarize.png": __vite_glob_0_27, "../../features/designer/assets/icons/text_to_rows.png": __vite_glob_0_28, "../../features/designer/assets/icons/union.png": __vite_glob_0_29, "../../features/designer/assets/icons/unique.png": __vite_glob_0_30, "../../features/designer/assets/icons/unpivot.png": __vite_glob_0_31, "../../features/designer/assets/icons/user-defined-icon.png": __vite_glob_0_32, "../../features/designer/assets/icons/view.png": __vite_glob_0_33 }))[`../../features/designer/assets/icons/${iconName}`], self.location).href;
1431
+ }
1432
+ function handleImageError(event) {
1433
+ const img = event.target;
1434
+ img.src = getDefaultIconUrl();
1435
+ }
1436
+ onMounted(() => {
1437
+ loadIcons();
1438
+ });
1439
+ return (_ctx, _cache) => {
1440
+ return openBlock(), createElementBlock("div", _hoisted_1$1, [
1441
+ _cache[9] || (_cache[9] = createBaseVNode("label", { class: "icon-label" }, "Node Icon", -1)),
1442
+ createBaseVNode("div", _hoisted_2$1, [
1443
+ createBaseVNode("div", {
1444
+ class: "current-icon",
1445
+ onClick: toggleDropdown
1446
+ }, [
1447
+ createBaseVNode("img", {
1448
+ src: getDisplayUrl(_ctx.modelValue),
1449
+ alt: _ctx.modelValue,
1450
+ class: "icon-preview",
1451
+ onError: handleImageError
1452
+ }, null, 40, _hoisted_3$1),
1453
+ createBaseVNode("span", _hoisted_4$1, toDisplayString(_ctx.modelValue || "Select icon..."), 1),
1454
+ _cache[2] || (_cache[2] = createBaseVNode("i", { class: "fa-solid fa-chevron-down dropdown-arrow" }, null, -1))
1455
+ ]),
1456
+ showDropdown.value ? (openBlock(), createElementBlock("div", _hoisted_5$1, [
1457
+ createBaseVNode("div", _hoisted_6$1, [
1458
+ createBaseVNode("label", _hoisted_7$1, [
1459
+ _cache[3] || (_cache[3] = createBaseVNode("i", { class: "fa-solid fa-upload" }, null, -1)),
1460
+ _cache[4] || (_cache[4] = createTextVNode(" Upload Icon ")),
1461
+ createBaseVNode("input", {
1462
+ type: "file",
1463
+ accept: ".png,.jpg,.jpeg,.svg,.gif,.webp",
1464
+ hidden: "",
1465
+ onChange: handleFileUpload
1466
+ }, null, 32)
1467
+ ])
1468
+ ]),
1469
+ customIcons.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_8$1, [
1470
+ _cache[6] || (_cache[6] = createBaseVNode("div", { class: "section-title" }, "Custom Icons", -1)),
1471
+ createBaseVNode("div", _hoisted_9$1, [
1472
+ (openBlock(true), createElementBlock(Fragment, null, renderList(customIcons.value, (icon) => {
1473
+ return openBlock(), createElementBlock("div", {
1474
+ key: icon.file_name,
1475
+ class: normalizeClass(["icon-option", { selected: _ctx.modelValue === icon.file_name }]),
1476
+ onClick: ($event) => selectIcon(icon.file_name)
1477
+ }, [
1478
+ createBaseVNode("img", {
1479
+ src: getCustomIconUrl$1(icon.file_name),
1480
+ alt: icon.file_name,
1481
+ class: "icon-img",
1482
+ onError: handleImageError
1483
+ }, null, 40, _hoisted_11$1),
1484
+ createBaseVNode("span", _hoisted_12$1, toDisplayString(icon.file_name), 1),
1485
+ createBaseVNode("button", {
1486
+ class: "delete-icon-btn",
1487
+ title: "Delete icon",
1488
+ onClick: withModifiers(($event) => deleteIcon(icon.file_name), ["stop"])
1489
+ }, _cache[5] || (_cache[5] = [
1490
+ createBaseVNode("i", { class: "fa-solid fa-times" }, null, -1)
1491
+ ]), 8, _hoisted_13$1)
1492
+ ], 10, _hoisted_10$1);
1493
+ }), 128))
1494
+ ])
1495
+ ])) : createCommentVNode("", true),
1496
+ createBaseVNode("div", _hoisted_14$1, [
1497
+ _cache[8] || (_cache[8] = createBaseVNode("div", { class: "section-title" }, "Default", -1)),
1498
+ createBaseVNode("div", _hoisted_15$1, [
1499
+ createBaseVNode("div", {
1500
+ class: normalizeClass(["icon-option", { selected: _ctx.modelValue === "user-defined-icon.png" }]),
1501
+ onClick: _cache[0] || (_cache[0] = ($event) => selectIcon("user-defined-icon.png"))
1502
+ }, [
1503
+ createBaseVNode("img", {
1504
+ src: getBuiltinIconUrl("user-defined-icon.png"),
1505
+ alt: "Default",
1506
+ class: "icon-img"
1507
+ }, null, 8, _hoisted_16$1),
1508
+ _cache[7] || (_cache[7] = createBaseVNode("span", { class: "icon-filename" }, "Default", -1))
1509
+ ], 2)
1510
+ ])
1511
+ ])
1512
+ ])) : createCommentVNode("", true)
1513
+ ]),
1514
+ showDropdown.value ? (openBlock(), createElementBlock("div", {
1515
+ key: 0,
1516
+ class: "backdrop",
1517
+ onClick: _cache[1] || (_cache[1] = ($event) => showDropdown.value = false)
1518
+ })) : createCommentVNode("", true)
1519
+ ]);
1520
+ };
1521
+ }
1522
+ });
1523
+ const IconSelector_vue_vue_type_style_index_0_scoped_5e08bde1_lang = "";
1524
+ const IconSelector = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-5e08bde1"]]);
1525
+ function useNodeDesignerState() {
1526
+ const nodeMetadata = reactive({ ...defaultNodeMetadata });
1527
+ const sections = ref([]);
1528
+ const selectedSectionIndex = ref(null);
1529
+ const selectedComponentIndex = ref(null);
1530
+ const processCode = ref(defaultProcessCode);
1531
+ const selectedComponent = computed(() => {
1532
+ var _a;
1533
+ if (selectedSectionIndex.value !== null && selectedComponentIndex.value !== null) {
1534
+ return ((_a = sections.value[selectedSectionIndex.value]) == null ? void 0 : _a.components[selectedComponentIndex.value]) || null;
1535
+ }
1536
+ return null;
1537
+ });
1538
+ const canSave = computed(() => {
1539
+ return nodeMetadata.node_name.trim() !== "" && nodeMetadata.node_category.trim() !== "";
1540
+ });
1541
+ function addSection() {
1542
+ const sectionNumber = sections.value.length + 1;
1543
+ sections.value.push({
1544
+ name: `section_${sectionNumber}`,
1545
+ title: `Section ${sectionNumber}`,
1546
+ components: []
1547
+ });
1548
+ selectedSectionIndex.value = sections.value.length - 1;
1549
+ selectedComponentIndex.value = null;
1550
+ }
1551
+ function removeSection(index) {
1552
+ sections.value.splice(index, 1);
1553
+ if (selectedSectionIndex.value === index) {
1554
+ selectedSectionIndex.value = null;
1555
+ selectedComponentIndex.value = null;
1556
+ }
1557
+ }
1558
+ function selectSection(index) {
1559
+ selectedSectionIndex.value = index;
1560
+ selectedComponentIndex.value = null;
1561
+ }
1562
+ function sanitizeSectionName(index) {
1563
+ let name = sections.value[index].name;
1564
+ name = name.replace(/[\s-]+/g, "_");
1565
+ name = name.replace(/[^a-zA-Z0-9_]/g, "");
1566
+ if (/^[0-9]/.test(name)) {
1567
+ name = "_" + name;
1568
+ }
1569
+ name = name.toLowerCase();
1570
+ sections.value[index].name = name;
1571
+ }
1572
+ function selectComponent(sectionIndex, compIndex) {
1573
+ selectedSectionIndex.value = sectionIndex;
1574
+ selectedComponentIndex.value = compIndex;
1575
+ }
1576
+ function removeComponent(sectionIndex, compIndex) {
1577
+ sections.value[sectionIndex].components.splice(compIndex, 1);
1578
+ if (selectedSectionIndex.value === sectionIndex && selectedComponentIndex.value === compIndex) {
1579
+ selectedComponentIndex.value = null;
1580
+ }
1581
+ }
1582
+ function addComponentToSection(sectionIndex, component) {
1583
+ sections.value[sectionIndex].components.push(component);
1584
+ selectedSectionIndex.value = sectionIndex;
1585
+ selectedComponentIndex.value = sections.value[sectionIndex].components.length - 1;
1586
+ }
1587
+ function resetState() {
1588
+ Object.assign(nodeMetadata, defaultNodeMetadata);
1589
+ sections.value = [];
1590
+ processCode.value = defaultProcessCode;
1591
+ selectedSectionIndex.value = null;
1592
+ selectedComponentIndex.value = null;
1593
+ }
1594
+ function getState() {
1595
+ return {
1596
+ nodeMetadata: { ...nodeMetadata },
1597
+ sections: sections.value,
1598
+ processCode: processCode.value
1599
+ };
1600
+ }
1601
+ function setState(state) {
1602
+ if (state.nodeMetadata) {
1603
+ Object.assign(nodeMetadata, state.nodeMetadata);
1604
+ }
1605
+ if (state.sections) {
1606
+ sections.value = state.sections;
1607
+ }
1608
+ if (state.processCode) {
1609
+ processCode.value = state.processCode;
1610
+ }
1611
+ }
1612
+ return {
1613
+ // State
1614
+ nodeMetadata,
1615
+ sections,
1616
+ selectedSectionIndex,
1617
+ selectedComponentIndex,
1618
+ processCode,
1619
+ // Computed
1620
+ selectedComponent,
1621
+ canSave,
1622
+ // Section methods
1623
+ addSection,
1624
+ removeSection,
1625
+ selectSection,
1626
+ sanitizeSectionName,
1627
+ // Component methods
1628
+ selectComponent,
1629
+ removeComponent,
1630
+ addComponentToSection,
1631
+ // State management
1632
+ resetState,
1633
+ getState,
1634
+ setState
1635
+ };
1636
+ }
1637
+ function useSessionStorage(getState, setState, resetState) {
1638
+ function saveToSessionStorage() {
1639
+ const state = getState();
1640
+ sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state));
1641
+ }
1642
+ function loadFromSessionStorage() {
1643
+ const saved = sessionStorage.getItem(STORAGE_KEY);
1644
+ if (saved) {
1645
+ try {
1646
+ const state = JSON.parse(saved);
1647
+ setState(state);
1648
+ } catch (e) {
1649
+ console.error("Failed to load from session storage:", e);
1650
+ }
1651
+ }
1652
+ }
1653
+ function clearSessionStorage() {
1654
+ sessionStorage.removeItem(STORAGE_KEY);
1655
+ resetState();
1656
+ }
1657
+ function setupAutoSave(watchSources) {
1658
+ watch(
1659
+ watchSources,
1660
+ () => {
1661
+ saveToSessionStorage();
1662
+ },
1663
+ { deep: true }
1664
+ );
1665
+ }
1666
+ function setupLoadOnMount() {
1667
+ onMounted(() => {
1668
+ loadFromSessionStorage();
1669
+ });
1670
+ }
1671
+ return {
1672
+ saveToSessionStorage,
1673
+ loadFromSessionStorage,
1674
+ clearSessionStorage,
1675
+ setupAutoSave,
1676
+ setupLoadOnMount
1677
+ };
1678
+ }
1679
+ function useNodeValidation() {
1680
+ const validationErrors = ref([]);
1681
+ const showValidationModal = ref(false);
1682
+ function validateSettings(nodeMetadata, sections, processCode) {
1683
+ const errors = [];
1684
+ if (!nodeMetadata.node_name.trim()) {
1685
+ errors.push({ field: "node_name", message: "Node name is required" });
1686
+ } else if (!/^[a-zA-Z][a-zA-Z0-9_\s]*$/.test(nodeMetadata.node_name)) {
1687
+ errors.push({
1688
+ field: "node_name",
1689
+ message: "Node name must start with a letter and contain only letters, numbers, spaces, and underscores"
1690
+ });
1691
+ }
1692
+ if (!nodeMetadata.node_category.trim()) {
1693
+ errors.push({ field: "node_category", message: "Category is required" });
1694
+ }
1695
+ const sectionNames = /* @__PURE__ */ new Set();
1696
+ sections.forEach((section, index) => {
1697
+ const name = section.name || toSnakeCase(section.title || "section");
1698
+ if (sectionNames.has(name)) {
1699
+ errors.push({ field: `section_${index}`, message: `Duplicate section name: "${name}"` });
1700
+ }
1701
+ sectionNames.add(name);
1702
+ const fieldNames = /* @__PURE__ */ new Set();
1703
+ section.components.forEach((comp, compIndex) => {
1704
+ const fieldName = toSnakeCase(comp.field_name);
1705
+ if (!fieldName) {
1706
+ errors.push({
1707
+ field: `section_${index}_comp_${compIndex}`,
1708
+ message: `Component in "${section.title}" is missing a field name`
1709
+ });
1710
+ } else if (fieldNames.has(fieldName)) {
1711
+ errors.push({
1712
+ field: `section_${index}_comp_${compIndex}`,
1713
+ message: `Duplicate field name "${fieldName}" in section "${section.title}"`
1714
+ });
1715
+ }
1716
+ fieldNames.add(fieldName);
1717
+ });
1718
+ });
1719
+ if (!processCode.includes("def process")) {
1720
+ errors.push({ field: "process_code", message: "Process method definition is missing" });
1721
+ }
1722
+ if (!processCode.includes("return")) {
1723
+ errors.push({ field: "process_code", message: "Process method must return a value" });
1724
+ }
1725
+ return errors;
1726
+ }
1727
+ function showErrors(errors) {
1728
+ validationErrors.value = errors;
1729
+ showValidationModal.value = true;
1730
+ }
1731
+ function closeValidationModal() {
1732
+ showValidationModal.value = false;
1733
+ }
1734
+ return {
1735
+ validationErrors,
1736
+ showValidationModal,
1737
+ validateSettings,
1738
+ showErrors,
1739
+ closeValidationModal
1740
+ };
1741
+ }
1742
+ function useNodeBrowser() {
1743
+ const showNodeBrowser = ref(false);
1744
+ const customNodes = ref([]);
1745
+ const loadingNodes = ref(false);
1746
+ const viewingNodeCode = ref("");
1747
+ const viewingNodeName = ref("");
1748
+ const viewingNodeFileName = ref("");
1749
+ const showDeleteConfirm = ref(false);
1750
+ async function fetchCustomNodes() {
1751
+ loadingNodes.value = true;
1752
+ try {
1753
+ const response = await axios.get("/user_defined_components/list-custom-nodes");
1754
+ customNodes.value = response.data;
1755
+ } catch (error) {
1756
+ console.error("Failed to fetch custom nodes:", error);
1757
+ customNodes.value = [];
1758
+ } finally {
1759
+ loadingNodes.value = false;
1760
+ }
1761
+ }
1762
+ async function viewCustomNode(fileName) {
1763
+ var _a;
1764
+ try {
1765
+ const response = await axios.get(`/user_defined_components/get-custom-node/${fileName}`);
1766
+ const nodeData = response.data;
1767
+ viewingNodeFileName.value = fileName;
1768
+ viewingNodeName.value = ((_a = nodeData.metadata) == null ? void 0 : _a.node_name) || fileName;
1769
+ viewingNodeCode.value = nodeData.content || "// No content available";
1770
+ } catch (error) {
1771
+ console.error("Failed to load custom node:", error);
1772
+ viewingNodeCode.value = `// Error loading node: ${error.message || "Unknown error"}`;
1773
+ }
1774
+ }
1775
+ function openNodeBrowser() {
1776
+ fetchCustomNodes();
1777
+ viewingNodeCode.value = "";
1778
+ viewingNodeName.value = "";
1779
+ viewingNodeFileName.value = "";
1780
+ showNodeBrowser.value = true;
1781
+ }
1782
+ function closeNodeBrowser() {
1783
+ showNodeBrowser.value = false;
1784
+ viewingNodeCode.value = "";
1785
+ viewingNodeName.value = "";
1786
+ viewingNodeFileName.value = "";
1787
+ }
1788
+ function backToNodeList() {
1789
+ viewingNodeCode.value = "";
1790
+ viewingNodeName.value = "";
1791
+ viewingNodeFileName.value = "";
1792
+ }
1793
+ function confirmDeleteNode() {
1794
+ showDeleteConfirm.value = true;
1795
+ }
1796
+ async function deleteNode() {
1797
+ var _a, _b;
1798
+ if (!viewingNodeFileName.value)
1799
+ return;
1800
+ try {
1801
+ await axios.delete(
1802
+ `/user_defined_components/delete-custom-node/${viewingNodeFileName.value}`
1803
+ );
1804
+ showDeleteConfirm.value = false;
1805
+ backToNodeList();
1806
+ fetchCustomNodes();
1807
+ } catch (error) {
1808
+ console.error("Failed to delete custom node:", error);
1809
+ alert(
1810
+ `Error deleting node: ${((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.detail) || error.message || "Unknown error"}`
1811
+ );
1812
+ showDeleteConfirm.value = false;
1813
+ }
1814
+ }
1815
+ return {
1816
+ // State
1817
+ showNodeBrowser,
1818
+ customNodes,
1819
+ loadingNodes,
1820
+ viewingNodeCode,
1821
+ viewingNodeName,
1822
+ viewingNodeFileName,
1823
+ showDeleteConfirm,
1824
+ // Methods
1825
+ fetchCustomNodes,
1826
+ viewCustomNode,
1827
+ openNodeBrowser,
1828
+ closeNodeBrowser,
1829
+ backToNodeList,
1830
+ confirmDeleteNode,
1831
+ deleteNode
1832
+ };
1833
+ }
1834
+ const lazyFrameMethods = [
1835
+ // Selection & Filtering
1836
+ { label: "select", type: "method", info: "Select columns", apply: "select()" },
1837
+ { label: "filter", type: "method", info: "Filter rows by condition", apply: "filter()" },
1838
+ { label: "with_columns", type: "method", info: "Add or modify columns", apply: "with_columns()" },
1839
+ { label: "drop", type: "method", info: "Drop columns", apply: "drop()" },
1840
+ { label: "rename", type: "method", info: "Rename columns", apply: "rename({})" },
1841
+ { label: "cast", type: "method", info: "Cast column types", apply: "cast({})" },
1842
+ // Sorting & Limiting
1843
+ { label: "sort", type: "method", info: "Sort by columns", apply: 'sort("")' },
1844
+ { label: "head", type: "method", info: "Get first n rows", apply: "head()" },
1845
+ { label: "tail", type: "method", info: "Get last n rows", apply: "tail()" },
1846
+ { label: "limit", type: "method", info: "Limit number of rows", apply: "limit()" },
1847
+ { label: "slice", type: "method", info: "Slice rows by offset and length", apply: "slice()" },
1848
+ { label: "unique", type: "method", info: "Get unique rows", apply: "unique()" },
1849
+ // Grouping & Aggregation
1850
+ { label: "group_by", type: "method", info: "Group by columns", apply: "group_by().agg()" },
1851
+ { label: "agg", type: "method", info: "Aggregate expressions", apply: "agg()" },
1852
+ { label: "rolling", type: "method", info: "Rolling window operations", apply: "rolling()" },
1853
+ {
1854
+ label: "group_by_dynamic",
1855
+ type: "method",
1856
+ info: "Dynamic time-based grouping",
1857
+ apply: "group_by_dynamic()"
1858
+ },
1859
+ // Joins
1860
+ {
1861
+ label: "join",
1862
+ type: "method",
1863
+ info: "Join with another LazyFrame",
1864
+ apply: 'join(other, on="", how="left")'
1865
+ },
1866
+ { label: "join_asof", type: "method", info: "As-of join for time series", apply: "join_asof()" },
1867
+ {
1868
+ label: "cross_join",
1869
+ type: "method",
1870
+ info: "Cross join (cartesian product)",
1871
+ apply: "cross_join()"
1872
+ },
1873
+ // Reshaping
1874
+ { label: "explode", type: "method", info: "Explode list column to rows", apply: 'explode("")' },
1875
+ { label: "unpivot", type: "method", info: "Unpivot wide to long format", apply: "unpivot()" },
1876
+ { label: "pivot", type: "method", info: "Pivot long to wide format", apply: "pivot()" },
1877
+ { label: "unnest", type: "method", info: "Unnest struct column", apply: 'unnest("")' },
1878
+ // Missing data
1879
+ { label: "fill_null", type: "method", info: "Fill null values", apply: "fill_null()" },
1880
+ { label: "fill_nan", type: "method", info: "Fill NaN values", apply: "fill_nan()" },
1881
+ { label: "drop_nulls", type: "method", info: "Drop rows with nulls", apply: "drop_nulls()" },
1882
+ { label: "interpolate", type: "method", info: "Interpolate null values", apply: "interpolate()" },
1883
+ // Other
1884
+ {
1885
+ label: "with_row_index",
1886
+ type: "method",
1887
+ info: "Add row index column",
1888
+ apply: 'with_row_index("index")'
1889
+ },
1890
+ { label: "reverse", type: "method", info: "Reverse row order", apply: "reverse()" },
1891
+ {
1892
+ label: "collect",
1893
+ type: "method",
1894
+ info: "Execute and collect to DataFrame",
1895
+ apply: "collect()"
1896
+ },
1897
+ { label: "lazy", type: "method", info: "Convert to LazyFrame", apply: "lazy()" },
1898
+ // Expression methods (chainable)
1899
+ { label: "alias", type: "method", info: "Rename expression result", apply: 'alias("")' },
1900
+ { label: "is_null", type: "method", info: "Check for null", apply: "is_null()" },
1901
+ { label: "is_not_null", type: "method", info: "Check for not null", apply: "is_not_null()" },
1902
+ { label: "sum", type: "method", info: "Sum values", apply: "sum()" },
1903
+ { label: "mean", type: "method", info: "Calculate mean", apply: "mean()" },
1904
+ { label: "min", type: "method", info: "Get minimum", apply: "min()" },
1905
+ { label: "max", type: "method", info: "Get maximum", apply: "max()" },
1906
+ { label: "count", type: "method", info: "Count values", apply: "count()" },
1907
+ { label: "first", type: "method", info: "Get first value", apply: "first()" },
1908
+ { label: "last", type: "method", info: "Get last value", apply: "last()" },
1909
+ { label: "str", type: "property", info: "String operations namespace", apply: "str." },
1910
+ { label: "dt", type: "property", info: "Datetime operations namespace", apply: "dt." },
1911
+ { label: "list", type: "property", info: "List operations namespace", apply: "list." },
1912
+ { label: "over", type: "method", info: "Window function over groups", apply: 'over("")' }
1913
+ ];
1914
+ const polarsCompletions = [
1915
+ { label: "self", type: "keyword", info: "Access node instance" },
1916
+ { label: "inputs[0]", type: "variable", info: "First input LazyFrame" },
1917
+ { label: "inputs[1]", type: "variable", info: "Second input LazyFrame" },
1918
+ // Polars expressions
1919
+ { label: "pl.col", type: "function", info: "Select a column by name", apply: 'pl.col("")' },
1920
+ { label: "pl.lit", type: "function", info: "Create a literal value", apply: "pl.lit()" },
1921
+ { label: "pl.all", type: "function", info: "Select all columns", apply: "pl.all()" },
1922
+ {
1923
+ label: "pl.exclude",
1924
+ type: "function",
1925
+ info: "Select all except specified",
1926
+ apply: 'pl.exclude("")'
1927
+ },
1928
+ {
1929
+ label: "pl.when",
1930
+ type: "function",
1931
+ info: "Start conditional expression",
1932
+ apply: "pl.when().then().otherwise()"
1933
+ },
1934
+ { label: "pl.concat", type: "function", info: "Concatenate LazyFrames", apply: "pl.concat([])" },
1935
+ { label: "pl.struct", type: "function", info: "Create struct column", apply: "pl.struct([])" },
1936
+ // LazyFrame methods with lf. prefix
1937
+ { label: "lf.select", type: "method", info: "Select columns", apply: "lf.select()" },
1938
+ { label: "lf.filter", type: "method", info: "Filter rows by condition", apply: "lf.filter()" },
1939
+ {
1940
+ label: "lf.with_columns",
1941
+ type: "method",
1942
+ info: "Add or modify columns",
1943
+ apply: "lf.with_columns()"
1944
+ },
1945
+ { label: "lf.drop", type: "method", info: "Drop columns", apply: "lf.drop()" },
1946
+ { label: "lf.rename", type: "method", info: "Rename columns", apply: "lf.rename({})" },
1947
+ { label: "lf.cast", type: "method", info: "Cast column types", apply: "lf.cast({})" },
1948
+ { label: "lf.sort", type: "method", info: "Sort by columns", apply: 'lf.sort("")' },
1949
+ { label: "lf.head", type: "method", info: "Get first n rows", apply: "lf.head()" },
1950
+ { label: "lf.tail", type: "method", info: "Get last n rows", apply: "lf.tail()" },
1951
+ { label: "lf.limit", type: "method", info: "Limit number of rows", apply: "lf.limit()" },
1952
+ {
1953
+ label: "lf.slice",
1954
+ type: "method",
1955
+ info: "Slice rows by offset and length",
1956
+ apply: "lf.slice()"
1957
+ },
1958
+ { label: "lf.unique", type: "method", info: "Get unique rows", apply: "lf.unique()" },
1959
+ { label: "lf.group_by", type: "method", info: "Group by columns", apply: "lf.group_by().agg()" },
1960
+ { label: "lf.agg", type: "method", info: "Aggregate expressions", apply: "lf.agg()" },
1961
+ { label: "lf.rolling", type: "method", info: "Rolling window operations", apply: "lf.rolling()" },
1962
+ {
1963
+ label: "lf.group_by_dynamic",
1964
+ type: "method",
1965
+ info: "Dynamic time-based grouping",
1966
+ apply: "lf.group_by_dynamic()"
1967
+ },
1968
+ {
1969
+ label: "lf.join",
1970
+ type: "method",
1971
+ info: "Join with another LazyFrame",
1972
+ apply: 'lf.join(other, on="", how="left")'
1973
+ },
1974
+ {
1975
+ label: "lf.join_asof",
1976
+ type: "method",
1977
+ info: "As-of join for time series",
1978
+ apply: "lf.join_asof()"
1979
+ },
1980
+ {
1981
+ label: "lf.cross_join",
1982
+ type: "method",
1983
+ info: "Cross join (cartesian product)",
1984
+ apply: "lf.cross_join()"
1985
+ },
1986
+ {
1987
+ label: "lf.explode",
1988
+ type: "method",
1989
+ info: "Explode list column to rows",
1990
+ apply: 'lf.explode("")'
1991
+ },
1992
+ {
1993
+ label: "lf.unpivot",
1994
+ type: "method",
1995
+ info: "Unpivot wide to long format",
1996
+ apply: "lf.unpivot()"
1997
+ },
1998
+ { label: "lf.pivot", type: "method", info: "Pivot long to wide format", apply: "lf.pivot()" },
1999
+ { label: "lf.unnest", type: "method", info: "Unnest struct column", apply: 'lf.unnest("")' },
2000
+ { label: "lf.fill_null", type: "method", info: "Fill null values", apply: "lf.fill_null()" },
2001
+ { label: "lf.fill_nan", type: "method", info: "Fill NaN values", apply: "lf.fill_nan()" },
2002
+ {
2003
+ label: "lf.drop_nulls",
2004
+ type: "method",
2005
+ info: "Drop rows with nulls",
2006
+ apply: "lf.drop_nulls()"
2007
+ },
2008
+ {
2009
+ label: "lf.interpolate",
2010
+ type: "method",
2011
+ info: "Interpolate null values",
2012
+ apply: "lf.interpolate()"
2013
+ },
2014
+ {
2015
+ label: "lf.with_row_index",
2016
+ type: "method",
2017
+ info: "Add row index column",
2018
+ apply: 'lf.with_row_index("index")'
2019
+ },
2020
+ { label: "lf.reverse", type: "method", info: "Reverse row order", apply: "lf.reverse()" },
2021
+ {
2022
+ label: "lf.collect",
2023
+ type: "method",
2024
+ info: "Execute and collect to DataFrame",
2025
+ apply: "lf.collect()"
2026
+ },
2027
+ { label: "lf.lazy", type: "method", info: "Convert to LazyFrame", apply: "lf.lazy()" },
2028
+ // Expression methods
2029
+ { label: ".alias", type: "method", info: "Rename expression result", apply: '.alias("")' },
2030
+ { label: ".cast", type: "method", info: "Cast to type", apply: ".cast(pl.Utf8)" },
2031
+ { label: ".is_null", type: "method", info: "Check for null", apply: ".is_null()" },
2032
+ { label: ".is_not_null", type: "method", info: "Check for not null", apply: ".is_not_null()" },
2033
+ { label: ".fill_null", type: "method", info: "Fill null values", apply: ".fill_null()" },
2034
+ { label: ".sum", type: "method", info: "Sum values", apply: ".sum()" },
2035
+ { label: ".mean", type: "method", info: "Calculate mean", apply: ".mean()" },
2036
+ { label: ".min", type: "method", info: "Get minimum", apply: ".min()" },
2037
+ { label: ".max", type: "method", info: "Get maximum", apply: ".max()" },
2038
+ { label: ".count", type: "method", info: "Count values", apply: ".count()" },
2039
+ { label: ".first", type: "method", info: "Get first value", apply: ".first()" },
2040
+ { label: ".last", type: "method", info: "Get last value", apply: ".last()" },
2041
+ { label: ".str", type: "property", info: "String operations namespace", apply: ".str." },
2042
+ { label: ".dt", type: "property", info: "Datetime operations namespace", apply: ".dt." },
2043
+ { label: ".list", type: "property", info: "List operations namespace", apply: ".list." },
2044
+ { label: ".over", type: "method", info: "Window function over groups", apply: '.over("")' }
2045
+ ];
2046
+ const secretStrMethods = [
2047
+ {
2048
+ label: "get_secret_value",
2049
+ type: "method",
2050
+ info: "Get the decrypted secret value as a string",
2051
+ apply: "get_secret_value()",
2052
+ detail: "SecretStr"
2053
+ }
2054
+ ];
2055
+ function usePolarsAutocompletion(getSections) {
2056
+ function findSecretStrVariables(doc) {
2057
+ const variables = [];
2058
+ const typeAnnotationPattern = /(\w+)\s*:\s*SecretStr\s*=/g;
2059
+ let match;
2060
+ while ((match = typeAnnotationPattern.exec(doc)) !== null) {
2061
+ variables.push(match[1]);
2062
+ }
2063
+ return variables;
2064
+ }
2065
+ function schemaCompletions(context) {
2066
+ const beforeCursor = context.state.doc.sliceString(0, context.pos);
2067
+ const fullDoc = context.state.doc.toString();
2068
+ const sections = getSections();
2069
+ const secretStrVars = findSecretStrVariables(fullDoc);
2070
+ for (const varName of secretStrVars) {
2071
+ const varMethodMatch = beforeCursor.match(new RegExp(`\\b${varName}\\.(\\w*)$`));
2072
+ if (varMethodMatch) {
2073
+ const typed = varMethodMatch[1];
2074
+ return {
2075
+ from: context.pos - typed.length,
2076
+ options: secretStrMethods,
2077
+ validFor: /^\w*$/
2078
+ };
2079
+ }
2080
+ }
2081
+ const secretStrMethodMatch = beforeCursor.match(/\.secret_value\.(\w*)$/);
2082
+ if (secretStrMethodMatch) {
2083
+ const typed = secretStrMethodMatch[1];
2084
+ return {
2085
+ from: context.pos - typed.length,
2086
+ options: secretStrMethods,
2087
+ validFor: /^\w*$/
2088
+ };
2089
+ }
2090
+ for (const section of sections) {
2091
+ const sectionName = section.name || toSnakeCase(section.title || "section");
2092
+ for (const comp of section.components) {
2093
+ const fieldName = toSnakeCase(comp.field_name);
2094
+ const valueMatch = beforeCursor.match(
2095
+ new RegExp(`self\\.settings_schema\\.${sectionName}\\.${fieldName}\\.(\\w*)$`)
2096
+ );
2097
+ if (valueMatch) {
2098
+ const typed = valueMatch[1];
2099
+ if (comp.component_type === "SecretSelector") {
2100
+ return {
2101
+ from: context.pos - typed.length,
2102
+ options: [
2103
+ {
2104
+ label: "secret_value",
2105
+ type: "property",
2106
+ info: "Get the decrypted secret value (SecretStr)",
2107
+ detail: "SecretSelector"
2108
+ }
2109
+ ],
2110
+ validFor: /^\w*$/
2111
+ };
2112
+ }
2113
+ return {
2114
+ from: context.pos - typed.length,
2115
+ options: [
2116
+ {
2117
+ label: "value",
2118
+ type: "property",
2119
+ info: "Get the setting value",
2120
+ detail: comp.component_type
2121
+ }
2122
+ ],
2123
+ validFor: /^\w*$/
2124
+ };
2125
+ }
2126
+ }
2127
+ }
2128
+ for (const section of sections) {
2129
+ const sectionName = section.name || toSnakeCase(section.title || "section");
2130
+ const sectionMatch = beforeCursor.match(
2131
+ new RegExp(`self\\.settings_schema\\.${sectionName}\\.(\\w*)$`)
2132
+ );
2133
+ if (sectionMatch) {
2134
+ const typed = sectionMatch[1];
2135
+ const componentOptions = section.components.map((comp) => {
2136
+ const fieldName = toSnakeCase(comp.field_name);
2137
+ return {
2138
+ label: fieldName,
2139
+ type: "property",
2140
+ info: `${comp.component_type}: ${comp.label}`,
2141
+ detail: comp.component_type
2142
+ };
2143
+ });
2144
+ return {
2145
+ from: context.pos - typed.length,
2146
+ options: componentOptions,
2147
+ validFor: /^\w*$/
2148
+ };
2149
+ }
2150
+ }
2151
+ const settingsMatch = beforeCursor.match(/self\.settings_schema\.(\w*)$/);
2152
+ if (settingsMatch) {
2153
+ const typed = settingsMatch[1];
2154
+ const sectionOptions = sections.map((section) => {
2155
+ const sectionName = section.name || toSnakeCase(section.title || "section");
2156
+ const sectionTitle = section.title || section.name || "Section";
2157
+ return {
2158
+ label: sectionName,
2159
+ type: "property",
2160
+ info: `Section: ${sectionTitle}`,
2161
+ detail: "Section"
2162
+ };
2163
+ });
2164
+ return {
2165
+ from: context.pos - typed.length,
2166
+ options: sectionOptions,
2167
+ validFor: /^\w*$/
2168
+ };
2169
+ }
2170
+ const selfDotMatch = beforeCursor.match(/self\.(\w*)$/);
2171
+ if (selfDotMatch) {
2172
+ const typed = selfDotMatch[1];
2173
+ return {
2174
+ from: context.pos - typed.length,
2175
+ options: [{ label: "settings_schema", type: "property", info: "Access node settings" }],
2176
+ validFor: /^\w*$/
2177
+ };
2178
+ }
2179
+ const lfMethodMatch = beforeCursor.match(/(\w+)\.(\w*)$/);
2180
+ if (lfMethodMatch) {
2181
+ const typed = lfMethodMatch[2];
2182
+ return {
2183
+ from: context.pos - typed.length,
2184
+ options: lazyFrameMethods,
2185
+ validFor: /^\w*$/
2186
+ };
2187
+ }
2188
+ const wordMatch = context.matchBefore(/\w+/);
2189
+ if (!wordMatch && !context.explicit)
2190
+ return null;
2191
+ return {
2192
+ from: wordMatch ? wordMatch.from : context.pos,
2193
+ options: polarsCompletions,
2194
+ validFor: /^\w*$/
2195
+ };
2196
+ }
2197
+ const tabKeymap = keymap.of([
2198
+ {
2199
+ key: "Tab",
2200
+ run: (view) => {
2201
+ if (acceptCompletion(view)) {
2202
+ return true;
2203
+ }
2204
+ return indentMore(view);
2205
+ }
2206
+ },
2207
+ {
2208
+ key: "Shift-Tab",
2209
+ run: (view) => {
2210
+ return indentLess(view);
2211
+ }
2212
+ }
2213
+ ]);
2214
+ const extensions = [
2215
+ python(),
2216
+ oneDark,
2217
+ EditorState.tabSize.of(4),
2218
+ autocompletion({
2219
+ override: [schemaCompletions],
2220
+ defaultKeymap: true,
2221
+ // Enable default keymap for arrow navigation
2222
+ closeOnBlur: false
2223
+ }),
2224
+ Prec.highest(tabKeymap)
2225
+ // Tab keymap with highest precedence
2226
+ ];
2227
+ const readOnlyExtensions = [
2228
+ python(),
2229
+ oneDark,
2230
+ EditorState.tabSize.of(4),
2231
+ EditorView.editable.of(false),
2232
+ EditorState.readOnly.of(true)
2233
+ ];
2234
+ return {
2235
+ extensions,
2236
+ readOnlyExtensions,
2237
+ schemaCompletions
2238
+ };
2239
+ }
2240
+ const _hoisted_1 = { class: "node-designer-container" };
2241
+ const _hoisted_2 = { class: "page-header" };
2242
+ const _hoisted_3 = { class: "header-actions" };
2243
+ const _hoisted_4 = { class: "designer-layout" };
2244
+ const _hoisted_5 = { class: "panel design-canvas" };
2245
+ const _hoisted_6 = { class: "panel-content" };
2246
+ const _hoisted_7 = { class: "metadata-section" };
2247
+ const _hoisted_8 = { class: "form-grid" };
2248
+ const _hoisted_9 = { class: "form-field" };
2249
+ const _hoisted_10 = { class: "form-field" };
2250
+ const _hoisted_11 = { class: "form-field" };
2251
+ const _hoisted_12 = { class: "form-field" };
2252
+ const _hoisted_13 = { class: "form-field" };
2253
+ const _hoisted_14 = { class: "form-field" };
2254
+ const _hoisted_15 = { class: "form-field icon-field" };
2255
+ const _hoisted_16 = { class: "sections-area" };
2256
+ const _hoisted_17 = { class: "sections-header" };
2257
+ const _hoisted_18 = {
2258
+ key: 0,
2259
+ class: "empty-sections"
2260
+ };
2261
+ const _sfc_main = /* @__PURE__ */ defineComponent({
2262
+ __name: "NodeDesigner",
2263
+ setup(__props) {
2264
+ const {
2265
+ nodeMetadata,
2266
+ sections,
2267
+ selectedSectionIndex,
2268
+ selectedComponentIndex,
2269
+ processCode,
2270
+ selectedComponent,
2271
+ addSection,
2272
+ removeSection,
2273
+ selectSection,
2274
+ sanitizeSectionName,
2275
+ selectComponent,
2276
+ removeComponent,
2277
+ addComponentToSection,
2278
+ resetState,
2279
+ getState,
2280
+ setState
2281
+ } = useNodeDesignerState();
2282
+ const validation = useNodeValidation();
2283
+ const codeGen = useCodeGeneration();
2284
+ const nodeBrowser = useNodeBrowser();
2285
+ const autocompletion2 = usePolarsAutocompletion(() => sections.value);
2286
+ const storage = useSessionStorage(getState, setState, resetState);
2287
+ const showHelpModal = ref(false);
2288
+ watch([() => ({ ...nodeMetadata }), sections, processCode], () => storage.saveToSessionStorage(), {
2289
+ deep: true
2290
+ });
2291
+ onMounted(() => {
2292
+ storage.loadFromSessionStorage();
2293
+ });
2294
+ function handleNew() {
2295
+ storage.clearSessionStorage();
2296
+ }
2297
+ function handlePreview() {
2298
+ codeGen.previewCode(nodeMetadata, sections.value, processCode.value);
2299
+ }
2300
+ async function handleSave() {
2301
+ var _a, _b;
2302
+ const errors = validation.validateSettings(nodeMetadata, sections.value, processCode.value);
2303
+ if (errors.length > 0) {
2304
+ validation.showErrors(errors);
2305
+ return;
2306
+ }
2307
+ const code = codeGen.generateCode(nodeMetadata, sections.value, processCode.value);
2308
+ const fileName = toSnakeCase(nodeMetadata.node_name) + ".py";
2309
+ try {
2310
+ await axios.post("/user_defined_components/save-custom-node", {
2311
+ file_name: fileName,
2312
+ code
2313
+ });
2314
+ alert(`Node "${nodeMetadata.node_name}" saved successfully!`);
2315
+ } catch (error) {
2316
+ const errorMsg = ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.detail) || error.message || "Failed to save node";
2317
+ alert(`Error saving node: ${errorMsg}`);
2318
+ }
2319
+ }
2320
+ function handleDrop(event, sectionIndex) {
2321
+ var _a;
2322
+ const componentType = (_a = event.dataTransfer) == null ? void 0 : _a.getData("component_type");
2323
+ if (!componentType)
2324
+ return;
2325
+ const compCount = sections.value[sectionIndex].components.length + 1;
2326
+ const newComponent = {
2327
+ component_type: componentType,
2328
+ field_name: `${toSnakeCase(componentType)}_${compCount}`,
2329
+ label: `${componentType} ${compCount}`,
2330
+ options_source: "static",
2331
+ options_string: ""
2332
+ };
2333
+ if (componentType === "TextInput") {
2334
+ newComponent.default = "";
2335
+ newComponent.placeholder = "";
2336
+ } else if (componentType === "NumericInput") {
2337
+ newComponent.default = 0;
2338
+ } else if (componentType === "ToggleSwitch") {
2339
+ newComponent.default = false;
2340
+ } else if (componentType === "ColumnSelector") {
2341
+ newComponent.required = false;
2342
+ newComponent.multiple = false;
2343
+ newComponent.data_types = "ALL";
2344
+ } else if (componentType === "SliderInput") {
2345
+ newComponent.min_value = 0;
2346
+ newComponent.max_value = 100;
2347
+ newComponent.step = 1;
2348
+ }
2349
+ addComponentToSection(sectionIndex, newComponent);
2350
+ }
2351
+ function handlePropertyUpdate(field, value) {
2352
+ if (selectedComponent.value) {
2353
+ selectedComponent.value[field] = value;
2354
+ }
2355
+ }
2356
+ const selectedSectionName = computed(() => {
2357
+ if (selectedSectionIndex.value === null)
2358
+ return "";
2359
+ const section = sections.value[selectedSectionIndex.value];
2360
+ return (section == null ? void 0 : section.name) || (section == null ? void 0 : section.title) || "";
2361
+ });
2362
+ function handleInsertVariable(code) {
2363
+ const lines = processCode.value.split("\n");
2364
+ let insertIndex = 1;
2365
+ for (let i = 0; i < lines.length; i++) {
2366
+ const trimmed = lines[i].trim();
2367
+ if (trimmed.startsWith("def process")) {
2368
+ insertIndex = i + 1;
2369
+ while (insertIndex < lines.length && (lines[insertIndex].trim().startsWith("#") || lines[insertIndex].trim() === "")) {
2370
+ insertIndex++;
2371
+ }
2372
+ break;
2373
+ }
2374
+ }
2375
+ lines.splice(insertIndex, 0, code);
2376
+ processCode.value = lines.join("\n");
2377
+ }
2378
+ return (_ctx, _cache) => {
2379
+ return openBlock(), createElementBlock("div", _hoisted_1, [
2380
+ createBaseVNode("div", _hoisted_2, [
2381
+ _cache[25] || (_cache[25] = createBaseVNode("div", { class: "header-left" }, [
2382
+ createBaseVNode("h2", { class: "page-title" }, "Node Designer"),
2383
+ createBaseVNode("p", { class: "page-description" }, "Design custom nodes visually")
2384
+ ], -1)),
2385
+ createBaseVNode("div", _hoisted_3, [
2386
+ createBaseVNode("button", {
2387
+ class: "btn btn-secondary",
2388
+ onClick: _cache[0] || (_cache[0] = ($event) => showHelpModal.value = true)
2389
+ }, _cache[20] || (_cache[20] = [
2390
+ createBaseVNode("i", { class: "fa-solid fa-circle-question" }, null, -1),
2391
+ createTextVNode(" Help ")
2392
+ ])),
2393
+ createBaseVNode("button", {
2394
+ class: "btn btn-secondary",
2395
+ onClick: _cache[1] || (_cache[1] = ($event) => unref(nodeBrowser).openNodeBrowser())
2396
+ }, _cache[21] || (_cache[21] = [
2397
+ createBaseVNode("i", { class: "fa-solid fa-folder-open" }, null, -1),
2398
+ createTextVNode(" Browse ")
2399
+ ])),
2400
+ createBaseVNode("button", {
2401
+ class: "btn btn-secondary",
2402
+ onClick: handleNew
2403
+ }, _cache[22] || (_cache[22] = [
2404
+ createBaseVNode("i", { class: "fa-solid fa-file" }, null, -1),
2405
+ createTextVNode(" New ")
2406
+ ])),
2407
+ createBaseVNode("button", {
2408
+ class: "btn btn-secondary",
2409
+ onClick: handlePreview
2410
+ }, _cache[23] || (_cache[23] = [
2411
+ createBaseVNode("i", { class: "fa-solid fa-code" }, null, -1),
2412
+ createTextVNode(" Preview ")
2413
+ ])),
2414
+ createBaseVNode("button", {
2415
+ class: "btn btn-primary",
2416
+ onClick: handleSave
2417
+ }, _cache[24] || (_cache[24] = [
2418
+ createBaseVNode("i", { class: "fa-solid fa-save" }, null, -1),
2419
+ createTextVNode(" Save ")
2420
+ ]))
2421
+ ])
2422
+ ]),
2423
+ createBaseVNode("div", _hoisted_4, [
2424
+ createVNode(ComponentPalette),
2425
+ createBaseVNode("div", _hoisted_5, [
2426
+ _cache[36] || (_cache[36] = createBaseVNode("div", { class: "panel-header" }, [
2427
+ createBaseVNode("h3", null, "Design Canvas")
2428
+ ], -1)),
2429
+ createBaseVNode("div", _hoisted_6, [
2430
+ createBaseVNode("div", _hoisted_7, [
2431
+ _cache[32] || (_cache[32] = createBaseVNode("h4", null, "Node Metadata", -1)),
2432
+ createBaseVNode("div", _hoisted_8, [
2433
+ createBaseVNode("div", _hoisted_9, [
2434
+ _cache[26] || (_cache[26] = createBaseVNode("label", { for: "node-name" }, "Node Name *", -1)),
2435
+ withDirectives(createBaseVNode("input", {
2436
+ id: "node-name",
2437
+ "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => unref(nodeMetadata).node_name = $event),
2438
+ type: "text",
2439
+ class: "form-input",
2440
+ placeholder: "My Custom Node"
2441
+ }, null, 512), [
2442
+ [vModelText, unref(nodeMetadata).node_name]
2443
+ ])
2444
+ ]),
2445
+ createBaseVNode("div", _hoisted_10, [
2446
+ _cache[27] || (_cache[27] = createBaseVNode("label", { for: "node-category" }, "Category *", -1)),
2447
+ withDirectives(createBaseVNode("input", {
2448
+ id: "node-category",
2449
+ "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => unref(nodeMetadata).node_category = $event),
2450
+ type: "text",
2451
+ class: "form-input",
2452
+ placeholder: "Custom"
2453
+ }, null, 512), [
2454
+ [vModelText, unref(nodeMetadata).node_category]
2455
+ ])
2456
+ ]),
2457
+ createBaseVNode("div", _hoisted_11, [
2458
+ _cache[28] || (_cache[28] = createBaseVNode("label", { for: "node-title" }, "Title", -1)),
2459
+ withDirectives(createBaseVNode("input", {
2460
+ id: "node-title",
2461
+ "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => unref(nodeMetadata).title = $event),
2462
+ type: "text",
2463
+ class: "form-input",
2464
+ placeholder: "My Custom Node"
2465
+ }, null, 512), [
2466
+ [vModelText, unref(nodeMetadata).title]
2467
+ ])
2468
+ ]),
2469
+ createBaseVNode("div", _hoisted_12, [
2470
+ _cache[29] || (_cache[29] = createBaseVNode("label", { for: "node-intro" }, "Description", -1)),
2471
+ withDirectives(createBaseVNode("input", {
2472
+ id: "node-intro",
2473
+ "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => unref(nodeMetadata).intro = $event),
2474
+ type: "text",
2475
+ class: "form-input",
2476
+ placeholder: "A custom node for data processing"
2477
+ }, null, 512), [
2478
+ [vModelText, unref(nodeMetadata).intro]
2479
+ ])
2480
+ ]),
2481
+ createBaseVNode("div", _hoisted_13, [
2482
+ _cache[30] || (_cache[30] = createBaseVNode("label", { for: "node-inputs" }, "Number of Inputs", -1)),
2483
+ withDirectives(createBaseVNode("input", {
2484
+ id: "node-inputs",
2485
+ "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => unref(nodeMetadata).number_of_inputs = $event),
2486
+ type: "number",
2487
+ min: "0",
2488
+ max: "10",
2489
+ class: "form-input"
2490
+ }, null, 512), [
2491
+ [
2492
+ vModelText,
2493
+ unref(nodeMetadata).number_of_inputs,
2494
+ void 0,
2495
+ { number: true }
2496
+ ]
2497
+ ])
2498
+ ]),
2499
+ createBaseVNode("div", _hoisted_14, [
2500
+ _cache[31] || (_cache[31] = createBaseVNode("label", { for: "node-outputs" }, "Number of Outputs", -1)),
2501
+ withDirectives(createBaseVNode("input", {
2502
+ id: "node-outputs",
2503
+ "onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => unref(nodeMetadata).number_of_outputs = $event),
2504
+ type: "number",
2505
+ min: "1",
2506
+ max: "10",
2507
+ class: "form-input"
2508
+ }, null, 512), [
2509
+ [
2510
+ vModelText,
2511
+ unref(nodeMetadata).number_of_outputs,
2512
+ void 0,
2513
+ { number: true }
2514
+ ]
2515
+ ])
2516
+ ]),
2517
+ createBaseVNode("div", _hoisted_15, [
2518
+ createVNode(IconSelector, {
2519
+ modelValue: unref(nodeMetadata).node_icon,
2520
+ "onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => unref(nodeMetadata).node_icon = $event)
2521
+ }, null, 8, ["modelValue"])
2522
+ ])
2523
+ ])
2524
+ ]),
2525
+ createBaseVNode("div", _hoisted_16, [
2526
+ createBaseVNode("div", _hoisted_17, [
2527
+ _cache[34] || (_cache[34] = createBaseVNode("h4", null, "UI Sections", -1)),
2528
+ createBaseVNode("button", {
2529
+ class: "add-section-btn",
2530
+ onClick: _cache[9] || (_cache[9] = ($event) => unref(addSection)())
2531
+ }, _cache[33] || (_cache[33] = [
2532
+ createBaseVNode("i", { class: "fa-solid fa-plus" }, null, -1),
2533
+ createTextVNode(" Add Section ")
2534
+ ]))
2535
+ ]),
2536
+ (openBlock(true), createElementBlock(Fragment, null, renderList(unref(sections), (section, sectionIndex) => {
2537
+ return openBlock(), createBlock(SectionCard, {
2538
+ key: sectionIndex,
2539
+ section,
2540
+ "is-selected": unref(selectedSectionIndex) === sectionIndex,
2541
+ "selected-component-index": unref(selectedSectionIndex) === sectionIndex ? unref(selectedComponentIndex) : null,
2542
+ onSelect: ($event) => unref(selectSection)(sectionIndex),
2543
+ onRemove: ($event) => unref(removeSection)(sectionIndex),
2544
+ onSelectComponent: ($event) => unref(selectComponent)(sectionIndex, $event),
2545
+ onRemoveComponent: ($event) => unref(removeComponent)(sectionIndex, $event),
2546
+ onDrop: ($event) => handleDrop($event, sectionIndex),
2547
+ onUpdateName: ($event) => {
2548
+ section.name = $event;
2549
+ unref(sanitizeSectionName)(sectionIndex);
2550
+ },
2551
+ onUpdateTitle: ($event) => section.title = $event
2552
+ }, null, 8, ["section", "is-selected", "selected-component-index", "onSelect", "onRemove", "onSelectComponent", "onRemoveComponent", "onDrop", "onUpdateName", "onUpdateTitle"]);
2553
+ }), 128)),
2554
+ unref(sections).length === 0 ? (openBlock(), createElementBlock("div", _hoisted_18, _cache[35] || (_cache[35] = [
2555
+ createBaseVNode("i", { class: "fa-solid fa-layer-group" }, null, -1),
2556
+ createBaseVNode("p", null, "No sections yet. Add a section to start designing your node UI.", -1)
2557
+ ]))) : createCommentVNode("", true)
2558
+ ]),
2559
+ createVNode(ProcessCodeEditor, {
2560
+ modelValue: unref(processCode),
2561
+ "onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => isRef(processCode) ? processCode.value = $event : null),
2562
+ extensions: unref(autocompletion2).extensions
2563
+ }, null, 8, ["modelValue", "extensions"])
2564
+ ])
2565
+ ]),
2566
+ createVNode(PropertyEditor, {
2567
+ component: unref(selectedComponent),
2568
+ "section-name": selectedSectionName.value,
2569
+ onUpdate: handlePropertyUpdate,
2570
+ onInsertVariable: handleInsertVariable
2571
+ }, null, 8, ["component", "section-name"])
2572
+ ]),
2573
+ createVNode(CodePreviewModal, {
2574
+ show: unref(codeGen).showPreviewModal.value,
2575
+ code: unref(codeGen).generatedCode.value,
2576
+ onClose: _cache[11] || (_cache[11] = ($event) => unref(codeGen).closePreview())
2577
+ }, null, 8, ["show", "code"]),
2578
+ createVNode(ValidationModal, {
2579
+ show: unref(validation).showValidationModal.value,
2580
+ errors: unref(validation).validationErrors.value,
2581
+ onClose: _cache[12] || (_cache[12] = ($event) => unref(validation).closeValidationModal())
2582
+ }, null, 8, ["show", "errors"]),
2583
+ createVNode(NodeBrowserModal, {
2584
+ show: unref(nodeBrowser).showNodeBrowser.value,
2585
+ nodes: unref(nodeBrowser).customNodes.value,
2586
+ loading: unref(nodeBrowser).loadingNodes.value,
2587
+ "viewing-node-code": unref(nodeBrowser).viewingNodeCode.value,
2588
+ "viewing-node-name": unref(nodeBrowser).viewingNodeName.value,
2589
+ "show-delete-confirm": unref(nodeBrowser).showDeleteConfirm.value,
2590
+ "read-only-extensions": unref(autocompletion2).readOnlyExtensions,
2591
+ onClose: _cache[13] || (_cache[13] = ($event) => unref(nodeBrowser).closeNodeBrowser()),
2592
+ onViewNode: _cache[14] || (_cache[14] = ($event) => unref(nodeBrowser).viewCustomNode($event)),
2593
+ onBack: _cache[15] || (_cache[15] = ($event) => unref(nodeBrowser).backToNodeList()),
2594
+ onConfirmDelete: _cache[16] || (_cache[16] = ($event) => unref(nodeBrowser).confirmDeleteNode()),
2595
+ onCancelDelete: _cache[17] || (_cache[17] = ($event) => unref(nodeBrowser).showDeleteConfirm.value = false),
2596
+ onDelete: _cache[18] || (_cache[18] = ($event) => unref(nodeBrowser).deleteNode())
2597
+ }, null, 8, ["show", "nodes", "loading", "viewing-node-code", "viewing-node-name", "show-delete-confirm", "read-only-extensions"]),
2598
+ createVNode(NodeDesignerHelpModal, {
2599
+ show: showHelpModal.value,
2600
+ onClose: _cache[19] || (_cache[19] = ($event) => showHelpModal.value = false)
2601
+ }, null, 8, ["show"])
2602
+ ]);
2603
+ };
2604
+ }
2605
+ });
2606
+ const NodeDesigner_vue_vue_type_style_index_0_scoped_1c613876_lang = "";
2607
+ const NodeDesigner = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-1c613876"]]);
2608
+ export {
2609
+ NodeDesigner as default
2610
+ };