Flowfile 0.5.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 (329) hide show
  1. build_backends/main.py +25 -22
  2. build_backends/main_prd.py +10 -19
  3. flowfile/__init__.py +178 -74
  4. flowfile/__main__.py +10 -7
  5. flowfile/api.py +51 -57
  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-0dfba9f2.js → CloudConnectionView-f13f202b.js} +11 -11
  11. flowfile/web/static/assets/{CloudStorageReader-d5b1b6c9.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-00d87aad.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-4685e75d.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-23e909da.js → ContextMenu-31ee57f0.js} +3 -3
  19. flowfile/web/static/assets/{ContextMenu-70ae0c79.js → ContextMenu-69a74055.js} +3 -3
  20. flowfile/web/static/assets/{ContextMenu-f149cf7c.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-702a3edd.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-b1519993.js → CustomNode-8479239b.js} +36 -24
  27. flowfile/web/static/assets/{DatabaseConnectionSettings-6f3e4ea5.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-d38c7295.js → DatabaseReader-c58b9552.js} +25 -15
  31. flowfile/web/static/assets/DatabaseView-6655afd6.css +57 -0
  32. flowfile/web/static/assets/{DatabaseManager-cf5ef661.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-b04ef46a.js → DatabaseWriter-4d05ddc7.js} +17 -10
  35. flowfile/web/static/assets/{designer-8da3ba3a.css → DesignerView-a6d0ee84.css} +614 -546
  36. flowfile/web/static/assets/{designer-9633482a.js → DesignerView-e6f5c0e8.js} +1107 -3170
  37. flowfile/web/static/assets/{documentation-ca400224.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-5fa10ed8.js → ExploreData-7b54caca.js} +18 -9
  41. flowfile/web/static/assets/{ExternalSource-d39af878.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-6b04fb1d.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-999521f4.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-17dd2198.js → GraphSolver-c7e6780e.js} +13 -11
  51. flowfile/web/static/assets/{GroupBy-6b039e18.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-24d0f113.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-34639209.js → ManualInput-8d3374b2.js} +170 -116
  59. flowfile/web/static/assets/{MultiSelect-0e8724a3.js → MultiSelect-ad1b6243.js} +2 -2
  60. flowfile/web/static/assets/{MultiSelect.vue_vue_type_script_setup_true_lang-b0e538c2.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-3d63a470.js → NumericInput-7100234c.js} +2 -2
  64. flowfile/web/static/assets/{NumericInput.vue_vue_type_script_setup_true_lang-e0edeccc.js → NumericInput.vue_vue_type_script_setup_true_lang-5130219f.js} +5 -2
  65. flowfile/web/static/assets/{Output-283fe388.css → Output-35e97000.css} +6 -6
  66. flowfile/web/static/assets/{Output-edea9802.js → Output-f5efd2aa.js} +12 -9
  67. flowfile/web/static/assets/{GraphSolver-f0cb7bfb.css → Pivot-0eda81b4.css} +5 -5
  68. flowfile/web/static/assets/{Pivot-61d19301.js → Pivot-d981d23c.js} +11 -9
  69. flowfile/web/static/assets/PivotValidation-0e905b1a.css +13 -0
  70. flowfile/web/static/assets/{PivotValidation-f97fec5b.js → PivotValidation-39386e95.js} +3 -3
  71. flowfile/web/static/assets/PivotValidation-41b57ad6.css +13 -0
  72. flowfile/web/static/assets/{PivotValidation-de9f43fe.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-bc3c9984.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-e808b239.css → Read-36e7bd51.css} +12 -12
  78. flowfile/web/static/assets/{Read-64a3f259.js → Read-aec2e377.js} +14 -11
  79. flowfile/web/static/assets/{RecordCount-3d5039be.js → RecordCount-78ed6845.js} +6 -4
  80. flowfile/web/static/assets/{RecordId-597510e0.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-df51adbe.js → SQLQueryComponent-48c72f5b.js} +3 -3
  83. flowfile/web/static/assets/{Sample-4be0a507.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-4839be57.js → SecretsView-17df66ee.js} +35 -36
  87. flowfile/web/static/assets/SecretsView-aa291340.css +38 -0
  88. flowfile/web/static/assets/{Select-9b72f201.js → Select-0aee4c54.js} +9 -7
  89. flowfile/web/static/assets/{SettingsSection-f0f75a42.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-e1e9c953.js → SettingsSection-cd341bb6.js} +3 -3
  94. flowfile/web/static/assets/{SettingsSection-7ded385d.js → SettingsSection-f2002a6d.js} +3 -3
  95. flowfile/web/static/assets/{SingleSelect-6c777aac.js → SingleSelect-460cc0ea.js} +2 -2
  96. flowfile/web/static/assets/{SingleSelect.vue_vue_type_script_setup_true_lang-33e3ff9b.js → SingleSelect.vue_vue_type_script_setup_true_lang-30741bb2.js} +1 -1
  97. flowfile/web/static/assets/{SliderInput-7cb93e62.js → SliderInput-5d926864.js} +7 -4
  98. flowfile/web/static/assets/SliderInput-f2e4f23c.css +4 -0
  99. flowfile/web/static/assets/{Sort-6cbde21a.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-d9a40c11.js → TextInput-a2d0bfbd.js} +2 -2
  102. flowfile/web/static/assets/{TextInput.vue_vue_type_script_setup_true_lang-5896c375.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-c4fcbf4d.js → TextToRows-918945f7.js} +11 -10
  105. flowfile/web/static/assets/{ToggleSwitch-4ef91d19.js → ToggleSwitch-f0ef5196.js} +2 -2
  106. flowfile/web/static/assets/{ToggleSwitch.vue_vue_type_script_setup_true_lang-38478c20.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-a03f512c.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-bfe9b996.js → Union-e8ab8c86.js} +8 -6
  111. flowfile/web/static/assets/{Unique-5d023a27.js → Unique-8cd4f976.js} +13 -10
  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-91cc5354.js → Unpivot-8da14095.js} +10 -8
  115. flowfile/web/static/assets/{UnpivotValidation-7ee2de44.js → UnpivotValidation-6f7d89ff.js} +3 -3
  116. flowfile/web/static/assets/UnpivotValidation-d5ca3b7b.css +13 -0
  117. flowfile/web/static/assets/{VueGraphicWalker-e51b9924.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-cf1221f0.js → api-24483f0d.js} +1 -1
  120. flowfile/web/static/assets/{api-c1bad5ca.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-614b998d.js → dropDown-ac0fda9d.js} +3 -3
  123. flowfile/web/static/assets/{fullEditor-f7971590.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-4fe5f36b.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-5429bbf8.js → index-fb6493ae.js} +41626 -40867
  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-076b85ab.js → outputCsv-8f8ba42d.js} +3 -3
  134. flowfile/web/static/assets/outputCsv-b9a072af.css +2499 -0
  135. flowfile/web/static/assets/{outputExcel-0fd17dbe.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-b61e0847.js → outputParquet-07c81f65.js} +4 -4
  138. flowfile/web/static/assets/outputParquet-54597c3c.css +4 -0
  139. flowfile/web/static/assets/{readCsv-a8bb8b61.js → readCsv-07f6d9ad.js} +3 -3
  140. flowfile/web/static/assets/{readCsv-c767cb37.css → readCsv-3bfac4c3.css} +15 -15
  141. flowfile/web/static/assets/{readExcel-806d2826.css → readExcel-3db6b763.css} +13 -13
  142. flowfile/web/static/assets/{readExcel-67b4aee0.js → readExcel-ed69bc8f.js} +5 -5
  143. flowfile/web/static/assets/{readParquet-48c81530.css → readParquet-c5244ad5.css} +4 -4
  144. flowfile/web/static/assets/{readParquet-92ce1dbc.js → readParquet-e3ed4528.js} +3 -3
  145. flowfile/web/static/assets/secrets.api-002e7d7e.js +65 -0
  146. flowfile/web/static/assets/{selectDynamic-92e25ee3.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-41b0e0d7.js → vue-codemirror.esm-0965f39f.js} +31 -640
  149. flowfile/web/static/assets/{vue-content-loader.es-2c8e608f.js → vue-content-loader.es-c506ad97.js} +1 -1
  150. flowfile/web/static/index.html +2 -2
  151. {flowfile-0.5.1.dist-info → flowfile-0.5.3.dist-info}/METADATA +2 -3
  152. flowfile-0.5.3.dist-info/RECORD +402 -0
  153. flowfile_core/__init__.py +13 -6
  154. flowfile_core/auth/jwt.py +51 -16
  155. flowfile_core/auth/models.py +32 -7
  156. flowfile_core/auth/password.py +89 -0
  157. flowfile_core/auth/secrets.py +8 -6
  158. flowfile_core/configs/__init__.py +9 -7
  159. flowfile_core/configs/flow_logger.py +15 -14
  160. flowfile_core/configs/node_store/__init__.py +72 -4
  161. flowfile_core/configs/node_store/nodes.py +155 -172
  162. flowfile_core/configs/node_store/user_defined_node_registry.py +108 -27
  163. flowfile_core/configs/settings.py +28 -15
  164. flowfile_core/database/connection.py +7 -6
  165. flowfile_core/database/init_db.py +96 -2
  166. flowfile_core/database/models.py +3 -1
  167. flowfile_core/fileExplorer/__init__.py +17 -0
  168. flowfile_core/fileExplorer/funcs.py +123 -57
  169. flowfile_core/fileExplorer/utils.py +10 -11
  170. flowfile_core/flowfile/_extensions/real_time_interface.py +10 -8
  171. flowfile_core/flowfile/analytics/analytics_processor.py +26 -24
  172. flowfile_core/flowfile/analytics/graphic_walker.py +11 -12
  173. flowfile_core/flowfile/analytics/utils.py +1 -1
  174. flowfile_core/flowfile/code_generator/code_generator.py +358 -244
  175. flowfile_core/flowfile/connection_manager/_connection_manager.py +6 -5
  176. flowfile_core/flowfile/connection_manager/models.py +1 -1
  177. flowfile_core/flowfile/database_connection_manager/db_connections.py +60 -44
  178. flowfile_core/flowfile/database_connection_manager/models.py +1 -1
  179. flowfile_core/flowfile/extensions.py +17 -12
  180. flowfile_core/flowfile/flow_data_engine/cloud_storage_reader.py +34 -32
  181. flowfile_core/flowfile/flow_data_engine/create/funcs.py +115 -83
  182. flowfile_core/flowfile/flow_data_engine/flow_data_engine.py +481 -423
  183. flowfile_core/flowfile/flow_data_engine/flow_file_column/interface.py +2 -2
  184. flowfile_core/flowfile/flow_data_engine/flow_file_column/main.py +92 -52
  185. flowfile_core/flowfile/flow_data_engine/flow_file_column/polars_type.py +12 -11
  186. flowfile_core/flowfile/flow_data_engine/flow_file_column/type_registry.py +6 -6
  187. flowfile_core/flowfile/flow_data_engine/flow_file_column/utils.py +26 -30
  188. flowfile_core/flowfile/flow_data_engine/fuzzy_matching/prepare_for_fuzzy_match.py +31 -20
  189. flowfile_core/flowfile/flow_data_engine/join/__init__.py +1 -1
  190. flowfile_core/flowfile/flow_data_engine/join/utils.py +11 -9
  191. flowfile_core/flowfile/flow_data_engine/join/verify_integrity.py +14 -15
  192. flowfile_core/flowfile/flow_data_engine/pivot_table.py +5 -7
  193. flowfile_core/flowfile/flow_data_engine/polars_code_parser.py +95 -82
  194. flowfile_core/flowfile/flow_data_engine/read_excel_tables.py +66 -65
  195. flowfile_core/flowfile/flow_data_engine/sample_data.py +27 -21
  196. flowfile_core/flowfile/flow_data_engine/subprocess_operations/__init__.py +1 -1
  197. flowfile_core/flowfile/flow_data_engine/subprocess_operations/models.py +13 -11
  198. flowfile_core/flowfile/flow_data_engine/subprocess_operations/subprocess_operations.py +190 -127
  199. flowfile_core/flowfile/flow_data_engine/threaded_processes.py +8 -8
  200. flowfile_core/flowfile/flow_data_engine/utils.py +99 -67
  201. flowfile_core/flowfile/flow_graph.py +918 -571
  202. flowfile_core/flowfile/flow_graph_utils.py +31 -49
  203. flowfile_core/flowfile/flow_node/flow_node.py +330 -233
  204. flowfile_core/flowfile/flow_node/models.py +53 -41
  205. flowfile_core/flowfile/flow_node/schema_callback.py +14 -19
  206. flowfile_core/flowfile/graph_tree/graph_tree.py +41 -41
  207. flowfile_core/flowfile/handler.py +80 -30
  208. flowfile_core/flowfile/manage/compatibility_enhancements.py +209 -126
  209. flowfile_core/flowfile/manage/io_flowfile.py +54 -57
  210. flowfile_core/flowfile/node_designer/__init__.py +15 -13
  211. flowfile_core/flowfile/node_designer/_type_registry.py +34 -37
  212. flowfile_core/flowfile/node_designer/custom_node.py +162 -36
  213. flowfile_core/flowfile/node_designer/ui_components.py +135 -34
  214. flowfile_core/flowfile/schema_callbacks.py +71 -51
  215. flowfile_core/flowfile/setting_generator/__init__.py +0 -1
  216. flowfile_core/flowfile/setting_generator/setting_generator.py +6 -5
  217. flowfile_core/flowfile/setting_generator/settings.py +64 -53
  218. flowfile_core/flowfile/sources/external_sources/base_class.py +12 -10
  219. flowfile_core/flowfile/sources/external_sources/custom_external_sources/external_source.py +27 -17
  220. flowfile_core/flowfile/sources/external_sources/custom_external_sources/sample_users.py +9 -9
  221. flowfile_core/flowfile/sources/external_sources/factory.py +0 -1
  222. flowfile_core/flowfile/sources/external_sources/sql_source/models.py +45 -31
  223. flowfile_core/flowfile/sources/external_sources/sql_source/sql_source.py +198 -73
  224. flowfile_core/flowfile/sources/external_sources/sql_source/utils.py +250 -196
  225. flowfile_core/flowfile/util/calculate_layout.py +9 -13
  226. flowfile_core/flowfile/util/execution_orderer.py +25 -17
  227. flowfile_core/flowfile/util/node_skipper.py +4 -4
  228. flowfile_core/flowfile/utils.py +19 -21
  229. flowfile_core/main.py +26 -19
  230. flowfile_core/routes/auth.py +284 -11
  231. flowfile_core/routes/cloud_connections.py +25 -25
  232. flowfile_core/routes/logs.py +21 -29
  233. flowfile_core/routes/public.py +3 -3
  234. flowfile_core/routes/routes.py +70 -34
  235. flowfile_core/routes/secrets.py +25 -27
  236. flowfile_core/routes/user_defined_components.py +483 -4
  237. flowfile_core/run_lock.py +0 -1
  238. flowfile_core/schemas/__init__.py +4 -6
  239. flowfile_core/schemas/analysis_schemas/graphic_walker_schemas.py +55 -55
  240. flowfile_core/schemas/cloud_storage_schemas.py +59 -53
  241. flowfile_core/schemas/input_schema.py +231 -144
  242. flowfile_core/schemas/output_model.py +49 -34
  243. flowfile_core/schemas/schemas.py +116 -89
  244. flowfile_core/schemas/transform_schema.py +518 -263
  245. flowfile_core/schemas/yaml_types.py +21 -7
  246. flowfile_core/secret_manager/secret_manager.py +17 -13
  247. flowfile_core/types.py +29 -9
  248. flowfile_core/utils/arrow_reader.py +7 -6
  249. flowfile_core/utils/excel_file_manager.py +3 -3
  250. flowfile_core/utils/fileManager.py +7 -7
  251. flowfile_core/utils/fl_executor.py +8 -10
  252. flowfile_core/utils/utils.py +4 -4
  253. flowfile_core/utils/validate_setup.py +5 -4
  254. flowfile_frame/__init__.py +106 -51
  255. flowfile_frame/adapters.py +2 -9
  256. flowfile_frame/adding_expr.py +73 -32
  257. flowfile_frame/cloud_storage/frame_helpers.py +27 -23
  258. flowfile_frame/cloud_storage/secret_manager.py +12 -26
  259. flowfile_frame/config.py +2 -5
  260. flowfile_frame/expr.py +311 -218
  261. flowfile_frame/expr.pyi +160 -159
  262. flowfile_frame/expr_name.py +23 -23
  263. flowfile_frame/flow_frame.py +571 -476
  264. flowfile_frame/flow_frame.pyi +123 -104
  265. flowfile_frame/flow_frame_methods.py +227 -246
  266. flowfile_frame/group_frame.py +50 -20
  267. flowfile_frame/join.py +2 -2
  268. flowfile_frame/lazy.py +129 -87
  269. flowfile_frame/lazy_methods.py +83 -30
  270. flowfile_frame/list_name_space.py +55 -50
  271. flowfile_frame/selectors.py +148 -68
  272. flowfile_frame/series.py +9 -7
  273. flowfile_frame/utils.py +19 -21
  274. flowfile_worker/__init__.py +12 -7
  275. flowfile_worker/configs.py +11 -19
  276. flowfile_worker/create/__init__.py +14 -9
  277. flowfile_worker/create/funcs.py +114 -77
  278. flowfile_worker/create/models.py +46 -43
  279. flowfile_worker/create/pl_types.py +14 -15
  280. flowfile_worker/create/read_excel_tables.py +34 -41
  281. flowfile_worker/create/utils.py +22 -19
  282. flowfile_worker/external_sources/s3_source/main.py +18 -51
  283. flowfile_worker/external_sources/s3_source/models.py +34 -27
  284. flowfile_worker/external_sources/sql_source/main.py +8 -5
  285. flowfile_worker/external_sources/sql_source/models.py +13 -9
  286. flowfile_worker/flow_logger.py +10 -8
  287. flowfile_worker/funcs.py +214 -155
  288. flowfile_worker/main.py +11 -17
  289. flowfile_worker/models.py +35 -28
  290. flowfile_worker/process_manager.py +2 -3
  291. flowfile_worker/routes.py +121 -90
  292. flowfile_worker/secrets.py +9 -6
  293. flowfile_worker/spawner.py +80 -49
  294. flowfile_worker/utils.py +3 -2
  295. shared/__init__.py +2 -7
  296. shared/storage_config.py +25 -13
  297. test_utils/postgres/commands.py +3 -2
  298. test_utils/postgres/fixtures.py +9 -9
  299. test_utils/s3/commands.py +1 -1
  300. test_utils/s3/data_generator.py +3 -4
  301. test_utils/s3/demo_data_generator.py +4 -7
  302. test_utils/s3/fixtures.py +7 -5
  303. tools/migrate/__init__.py +1 -1
  304. tools/migrate/__main__.py +16 -29
  305. tools/migrate/legacy_schemas.py +251 -190
  306. tools/migrate/migrate.py +193 -181
  307. tools/migrate/tests/conftest.py +1 -3
  308. tools/migrate/tests/test_migrate.py +36 -41
  309. tools/migrate/tests/test_migration_e2e.py +28 -29
  310. tools/migrate/tests/test_node_migrations.py +50 -20
  311. flowfile/web/static/assets/CloudConnectionManager-2dfdce2f.css +0 -86
  312. flowfile/web/static/assets/CustomNode-74a37f74.css +0 -32
  313. flowfile/web/static/assets/DatabaseManager-30fa27e5.css +0 -64
  314. flowfile/web/static/assets/Filter-9b6d08db.js +0 -164
  315. flowfile/web/static/assets/Filter-f62091b3.css +0 -20
  316. flowfile/web/static/assets/ManualInput-3246a08d.css +0 -96
  317. flowfile/web/static/assets/PivotValidation-891ddfb0.css +0 -13
  318. flowfile/web/static/assets/PivotValidation-c46cd420.css +0 -13
  319. flowfile/web/static/assets/SliderInput-b8fb6a8c.css +0 -4
  320. flowfile/web/static/assets/UnpivotValidation-0d240eeb.css +0 -13
  321. flowfile/web/static/assets/nodeInput-5d0d6b79.js +0 -41
  322. flowfile/web/static/assets/outputCsv-9cc59e0b.css +0 -2499
  323. flowfile/web/static/assets/outputParquet-cf8cf3f2.css +0 -4
  324. flowfile/web/static/assets/secretApi-68435402.js +0 -46
  325. flowfile/web/static/assets/vue-codemirror-bccfde04.css +0 -32
  326. flowfile-0.5.1.dist-info/RECORD +0 -388
  327. {flowfile-0.5.1.dist-info → flowfile-0.5.3.dist-info}/WHEEL +0 -0
  328. {flowfile-0.5.1.dist-info → flowfile-0.5.3.dist-info}/entry_points.txt +0 -0
  329. {flowfile-0.5.1.dist-info → flowfile-0.5.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,4 @@
1
-
2
1
  from pydantic import BaseModel, SecretStr
3
- from typing import Optional, List
4
2
 
5
3
 
6
4
  class Token(BaseModel):
@@ -9,21 +7,48 @@ class Token(BaseModel):
9
7
 
10
8
 
11
9
  class TokenData(BaseModel):
12
- username: Optional[str] = None
10
+ username: str | None = None
13
11
 
14
12
 
15
13
  class User(BaseModel):
16
14
  username: str
17
- id: Optional[int] = None
18
- email: Optional[str] = None
19
- full_name: Optional[str] = None
20
- disabled: Optional[bool] = False
15
+ id: int | None = None
16
+ email: str | None = None
17
+ full_name: str | None = None
18
+ disabled: bool | None = False
19
+ is_admin: bool | None = False
20
+ must_change_password: bool | None = False
21
21
 
22
22
 
23
23
  class UserInDB(User):
24
24
  hashed_password: str
25
25
 
26
26
 
27
+ class UserCreate(BaseModel):
28
+ """Model for creating a new user (admin only)"""
29
+ username: str
30
+ password: str
31
+ email: str | None = None
32
+ full_name: str | None = None
33
+ is_admin: bool = False
34
+
35
+
36
+ class UserUpdate(BaseModel):
37
+ """Model for updating a user (admin only)"""
38
+ email: str | None = None
39
+ full_name: str | None = None
40
+ disabled: bool | None = None
41
+ is_admin: bool | None = None
42
+ password: str | None = None # Optional password change
43
+ must_change_password: bool | None = None
44
+
45
+
46
+ class ChangePassword(BaseModel):
47
+ """Model for user changing their own password"""
48
+ current_password: str
49
+ new_password: str
50
+
51
+
27
52
  class SecretInput(BaseModel):
28
53
  name: str
29
54
  value: SecretStr
@@ -0,0 +1,89 @@
1
+ """Password hashing and verification utilities."""
2
+
3
+ import re
4
+ from passlib.context import CryptContext
5
+
6
+ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
7
+
8
+ # Password requirements
9
+ PASSWORD_MIN_LENGTH = 8
10
+ PASSWORD_REQUIREMENTS = {
11
+ "min_length": PASSWORD_MIN_LENGTH,
12
+ "require_number": True,
13
+ "require_special": True,
14
+ "special_chars": "!@#$%^&*()_+-=[]{}|;:,.<>?"
15
+ }
16
+
17
+
18
+ class PasswordValidationError(Exception):
19
+ """Raised when password doesn't meet requirements."""
20
+ pass
21
+
22
+
23
+ def validate_password(password: str) -> tuple[bool, str]:
24
+ """
25
+ Validate password against security requirements.
26
+
27
+ Requirements:
28
+ - Minimum 8 characters
29
+ - At least one number
30
+ - At least one special character
31
+
32
+ Args:
33
+ password: The plain text password to validate
34
+
35
+ Returns:
36
+ Tuple of (is_valid, error_message)
37
+ """
38
+ if len(password) < PASSWORD_MIN_LENGTH:
39
+ return False, f"Password must be at least {PASSWORD_MIN_LENGTH} characters long"
40
+
41
+ if not re.search(r'\d', password):
42
+ return False, "Password must contain at least one number"
43
+
44
+ if not re.search(r'[!@#$%^&*()_+\-=\[\]{}|;:,.<>?]', password):
45
+ return False, "Password must contain at least one special character (!@#$%^&*()_+-=[]{}|;:,.<>?)"
46
+
47
+ return True, ""
48
+
49
+
50
+ def validate_password_or_raise(password: str) -> None:
51
+ """
52
+ Validate password and raise exception if invalid.
53
+
54
+ Args:
55
+ password: The plain text password to validate
56
+
57
+ Raises:
58
+ PasswordValidationError: If password doesn't meet requirements
59
+ """
60
+ is_valid, error_message = validate_password(password)
61
+ if not is_valid:
62
+ raise PasswordValidationError(error_message)
63
+
64
+
65
+ def verify_password(plain: str, hashed: str) -> bool:
66
+ """
67
+ Verify a plain password against a hashed password.
68
+
69
+ Args:
70
+ plain: The plain text password
71
+ hashed: The hashed password to verify against
72
+
73
+ Returns:
74
+ True if the password matches, False otherwise
75
+ """
76
+ return pwd_context.verify(plain, hashed)
77
+
78
+
79
+ def get_password_hash(password: str) -> str:
80
+ """
81
+ Hash a plain text password.
82
+
83
+ Args:
84
+ password: The plain text password to hash
85
+
86
+ Returns:
87
+ The hashed password
88
+ """
89
+ return pwd_context.hash(password)
@@ -1,11 +1,13 @@
1
1
  """
2
2
  Secure storage module for FlowFile credentials and secrets.
3
3
  """
4
- from cryptography.fernet import Fernet
5
- import os
6
- from pathlib import Path
4
+
7
5
  import json
8
6
  import logging
7
+ import os
8
+ from pathlib import Path
9
+
10
+ from cryptography.fernet import Fernet
9
11
 
10
12
  logger = logging.getLogger(__name__)
11
13
 
@@ -15,7 +17,7 @@ class SecureStorage:
15
17
 
16
18
  def __init__(self):
17
19
  env = os.environ.get("FLOWFILE_MODE")
18
- logger.debug(f'Using secure storage in {env} mode')
20
+ logger.debug(f"Using secure storage in {env} mode")
19
21
  if os.environ.get("FLOWFILE_MODE") == "electron":
20
22
  app_data = os.environ.get("APPDATA") or os.path.expanduser("~/.config")
21
23
  self.storage_path = Path(app_data) / "flowfile"
@@ -148,7 +150,7 @@ def get_docker_secret_key():
148
150
  secret_path = "/run/secrets/flowfile_master_key"
149
151
  if os.path.exists(secret_path):
150
152
  try:
151
- with open(secret_path, "r") as f:
153
+ with open(secret_path) as f:
152
154
  return f.read().strip()
153
155
  except Exception as e:
154
156
  logger.error(f"Failed to read master key from Docker secret: {e}")
@@ -168,7 +170,7 @@ def get_master_key():
168
170
  Returns:
169
171
  str: The master encryption key
170
172
  """
171
- if os.environ.get("RUNNING_IN_DOCKER") == "true":
173
+ if os.environ.get("FLOWFILE_MODE") == "docker":
172
174
  return get_docker_secret_key()
173
175
 
174
176
  key = get_password("flowfile", "master_key")
@@ -1,13 +1,14 @@
1
1
  # flowfile_core/flowfile_core/configs/__init__.py
2
2
  import logging
3
+ import os
3
4
  import sys
4
5
  from pathlib import Path
5
- import os
6
6
 
7
- os.environ["FLOWFILE_MODE"] = "electron"
7
+ if "FLOWFILE_MODE" not in os.environ:
8
+ os.environ["FLOWFILE_MODE"] = "electron"
8
9
 
9
10
  # Create and configure the logger
10
- logger = logging.getLogger('PipelineHandler')
11
+ logger = logging.getLogger("PipelineHandler")
11
12
  logger.setLevel(logging.INFO)
12
13
  logger.propagate = False
13
14
 
@@ -17,9 +18,9 @@ if logger.hasHandlers():
17
18
 
18
19
  # Try to determine the best output stream
19
20
  output_stream = None
20
- if hasattr(sys.stdout, 'isatty') and sys.stdout.isatty():
21
+ if hasattr(sys.stdout, "isatty") and sys.stdout.isatty():
21
22
  output_stream = sys.stdout
22
- elif hasattr(sys.stderr, 'isatty') and sys.stderr.isatty():
23
+ elif hasattr(sys.stderr, "isatty") and sys.stderr.isatty():
23
24
  output_stream = sys.stderr
24
25
  else:
25
26
  # Use __stdout__ for debugger environments (PyDev, PyCharm, etc.)
@@ -29,7 +30,7 @@ console_handler = logging.StreamHandler(output_stream)
29
30
  console_handler.setLevel(logging.INFO)
30
31
 
31
32
  # Create formatter
32
- formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
33
+ formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
33
34
  console_handler.setFormatter(formatter)
34
35
 
35
36
  logger.addHandler(console_handler)
@@ -37,10 +38,11 @@ logger.addHandler(console_handler)
37
38
  # Create logs directory in temp at startup
38
39
  try:
39
40
  from tempfile import gettempdir
41
+
40
42
  log_dir = Path(gettempdir()) / "flowfile_logs"
41
43
  log_dir.mkdir(exist_ok=True)
42
44
  except Exception as e:
43
45
  logger.warning(f"Failed to create logs directory: {e}")
44
46
 
45
47
  # Initialize vault
46
- logger.info("Logging system initialized")
48
+ logger.info("Logging system initialized")
@@ -1,14 +1,15 @@
1
1
  import logging
2
- from pathlib import Path
3
- from datetime import datetime
4
- import os
5
2
  import logging.handlers
3
+ import os
6
4
  import queue
7
5
  import threading
6
+ from datetime import datetime
7
+ from pathlib import Path
8
+
8
9
  from shared.storage_config import storage
9
10
 
10
11
  _process_safe_queue = queue.Queue(-1)
11
- main_logger = logging.getLogger('PipelineHandler')
12
+ main_logger = logging.getLogger("PipelineHandler")
12
13
 
13
14
 
14
15
  class NodeLogger:
@@ -38,6 +39,7 @@ class NodeLogger:
38
39
 
39
40
  class FlowLogger:
40
41
  """Thread-safe logger for flow execution"""
42
+
41
43
  _instances = {}
42
44
  _instances_lock = threading.RLock()
43
45
  _queue_listener = None
@@ -47,7 +49,7 @@ class FlowLogger:
47
49
  def handle_extra_log_info(flow_id: int, extra: dict = None) -> dict:
48
50
  if extra is None:
49
51
  extra = {}
50
- extra['flow_id'] = flow_id
52
+ extra["flow_id"] = flow_id
51
53
  return extra
52
54
 
53
55
  def __new__(cls, flow_id: int, clear_existing_logs: bool = False):
@@ -75,7 +77,7 @@ class FlowLogger:
75
77
 
76
78
  def _setup_new_logger(self):
77
79
  """Creates a new logger instance with appropriate handlers"""
78
- logger_name = f'FlowExecution.{self.flow_id}'
80
+ logger_name = f"FlowExecution.{self.flow_id}"
79
81
  self._logger = logging.getLogger(logger_name)
80
82
  self._logger.setLevel(logging.INFO)
81
83
  self.setup_logging()
@@ -131,7 +133,7 @@ class FlowLogger:
131
133
 
132
134
  try:
133
135
  # Create an empty file
134
- with open(self.log_file_path, 'w') as f:
136
+ with open(self.log_file_path, "w") as f:
135
137
  pass
136
138
 
137
139
  # Re-setup the logger
@@ -154,9 +156,7 @@ class FlowLogger:
154
156
  """Start the queue listener for asynchronous logging"""
155
157
  queue_handler = logging.handlers.QueueHandler(_process_safe_queue)
156
158
  cls._queue_listener = logging.handlers.QueueListener(
157
- _process_safe_queue,
158
- queue_handler,
159
- respect_handler_level=True
159
+ _process_safe_queue, queue_handler, respect_handler_level=True
160
160
  )
161
161
  cls._queue_listener.start()
162
162
 
@@ -193,7 +193,7 @@ class FlowLogger:
193
193
 
194
194
  # Add file handler
195
195
  file_handler = logging.FileHandler(self.log_file_path)
196
- formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
196
+ formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
197
197
  file_handler.setFormatter(formatter)
198
198
  self._logger.addHandler(file_handler)
199
199
 
@@ -214,7 +214,8 @@ class FlowLogger:
214
214
  else:
215
215
  # If still can't get lock, proceed anyway
216
216
  main_logger.warning(
217
- f"Could not acquire lock for flow {self.flow_id}, proceeding with file clearing anyway")
217
+ f"Could not acquire lock for flow {self.flow_id}, proceeding with file clearing anyway"
218
+ )
218
219
  self._clear_log_impl()
219
220
 
220
221
  def _clear_log_impl(self):
@@ -223,7 +224,7 @@ class FlowLogger:
223
224
  # Ensure parent directory exists
224
225
  self.refresh_logger_if_needed()
225
226
  # Truncate file
226
- with open(self.log_file_path, 'w') as f:
227
+ with open(self.log_file_path, "w") as f:
227
228
  pass
228
229
  main_logger.info(f"Log file cleared for flow {self.flow_id}")
229
230
  except Exception as e:
@@ -409,7 +410,7 @@ def read_log_from_line(log_file_path: Path, start_line: int = 0):
409
410
  """Read log file content starting from a specific line"""
410
411
  lines = []
411
412
  try:
412
- with open(log_file_path, "r") as file:
413
+ with open(log_file_path) as file:
413
414
  # Skip lines efficiently if needed
414
415
  if start_line > 0:
415
416
  for _ in range(start_line):
@@ -1,10 +1,17 @@
1
- from flowfile_core.configs.node_store.user_defined_node_registry import get_all_nodes_from_standard_location
1
+ import logging
2
+
2
3
  from flowfile_core.configs.node_store.nodes import get_all_standard_nodes
3
- from flowfile_core.schemas.schemas import NodeTemplate
4
+ from flowfile_core.configs.node_store.user_defined_node_registry import (
5
+ get_all_nodes_from_standard_location,
6
+ load_single_node_from_file,
7
+ unload_node_by_name,
8
+ )
4
9
  from flowfile_core.flowfile.node_designer.custom_node import CustomNodeBase
10
+ from flowfile_core.schemas.schemas import NodeTemplate
5
11
 
12
+ logger = logging.getLogger(__name__)
6
13
 
7
- nodes_with_defaults = {'sample', 'sort', 'union', 'select', 'record_count'}
14
+ nodes_with_defaults = {"sample", "sort", "union", "select", "record_count"}
8
15
 
9
16
 
10
17
  def register_custom_node(node: NodeTemplate):
@@ -18,6 +25,68 @@ def add_to_custom_node_store(custom_node: type[CustomNodeBase]):
18
25
  register_custom_node(custom_node().to_node_template())
19
26
 
20
27
 
28
+ def remove_from_custom_node_store(node_key: str, file_stem: str = None) -> bool:
29
+ """
30
+ Remove a custom node from both CUSTOM_NODE_STORE and node registries.
31
+
32
+ Args:
33
+ node_key: The key/item name of the node to remove
34
+ file_stem: Optional file name stem (without .py) to use as fallback for matching
35
+
36
+ Returns:
37
+ True if the node was found and removed, False otherwise
38
+ """
39
+ removed = False
40
+
41
+ logger.info(f"Attempting to remove node with key: '{node_key}' (file_stem: '{file_stem}')")
42
+ logger.info(f"Current CUSTOM_NODE_STORE keys: {list(CUSTOM_NODE_STORE.keys())}")
43
+ logger.info(f"Current nodes_list items: {[n.item for n in nodes_list if hasattr(n, 'item')]}")
44
+
45
+ # Try to find the key - use exact match first, then fallback to file_stem
46
+ actual_key = None
47
+ if node_key in CUSTOM_NODE_STORE:
48
+ actual_key = node_key
49
+ elif file_stem and file_stem in CUSTOM_NODE_STORE:
50
+ actual_key = file_stem
51
+ logger.info(f"Using file_stem '{file_stem}' as key instead of '{node_key}'")
52
+
53
+ # Remove from CUSTOM_NODE_STORE
54
+ if actual_key and actual_key in CUSTOM_NODE_STORE:
55
+ del CUSTOM_NODE_STORE[actual_key]
56
+ logger.info(f"Removed '{actual_key}' from CUSTOM_NODE_STORE")
57
+ removed = True
58
+ else:
59
+ logger.warning(f"Key '{node_key}' (or file_stem '{file_stem}') not found in CUSTOM_NODE_STORE")
60
+
61
+ # Remove from node_dict - try both keys
62
+ key_to_use = actual_key or node_key
63
+ if key_to_use in node_dict:
64
+ del node_dict[key_to_use]
65
+ logger.info(f"Removed '{key_to_use}' from node_dict")
66
+ elif file_stem and file_stem in node_dict:
67
+ del node_dict[file_stem]
68
+ logger.info(f"Removed '{file_stem}' from node_dict")
69
+
70
+ # Remove from nodes_list - try both keys
71
+ removed_from_list = False
72
+ for i, node in enumerate(nodes_list):
73
+ if node.item == key_to_use or (file_stem and node.item == file_stem):
74
+ nodes_list.pop(i)
75
+ logger.info(f"Removed '{node.item}' from nodes_list at index {i}")
76
+ removed_from_list = True
77
+ break
78
+
79
+ if not removed_from_list:
80
+ logger.warning(f"Key '{node_key}' not found in nodes_list")
81
+
82
+ # Clean up module cache
83
+ unload_node_by_name(node_key)
84
+ if file_stem and file_stem != node_key:
85
+ unload_node_by_name(file_stem)
86
+
87
+ return removed
88
+
89
+
21
90
  CUSTOM_NODE_STORE = get_all_nodes_from_standard_location()
22
91
  nodes_list, node_dict, node_defaults = get_all_standard_nodes()
23
92
 
@@ -26,5 +95,4 @@ for custom_node in CUSTOM_NODE_STORE.values():
26
95
 
27
96
 
28
97
  def check_if_has_default_setting(node_item: str):
29
-
30
98
  return node_item in nodes_with_defaults