@solidxai/core-ui 0.1.13-beta.2 → 0.1.13-beta.4

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 (501) hide show
  1. package/dist/components/auth/SolidOTPVerify.d.ts +3 -0
  2. package/dist/components/auth/SolidOTPVerify.d.ts.map +1 -0
  3. package/dist/components/auth/SolidOTPVerify.js +67 -0
  4. package/dist/components/auth/SolidOTPVerify.js.map +1 -0
  5. package/dist/components/auth/SolidOTPVerify.tsx +133 -0
  6. package/dist/components/common/AuthBanner.d.ts +3 -0
  7. package/dist/components/common/AuthBanner.d.ts.map +1 -0
  8. package/dist/components/common/AuthBanner.js +15 -0
  9. package/dist/components/common/AuthBanner.js.map +1 -0
  10. package/dist/components/common/AuthBanner.tsx +41 -0
  11. package/dist/components/common/SingleSelectAutoCompleteField.d.ts +2 -0
  12. package/dist/components/common/SingleSelectAutoCompleteField.d.ts.map +1 -0
  13. package/dist/components/common/SingleSelectAutoCompleteField.js +92 -0
  14. package/dist/components/common/SingleSelectAutoCompleteField.js.map +1 -0
  15. package/dist/components/common/SingleSelectAutoCompleteField.tsx +73 -0
  16. package/dist/components/common/SolidExportStepper.d.ts +12 -0
  17. package/dist/components/common/SolidExportStepper.d.ts.map +1 -0
  18. package/dist/components/common/SolidExportStepper.js +30 -0
  19. package/dist/components/common/SolidExportStepper.js.map +1 -0
  20. package/dist/components/common/SolidExportStepper.tsx +135 -0
  21. package/dist/components/core/card/SolidCardView.d.ts.map +1 -1
  22. package/dist/components/core/card/SolidCardView.js +6 -11
  23. package/dist/components/core/card/SolidCardView.js.map +1 -1
  24. package/dist/components/core/card/SolidCardView.tsx +6 -11
  25. package/dist/components/core/card/SolidCardViewConfigure.d.ts.map +1 -1
  26. package/dist/components/core/card/SolidCardViewConfigure.js +3 -7
  27. package/dist/components/core/card/SolidCardViewConfigure.js.map +1 -1
  28. package/dist/components/core/card/SolidCardViewConfigure.tsx +3 -9
  29. package/dist/components/core/common/LoadDynamicJsxComponent.d.ts +2 -0
  30. package/dist/components/core/common/LoadDynamicJsxComponent.d.ts.map +1 -0
  31. package/dist/components/core/common/LoadDynamicJsxComponent.js +50 -0
  32. package/dist/components/core/common/LoadDynamicJsxComponent.js.map +1 -0
  33. package/dist/components/core/common/LoadDynamicJsxComponent.tsx +70 -0
  34. package/dist/components/core/common/SolidGenericImport/SolidImportWrapper.d.ts +2 -0
  35. package/dist/components/core/common/SolidGenericImport/SolidImportWrapper.d.ts.map +1 -0
  36. package/dist/components/core/common/SolidGenericImport/SolidImportWrapper.js +16 -0
  37. package/dist/components/core/common/SolidGenericImport/SolidImportWrapper.js.map +1 -0
  38. package/dist/components/core/common/SolidGenericImport/SolidImportWrapper.tsx +29 -0
  39. package/dist/components/core/dashboard/DashboardFilter.d.ts +13 -0
  40. package/dist/components/core/dashboard/DashboardFilter.d.ts.map +1 -0
  41. package/dist/components/core/dashboard/DashboardFilter.js +299 -0
  42. package/dist/components/core/dashboard/DashboardFilter.js.map +1 -0
  43. package/dist/components/core/dashboard/DashboardFilter.tsx +348 -0
  44. package/dist/components/core/dashboard/PrimeDataTableWrapper.d.ts +3 -0
  45. package/dist/components/core/dashboard/PrimeDataTableWrapper.d.ts.map +1 -0
  46. package/dist/components/core/dashboard/PrimeDataTableWrapper.js +21 -0
  47. package/dist/components/core/dashboard/PrimeDataTableWrapper.js.map +1 -0
  48. package/dist/components/core/dashboard/PrimeDataTableWrapper.tsx +40 -0
  49. package/dist/components/core/dashboard/SolidDashboard.d.ts +28 -0
  50. package/dist/components/core/dashboard/SolidDashboard.d.ts.map +1 -0
  51. package/dist/components/core/dashboard/SolidDashboard.js +183 -0
  52. package/dist/components/core/dashboard/SolidDashboard.js.map +1 -0
  53. package/dist/components/core/dashboard/SolidDashboard.module.css +83 -0
  54. package/dist/components/core/dashboard/SolidDashboard.tsx +263 -0
  55. package/dist/components/core/dashboard/SolidDashboardBody.d.ts +24 -0
  56. package/dist/components/core/dashboard/SolidDashboardBody.d.ts.map +1 -0
  57. package/dist/components/core/dashboard/SolidDashboardBody.js +162 -0
  58. package/dist/components/core/dashboard/SolidDashboardBody.js.map +1 -0
  59. package/dist/components/core/dashboard/SolidDashboardBody.tsx +168 -0
  60. package/dist/components/core/dashboard/SolidDashboardFilterRequired.d.ts +2 -0
  61. package/dist/components/core/dashboard/SolidDashboardFilterRequired.d.ts.map +1 -0
  62. package/dist/components/core/dashboard/SolidDashboardFilterRequired.js +11 -0
  63. package/dist/components/core/dashboard/SolidDashboardFilterRequired.js.map +1 -0
  64. package/dist/components/core/dashboard/SolidDashboardFilterRequired.tsx +28 -0
  65. package/dist/components/core/dashboard/SolidDashboardHeader.d.ts +3 -0
  66. package/dist/components/core/dashboard/SolidDashboardHeader.d.ts.map +1 -0
  67. package/dist/components/core/dashboard/SolidDashboardHeader.js +6 -0
  68. package/dist/components/core/dashboard/SolidDashboardHeader.js.map +1 -0
  69. package/dist/components/core/dashboard/SolidDashboardHeader.tsx +10 -0
  70. package/dist/components/core/dashboard/SolidDashboardLoading.d.ts +2 -0
  71. package/dist/components/core/dashboard/SolidDashboardLoading.d.ts.map +1 -0
  72. package/dist/components/core/dashboard/SolidDashboardLoading.js +10 -0
  73. package/dist/components/core/dashboard/SolidDashboardLoading.js.map +1 -0
  74. package/dist/components/core/dashboard/SolidDashboardLoading.tsx +61 -0
  75. package/dist/components/core/dashboard/SolidDashboardNotAvailable.d.ts +3 -0
  76. package/dist/components/core/dashboard/SolidDashboardNotAvailable.d.ts.map +1 -0
  77. package/dist/components/core/dashboard/SolidDashboardNotAvailable.js +12 -0
  78. package/dist/components/core/dashboard/SolidDashboardNotAvailable.js.map +1 -0
  79. package/dist/components/core/dashboard/SolidDashboardNotAvailable.tsx +32 -0
  80. package/dist/components/core/dashboard/SolidDashboardRenderError.d.ts +2 -0
  81. package/dist/components/core/dashboard/SolidDashboardRenderError.d.ts.map +1 -0
  82. package/dist/components/core/dashboard/SolidDashboardRenderError.js +11 -0
  83. package/dist/components/core/dashboard/SolidDashboardRenderError.js.map +1 -0
  84. package/dist/components/core/dashboard/SolidDashboardRenderError.tsx +28 -0
  85. package/dist/components/core/dashboard/SolidDashboardVariable.d.ts +19 -0
  86. package/dist/components/core/dashboard/SolidDashboardVariable.d.ts.map +1 -0
  87. package/dist/components/core/dashboard/SolidDashboardVariable.js +171 -0
  88. package/dist/components/core/dashboard/SolidDashboardVariable.js.map +1 -0
  89. package/dist/components/core/dashboard/SolidDashboardVariable.tsx +259 -0
  90. package/dist/components/core/dashboard/SolidQuestionRenderer.d.ts +9 -0
  91. package/dist/components/core/dashboard/SolidQuestionRenderer.d.ts.map +1 -0
  92. package/dist/components/core/dashboard/SolidQuestionRenderer.js +42 -0
  93. package/dist/components/core/dashboard/SolidQuestionRenderer.js.map +1 -0
  94. package/dist/components/core/dashboard/SolidQuestionRenderer.tsx +99 -0
  95. package/dist/components/core/dashboard/chart-renderers/ChartJsRenderer.d.ts +9 -0
  96. package/dist/components/core/dashboard/chart-renderers/ChartJsRenderer.d.ts.map +1 -0
  97. package/dist/components/core/dashboard/chart-renderers/ChartJsRenderer.js +35 -0
  98. package/dist/components/core/dashboard/chart-renderers/ChartJsRenderer.js.map +1 -0
  99. package/dist/components/core/dashboard/chart-renderers/ChartJsRenderer.tsx +48 -0
  100. package/dist/components/core/dashboard/chart-renderers/PrimeReactDatatableRenderer.d.ts +7 -0
  101. package/dist/components/core/dashboard/chart-renderers/PrimeReactDatatableRenderer.d.ts.map +1 -0
  102. package/dist/components/core/dashboard/chart-renderers/PrimeReactDatatableRenderer.js +22 -0
  103. package/dist/components/core/dashboard/chart-renderers/PrimeReactDatatableRenderer.js.map +1 -0
  104. package/dist/components/core/dashboard/chart-renderers/PrimeReactDatatableRenderer.tsx +51 -0
  105. package/dist/components/core/dashboard/chart-renderers/init-chartjs.d.ts +2 -0
  106. package/dist/components/core/dashboard/chart-renderers/init-chartjs.d.ts.map +1 -0
  107. package/dist/components/core/dashboard/chart-renderers/init-chartjs.js +4 -0
  108. package/dist/components/core/dashboard/chart-renderers/init-chartjs.js.map +1 -0
  109. package/dist/components/core/dashboard/chart-renderers/init-chartjs.ts +25 -0
  110. package/dist/components/core/dashboard/dashboard-utils.d.ts +2 -0
  111. package/dist/components/core/dashboard/dashboard-utils.d.ts.map +1 -0
  112. package/dist/components/core/dashboard/dashboard-utils.js +38 -0
  113. package/dist/components/core/dashboard/dashboard-utils.js.map +1 -0
  114. package/dist/components/core/dashboard/dashboard-utils.ts +39 -0
  115. package/dist/components/core/extension/solid-core/dashboard/dashboardFormViewChangeHandler.d.ts +10 -0
  116. package/dist/components/core/extension/solid-core/dashboard/dashboardFormViewChangeHandler.d.ts.map +1 -0
  117. package/dist/components/core/extension/solid-core/dashboard/dashboardFormViewChangeHandler.js +16 -0
  118. package/dist/components/core/extension/solid-core/dashboard/dashboardFormViewChangeHandler.js.map +1 -0
  119. package/dist/components/core/extension/solid-core/dashboard/dashboardFormViewChangeHandler.ts +19 -0
  120. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionFieldChangeHandler.d.ts +8 -0
  121. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionFieldChangeHandler.d.ts.map +1 -0
  122. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionFieldChangeHandler.js +64 -0
  123. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionFieldChangeHandler.js.map +1 -0
  124. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionFieldChangeHandler.ts +30 -0
  125. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionOnFormLoadHandler.d.ts +8 -0
  126. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionOnFormLoadHandler.d.ts.map +1 -0
  127. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionOnFormLoadHandler.js +62 -0
  128. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionOnFormLoadHandler.js.map +1 -0
  129. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionOnFormLoadHandler.ts +29 -0
  130. package/dist/components/core/extension/solid-core/dashboardQuestion/ChartFormPreviewWidget.d.ts +4 -0
  131. package/dist/components/core/extension/solid-core/dashboardQuestion/ChartFormPreviewWidget.d.ts.map +1 -0
  132. package/dist/components/core/extension/solid-core/dashboardQuestion/ChartFormPreviewWidget.js +23 -0
  133. package/dist/components/core/extension/solid-core/dashboardQuestion/ChartFormPreviewWidget.js.map +1 -0
  134. package/dist/components/core/extension/solid-core/dashboardQuestion/ChartFormPreviewWidget.tsx +36 -0
  135. package/dist/components/core/form/SolidFormView.d.ts.map +1 -1
  136. package/dist/components/core/form/SolidFormView.js +2 -10
  137. package/dist/components/core/form/SolidFormView.js.map +1 -1
  138. package/dist/components/core/form/SolidFormView.tsx +2 -10
  139. package/dist/components/core/form/fields/SolidMediaMultipleField.d.ts.map +1 -1
  140. package/dist/components/core/form/fields/SolidMediaMultipleField.js +111 -106
  141. package/dist/components/core/form/fields/SolidMediaMultipleField.js.map +1 -1
  142. package/dist/components/core/form/fields/SolidMediaMultipleField.tsx +165 -134
  143. package/dist/components/core/form/fields/SolidMediaSingleField.d.ts.map +1 -1
  144. package/dist/components/core/form/fields/SolidMediaSingleField.js +81 -84
  145. package/dist/components/core/form/fields/SolidMediaSingleField.js.map +1 -1
  146. package/dist/components/core/form/fields/SolidMediaSingleField.tsx +97 -86
  147. package/dist/components/core/form/fields/widgets/SolidChatterMessageCoModelEntityIdFormViewWidget.d.ts +3 -0
  148. package/dist/components/core/form/fields/widgets/SolidChatterMessageCoModelEntityIdFormViewWidget.d.ts.map +1 -0
  149. package/dist/components/core/form/fields/widgets/SolidChatterMessageCoModelEntityIdFormViewWidget.js +92 -0
  150. package/dist/components/core/form/fields/widgets/SolidChatterMessageCoModelEntityIdFormViewWidget.js.map +1 -0
  151. package/dist/components/core/form/fields/widgets/SolidChatterMessageCoModelEntityIdFormViewWidget.tsx +68 -0
  152. package/dist/components/core/form/fields/widgets/SolidLovTypeChangeFormEditWidget.d.ts +3 -0
  153. package/dist/components/core/form/fields/widgets/SolidLovTypeChangeFormEditWidget.d.ts.map +1 -0
  154. package/dist/components/core/form/fields/widgets/SolidLovTypeChangeFormEditWidget.js +111 -0
  155. package/dist/components/core/form/fields/widgets/SolidLovTypeChangeFormEditWidget.js.map +1 -0
  156. package/dist/components/core/form/fields/widgets/SolidLovTypeChangeFormEditWidget.tsx +122 -0
  157. package/dist/components/core/kanban/SolidKanbanView.d.ts.map +1 -1
  158. package/dist/components/core/kanban/SolidKanbanView.js +6 -11
  159. package/dist/components/core/kanban/SolidKanbanView.js.map +1 -1
  160. package/dist/components/core/kanban/SolidKanbanView.tsx +6 -11
  161. package/dist/components/core/kanban/SolidKanbanViewConfigure.d.ts.map +1 -1
  162. package/dist/components/core/kanban/SolidKanbanViewConfigure.js +3 -7
  163. package/dist/components/core/kanban/SolidKanbanViewConfigure.js.map +1 -1
  164. package/dist/components/core/kanban/SolidKanbanViewConfigure.tsx +3 -9
  165. package/dist/components/core/kanban/SolidKanbanViewFields.d.ts +12 -0
  166. package/dist/components/core/kanban/SolidKanbanViewFields.d.ts.map +1 -0
  167. package/dist/components/core/kanban/SolidKanbanViewFields.js +145 -0
  168. package/dist/components/core/kanban/SolidKanbanViewFields.js.map +1 -0
  169. package/dist/components/core/kanban/SolidKanbanViewFields.tsx +164 -0
  170. package/dist/components/core/kanban/SolidManyToOneFilterElement.d.ts +2 -0
  171. package/dist/components/core/kanban/SolidManyToOneFilterElement.d.ts.map +1 -0
  172. package/dist/components/core/kanban/SolidManyToOneFilterElement.js +87 -0
  173. package/dist/components/core/kanban/SolidManyToOneFilterElement.js.map +1 -0
  174. package/dist/components/core/kanban/SolidManyToOneFilterElement.tsx +59 -0
  175. package/dist/components/core/kanban/SolidSelectionDynamicFilterElement.d.ts +2 -0
  176. package/dist/components/core/kanban/SolidSelectionDynamicFilterElement.d.ts.map +1 -0
  177. package/dist/components/core/kanban/SolidSelectionDynamicFilterElement.js +73 -0
  178. package/dist/components/core/kanban/SolidSelectionDynamicFilterElement.js.map +1 -0
  179. package/dist/components/core/kanban/SolidSelectionDynamicFilterElement.tsx +50 -0
  180. package/dist/components/core/kanban/SolidSelectionStaticFilterElement.d.ts +2 -0
  181. package/dist/components/core/kanban/SolidSelectionStaticFilterElement.d.ts.map +1 -0
  182. package/dist/components/core/kanban/SolidSelectionStaticFilterElement.js +20 -0
  183. package/dist/components/core/kanban/SolidSelectionStaticFilterElement.js.map +1 -0
  184. package/dist/components/core/kanban/SolidSelectionStaticFilterElement.tsx +32 -0
  185. package/dist/components/core/kanban/SolidVarInputsFilterElement.d.ts +12 -0
  186. package/dist/components/core/kanban/SolidVarInputsFilterElement.d.ts.map +1 -0
  187. package/dist/components/core/kanban/SolidVarInputsFilterElement.js +81 -0
  188. package/dist/components/core/kanban/SolidVarInputsFilterElement.js.map +1 -0
  189. package/dist/components/core/kanban/SolidVarInputsFilterElement.tsx +184 -0
  190. package/dist/components/core/kanban/kanban-fields/SolidBigintKanbanField.d.ts +4 -0
  191. package/dist/components/core/kanban/kanban-fields/SolidBigintKanbanField.d.ts.map +1 -0
  192. package/dist/components/core/kanban/kanban-fields/SolidBigintKanbanField.js +7 -0
  193. package/dist/components/core/kanban/kanban-fields/SolidBigintKanbanField.js.map +1 -0
  194. package/dist/components/core/kanban/kanban-fields/SolidBigintKanbanField.tsx +9 -0
  195. package/dist/components/core/kanban/kanban-fields/SolidBooleanKanbanField.d.ts +4 -0
  196. package/dist/components/core/kanban/kanban-fields/SolidBooleanKanbanField.d.ts.map +1 -0
  197. package/dist/components/core/kanban/kanban-fields/SolidBooleanKanbanField.js +8 -0
  198. package/dist/components/core/kanban/kanban-fields/SolidBooleanKanbanField.js.map +1 -0
  199. package/dist/components/core/kanban/kanban-fields/SolidBooleanKanbanField.tsx +16 -0
  200. package/dist/components/core/kanban/kanban-fields/SolidComputedKanbanField.d.ts +4 -0
  201. package/dist/components/core/kanban/kanban-fields/SolidComputedKanbanField.d.ts.map +1 -0
  202. package/dist/components/core/kanban/kanban-fields/SolidComputedKanbanField.js +21 -0
  203. package/dist/components/core/kanban/kanban-fields/SolidComputedKanbanField.js.map +1 -0
  204. package/dist/components/core/kanban/kanban-fields/SolidComputedKanbanField.tsx +23 -0
  205. package/dist/components/core/kanban/kanban-fields/SolidDateKanbanField.d.ts +4 -0
  206. package/dist/components/core/kanban/kanban-fields/SolidDateKanbanField.d.ts.map +1 -0
  207. package/dist/components/core/kanban/kanban-fields/SolidDateKanbanField.js +8 -0
  208. package/dist/components/core/kanban/kanban-fields/SolidDateKanbanField.js.map +1 -0
  209. package/dist/components/core/kanban/kanban-fields/SolidDateKanbanField.tsx +14 -0
  210. package/dist/components/core/kanban/kanban-fields/SolidDatetimeKanbanField.d.ts +4 -0
  211. package/dist/components/core/kanban/kanban-fields/SolidDatetimeKanbanField.d.ts.map +1 -0
  212. package/dist/components/core/kanban/kanban-fields/SolidDatetimeKanbanField.js +8 -0
  213. package/dist/components/core/kanban/kanban-fields/SolidDatetimeKanbanField.js.map +1 -0
  214. package/dist/components/core/kanban/kanban-fields/SolidDatetimeKanbanField.tsx +13 -0
  215. package/dist/components/core/kanban/kanban-fields/SolidDecimalKanbanField.d.ts +4 -0
  216. package/dist/components/core/kanban/kanban-fields/SolidDecimalKanbanField.d.ts.map +1 -0
  217. package/dist/components/core/kanban/kanban-fields/SolidDecimalKanbanField.js +7 -0
  218. package/dist/components/core/kanban/kanban-fields/SolidDecimalKanbanField.js.map +1 -0
  219. package/dist/components/core/kanban/kanban-fields/SolidDecimalKanbanField.tsx +9 -0
  220. package/dist/components/core/kanban/kanban-fields/SolidExternalIdKanbanField.d.ts +4 -0
  221. package/dist/components/core/kanban/kanban-fields/SolidExternalIdKanbanField.d.ts.map +1 -0
  222. package/dist/components/core/kanban/kanban-fields/SolidExternalIdKanbanField.js +8 -0
  223. package/dist/components/core/kanban/kanban-fields/SolidExternalIdKanbanField.js.map +1 -0
  224. package/dist/components/core/kanban/kanban-fields/SolidExternalIdKanbanField.tsx +12 -0
  225. package/dist/components/core/kanban/kanban-fields/SolidFloatKanbanField.d.ts +4 -0
  226. package/dist/components/core/kanban/kanban-fields/SolidFloatKanbanField.d.ts.map +1 -0
  227. package/dist/components/core/kanban/kanban-fields/SolidFloatKanbanField.js +7 -0
  228. package/dist/components/core/kanban/kanban-fields/SolidFloatKanbanField.js.map +1 -0
  229. package/dist/components/core/kanban/kanban-fields/SolidFloatKanbanField.tsx +9 -0
  230. package/dist/components/core/kanban/kanban-fields/SolidIdKanbanField.d.ts +4 -0
  231. package/dist/components/core/kanban/kanban-fields/SolidIdKanbanField.d.ts.map +1 -0
  232. package/dist/components/core/kanban/kanban-fields/SolidIdKanbanField.js +8 -0
  233. package/dist/components/core/kanban/kanban-fields/SolidIdKanbanField.js.map +1 -0
  234. package/dist/components/core/kanban/kanban-fields/SolidIdKanbanField.tsx +14 -0
  235. package/dist/components/core/kanban/kanban-fields/SolidIntKanbanField.d.ts +4 -0
  236. package/dist/components/core/kanban/kanban-fields/SolidIntKanbanField.d.ts.map +1 -0
  237. package/dist/components/core/kanban/kanban-fields/SolidIntKanbanField.js +16 -0
  238. package/dist/components/core/kanban/kanban-fields/SolidIntKanbanField.js.map +1 -0
  239. package/dist/components/core/kanban/kanban-fields/SolidIntKanbanField.tsx +20 -0
  240. package/dist/components/core/kanban/kanban-fields/SolidLongTextKanbanField.d.ts +4 -0
  241. package/dist/components/core/kanban/kanban-fields/SolidLongTextKanbanField.d.ts.map +1 -0
  242. package/dist/components/core/kanban/kanban-fields/SolidLongTextKanbanField.js +7 -0
  243. package/dist/components/core/kanban/kanban-fields/SolidLongTextKanbanField.js.map +1 -0
  244. package/dist/components/core/kanban/kanban-fields/SolidLongTextKanbanField.tsx +9 -0
  245. package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.d.ts +4 -0
  246. package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.d.ts.map +1 -0
  247. package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.js +56 -0
  248. package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.js.map +1 -0
  249. package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.tsx +140 -0
  250. package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.d.ts +4 -0
  251. package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.d.ts.map +1 -0
  252. package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.js +42 -0
  253. package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.js.map +1 -0
  254. package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.tsx +164 -0
  255. package/dist/components/core/kanban/kanban-fields/SolidRelationKanbanField.d.ts +4 -0
  256. package/dist/components/core/kanban/kanban-fields/SolidRelationKanbanField.d.ts.map +1 -0
  257. package/dist/components/core/kanban/kanban-fields/SolidRelationKanbanField.js +11 -0
  258. package/dist/components/core/kanban/kanban-fields/SolidRelationKanbanField.js.map +1 -0
  259. package/dist/components/core/kanban/kanban-fields/SolidRelationKanbanField.tsx +13 -0
  260. package/dist/components/core/kanban/kanban-fields/SolidRichTextKanbanField.d.ts +4 -0
  261. package/dist/components/core/kanban/kanban-fields/SolidRichTextKanbanField.d.ts.map +1 -0
  262. package/dist/components/core/kanban/kanban-fields/SolidRichTextKanbanField.js +7 -0
  263. package/dist/components/core/kanban/kanban-fields/SolidRichTextKanbanField.js.map +1 -0
  264. package/dist/components/core/kanban/kanban-fields/SolidRichTextKanbanField.tsx +9 -0
  265. package/dist/components/core/kanban/kanban-fields/SolidSelectionDynamicKanbanField.d.ts +4 -0
  266. package/dist/components/core/kanban/kanban-fields/SolidSelectionDynamicKanbanField.d.ts.map +1 -0
  267. package/dist/components/core/kanban/kanban-fields/SolidSelectionDynamicKanbanField.js +8 -0
  268. package/dist/components/core/kanban/kanban-fields/SolidSelectionDynamicKanbanField.js.map +1 -0
  269. package/dist/components/core/kanban/kanban-fields/SolidSelectionDynamicKanbanField.tsx +14 -0
  270. package/dist/components/core/kanban/kanban-fields/SolidSelectionStaticKanbanField.d.ts +4 -0
  271. package/dist/components/core/kanban/kanban-fields/SolidSelectionStaticKanbanField.d.ts.map +1 -0
  272. package/dist/components/core/kanban/kanban-fields/SolidSelectionStaticKanbanField.js +8 -0
  273. package/dist/components/core/kanban/kanban-fields/SolidSelectionStaticKanbanField.js.map +1 -0
  274. package/dist/components/core/kanban/kanban-fields/SolidSelectionStaticKanbanField.tsx +14 -0
  275. package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.d.ts +4 -0
  276. package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.d.ts.map +1 -0
  277. package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.js +37 -0
  278. package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.js.map +1 -0
  279. package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.tsx +121 -0
  280. package/dist/components/core/kanban/kanban-fields/SolidTimeKanbanField.d.ts +4 -0
  281. package/dist/components/core/kanban/kanban-fields/SolidTimeKanbanField.d.ts.map +1 -0
  282. package/dist/components/core/kanban/kanban-fields/SolidTimeKanbanField.js +8 -0
  283. package/dist/components/core/kanban/kanban-fields/SolidTimeKanbanField.js.map +1 -0
  284. package/dist/components/core/kanban/kanban-fields/SolidTimeKanbanField.tsx +12 -0
  285. package/dist/components/core/kanban/kanban-fields/SolidUuidKanbanField.d.ts +4 -0
  286. package/dist/components/core/kanban/kanban-fields/SolidUuidKanbanField.d.ts.map +1 -0
  287. package/dist/components/core/kanban/kanban-fields/SolidUuidKanbanField.js +8 -0
  288. package/dist/components/core/kanban/kanban-fields/SolidUuidKanbanField.js.map +1 -0
  289. package/dist/components/core/kanban/kanban-fields/SolidUuidKanbanField.tsx +13 -0
  290. package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.d.ts +4 -0
  291. package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.d.ts.map +1 -0
  292. package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.js +7 -0
  293. package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.js.map +1 -0
  294. package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.tsx +16 -0
  295. package/dist/components/core/list/SolidEmptyListViewPlaceholder.d.ts.map +1 -1
  296. package/dist/components/core/list/SolidEmptyListViewPlaceholder.js +2 -3
  297. package/dist/components/core/list/SolidEmptyListViewPlaceholder.js.map +1 -1
  298. package/dist/components/core/list/SolidEmptyListViewPlaceholder.tsx +2 -3
  299. package/dist/components/core/list/SolidListView.d.ts.map +1 -1
  300. package/dist/components/core/list/SolidListView.js +2 -14
  301. package/dist/components/core/list/SolidListView.js.map +1 -1
  302. package/dist/components/core/list/SolidListView.tsx +2 -14
  303. package/dist/components/core/list/SolidListViewConfigure.d.ts.map +1 -1
  304. package/dist/components/core/list/SolidListViewConfigure.js +7 -5
  305. package/dist/components/core/list/SolidListViewConfigure.js.map +1 -1
  306. package/dist/components/core/list/SolidListViewConfigure.tsx +7 -5
  307. package/dist/components/core/list/SolidListViewRowButtonContextMenu.d.ts +2 -0
  308. package/dist/components/core/list/SolidListViewRowButtonContextMenu.d.ts.map +1 -0
  309. package/dist/components/core/list/SolidListViewRowButtonContextMenu.js +39 -0
  310. package/dist/components/core/list/SolidListViewRowButtonContextMenu.js.map +1 -0
  311. package/dist/components/core/list/SolidListViewRowButtonContextMenu.tsx +40 -0
  312. package/dist/components/core/list/SolidVarInputsFilterElement.d.ts +12 -0
  313. package/dist/components/core/list/SolidVarInputsFilterElement.d.ts.map +1 -0
  314. package/dist/components/core/list/SolidVarInputsFilterElement.js +81 -0
  315. package/dist/components/core/list/SolidVarInputsFilterElement.js.map +1 -0
  316. package/dist/components/core/list/SolidVarInputsFilterElement.tsx +184 -0
  317. package/dist/components/core/list/columns/SolidMediaMultipleColumn.d.ts.map +1 -1
  318. package/dist/components/core/list/columns/SolidMediaMultipleColumn.js +42 -81
  319. package/dist/components/core/list/columns/SolidMediaMultipleColumn.js.map +1 -1
  320. package/dist/components/core/list/columns/SolidMediaMultipleColumn.tsx +90 -120
  321. package/dist/components/core/list/columns/SolidMediaSingleColumn.d.ts.map +1 -1
  322. package/dist/components/core/list/columns/SolidMediaSingleColumn.js +34 -42
  323. package/dist/components/core/list/columns/SolidMediaSingleColumn.js.map +1 -1
  324. package/dist/components/core/list/columns/SolidMediaSingleColumn.tsx +51 -46
  325. package/dist/components/core/list/widgets/SolidChatterMessageCoModelEntityIdListViewWidget.d.ts +3 -0
  326. package/dist/components/core/list/widgets/SolidChatterMessageCoModelEntityIdListViewWidget.d.ts.map +1 -0
  327. package/dist/components/core/list/widgets/SolidChatterMessageCoModelEntityIdListViewWidget.js +87 -0
  328. package/dist/components/core/list/widgets/SolidChatterMessageCoModelEntityIdListViewWidget.js.map +1 -0
  329. package/dist/components/core/list/widgets/SolidChatterMessageCoModelEntityIdListViewWidget.tsx +70 -0
  330. package/dist/components/core/list/widgets/SolidMqMessageStageListViewWidget.d.ts +3 -0
  331. package/dist/components/core/list/widgets/SolidMqMessageStageListViewWidget.d.ts.map +1 -0
  332. package/dist/components/core/list/widgets/SolidMqMessageStageListViewWidget.js +33 -0
  333. package/dist/components/core/list/widgets/SolidMqMessageStageListViewWidget.js.map +1 -0
  334. package/dist/components/core/list/widgets/SolidMqMessageStageListViewWidget.tsx +50 -0
  335. package/dist/components/core/list/widgets/SolidSummarizeListHeaderActionMqMessages.d.ts +3 -0
  336. package/dist/components/core/list/widgets/SolidSummarizeListHeaderActionMqMessages.d.ts.map +1 -0
  337. package/dist/components/core/list/widgets/SolidSummarizeListHeaderActionMqMessages.js +158 -0
  338. package/dist/components/core/list/widgets/SolidSummarizeListHeaderActionMqMessages.js.map +1 -0
  339. package/dist/components/core/list/widgets/SolidSummarizeListHeaderActionMqMessages.tsx +185 -0
  340. package/dist/components/core/tree/SolidTreeView.d.ts.map +1 -1
  341. package/dist/components/core/tree/SolidTreeView.js +2 -14
  342. package/dist/components/core/tree/SolidTreeView.js.map +1 -1
  343. package/dist/components/core/tree/SolidTreeView.tsx +2 -14
  344. package/dist/components/layout/DashboardHeader.d.ts +3 -0
  345. package/dist/components/layout/DashboardHeader.d.ts.map +1 -0
  346. package/dist/components/layout/DashboardHeader.js +20 -0
  347. package/dist/components/layout/DashboardHeader.js.map +1 -0
  348. package/dist/components/layout/DashboardHeader.tsx +94 -0
  349. package/dist/helpers/# no such endpoints exist, need to calle +3 -0
  350. package/dist/helpers/ToastContainer.d.ts +4 -0
  351. package/dist/helpers/ToastContainer.d.ts.map +1 -0
  352. package/dist/helpers/ToastContainer.js +49 -0
  353. package/dist/helpers/ToastContainer.js.map +1 -0
  354. package/dist/helpers/ToastContainer.tsx +94 -0
  355. package/dist/helpers/downloadMediaFile.d.ts.map +1 -1
  356. package/dist/helpers/downloadMediaFile.js +10 -3
  357. package/dist/helpers/downloadMediaFile.js.map +1 -1
  358. package/dist/helpers/downloadMediaFile.tsx +13 -7
  359. package/dist/helpers/fileTypeIcon.d.ts +3 -2
  360. package/dist/helpers/fileTypeIcon.d.ts.map +1 -1
  361. package/dist/helpers/fileTypeIcon.js +11 -7
  362. package/dist/helpers/fileTypeIcon.js.map +1 -1
  363. package/dist/helpers/fileTypeIcon.tsx +12 -7
  364. package/dist/helpers/mediaType.d.ts +7 -0
  365. package/dist/helpers/mediaType.d.ts.map +1 -1
  366. package/dist/helpers/mediaType.js +39 -8
  367. package/dist/helpers/mediaType.js.map +1 -1
  368. package/dist/helpers/mediaType.ts +46 -7
  369. package/dist/helpers/mediaUrl.d.ts +2 -0
  370. package/dist/helpers/mediaUrl.d.ts.map +1 -0
  371. package/dist/helpers/mediaUrl.js +10 -0
  372. package/dist/helpers/mediaUrl.js.map +1 -0
  373. package/dist/helpers/mediaUrl.ts +11 -0
  374. package/dist/helpers/permissions.d.ts +13 -0
  375. package/dist/helpers/permissions.d.ts.map +1 -1
  376. package/dist/helpers/permissions.js +79 -0
  377. package/dist/helpers/permissions.js.map +1 -1
  378. package/dist/helpers/permissions.ts +92 -1
  379. package/dist/helpers/showToast.d.ts +5 -0
  380. package/dist/helpers/showToast.d.ts.map +1 -0
  381. package/dist/helpers/showToast.js +17 -0
  382. package/dist/helpers/showToast.js.map +1 -0
  383. package/dist/helpers/showToast.ts +13 -0
  384. package/dist/helpers/studioSandbox.d.ts +31 -0
  385. package/dist/helpers/studioSandbox.d.ts.map +1 -0
  386. package/dist/helpers/studioSandbox.js +104 -0
  387. package/dist/helpers/studioSandbox.js.map +1 -0
  388. package/dist/helpers/studioSandbox.ts +117 -0
  389. package/dist/nextAuth/authProviders.d.ts +4 -0
  390. package/dist/nextAuth/authProviders.d.ts.map +1 -0
  391. package/dist/nextAuth/authProviders.js +198 -0
  392. package/dist/nextAuth/authProviders.js.map +1 -0
  393. package/dist/nextAuth/authProviders.tsx +232 -0
  394. package/dist/nextAuth/handleLogout.d.ts +2 -0
  395. package/dist/nextAuth/handleLogout.d.ts.map +1 -0
  396. package/dist/nextAuth/handleLogout.js +36 -0
  397. package/dist/nextAuth/handleLogout.js.map +1 -0
  398. package/dist/nextAuth/handleLogout.tsx +39 -0
  399. package/dist/nextAuth/refreshAccessToken.d.ts +2 -0
  400. package/dist/nextAuth/refreshAccessToken.d.ts.map +1 -0
  401. package/dist/nextAuth/refreshAccessToken.js +24 -0
  402. package/dist/nextAuth/refreshAccessToken.js.map +1 -0
  403. package/dist/nextAuth/refreshAccessToken.tsx +28 -0
  404. package/dist/redux/api/dashboardApi.d.ts +23 -0
  405. package/dist/redux/api/dashboardApi.d.ts.map +1 -0
  406. package/dist/redux/api/dashboardApi.js +35 -0
  407. package/dist/redux/api/dashboardApi.js.map +1 -0
  408. package/dist/redux/api/dashboardApi.ts +56 -0
  409. package/dist/redux/api/dashboardLayoutApi.d.ts +24 -0
  410. package/dist/redux/api/dashboardLayoutApi.d.ts.map +1 -0
  411. package/dist/redux/api/dashboardLayoutApi.js +34 -0
  412. package/dist/redux/api/dashboardLayoutApi.js.map +1 -0
  413. package/dist/redux/api/dashboardLayoutApi.ts +55 -0
  414. package/dist/redux/api/dashboardQuestionApi.d.ts +5 -0
  415. package/dist/redux/api/dashboardQuestionApi.d.ts.map +1 -0
  416. package/dist/redux/api/dashboardQuestionApi.js +18 -0
  417. package/dist/redux/api/dashboardQuestionApi.js.map +1 -0
  418. package/dist/redux/api/dashboardQuestionApi.ts +17 -0
  419. package/dist/redux/features/settingsSlice.d.ts +20 -0
  420. package/dist/redux/features/settingsSlice.d.ts.map +1 -0
  421. package/dist/redux/features/settingsSlice.js +39 -0
  422. package/dist/redux/features/settingsSlice.js.map +1 -0
  423. package/dist/redux/features/settingsSlice.ts +60 -0
  424. package/dist/resources/images/Footerbg.png +0 -0
  425. package/dist/resources/images/LoginBanner.png +0 -0
  426. package/dist/resources/images/dashboard/Ellipse 1.svg +10 -0
  427. package/dist/resources/images/dashboard/Rectangle 17.svg +10 -0
  428. package/dist/resources/images/dashboard/Rectangle 25.svg +11 -0
  429. package/dist/resources/images/dashboard/image 5.svg +9 -0
  430. package/dist/resources/images/loginhero.png +0 -0
  431. package/dist/resources/images/logo.png +0 -0
  432. package/dist/resources/images/radix-logo-white.png +0 -0
  433. package/dist/resources/images/radix-logo.png +0 -0
  434. package/dist/resources/images/signupBanner.png +0 -0
  435. package/dist/resources/shadcn-base.css +16 -70
  436. package/dist/resources/solid-tailwind-generated.css +1 -1
  437. package/package.json +1 -1
  438. package/dist/components/core/extension/solid-core/workflowDefinition/list/openWorkflowDefinitionEditorHeaderAction.d.ts +0 -8
  439. package/dist/components/core/extension/solid-core/workflowDefinition/list/openWorkflowDefinitionEditorHeaderAction.d.ts.map +0 -1
  440. package/dist/components/core/extension/solid-core/workflowDefinition/list/openWorkflowDefinitionEditorHeaderAction.js +0 -6
  441. package/dist/components/core/extension/solid-core/workflowDefinition/list/openWorkflowDefinitionEditorHeaderAction.js.map +0 -1
  442. package/dist/components/core/extension/solid-core/workflowDefinition/list/openWorkflowDefinitionEditorHeaderAction.ts +0 -13
  443. package/dist/components/core/extension/solid-core/workflowDefinition/list/openWorkflowDefinitionEditorRowAction.d.ts +0 -11
  444. package/dist/components/core/extension/solid-core/workflowDefinition/list/openWorkflowDefinitionEditorRowAction.d.ts.map +0 -1
  445. package/dist/components/core/extension/solid-core/workflowDefinition/list/openWorkflowDefinitionEditorRowAction.js +0 -10
  446. package/dist/components/core/extension/solid-core/workflowDefinition/list/openWorkflowDefinitionEditorRowAction.js.map +0 -1
  447. package/dist/components/core/extension/solid-core/workflowDefinition/list/openWorkflowDefinitionEditorRowAction.ts +0 -22
  448. package/dist/components/core/list/SolidCustomListColumn.d.ts +0 -8
  449. package/dist/components/core/list/SolidCustomListColumn.d.ts.map +0 -1
  450. package/dist/components/core/list/SolidCustomListColumn.js +0 -47
  451. package/dist/components/core/list/SolidCustomListColumn.js.map +0 -1
  452. package/dist/components/core/list/SolidCustomListColumn.tsx +0 -57
  453. package/dist/components/workflow/WorkflowFlowCanvas.css +0 -431
  454. package/dist/components/workflow/WorkflowFlowCanvas.d.ts +0 -41
  455. package/dist/components/workflow/WorkflowFlowCanvas.d.ts.map +0 -1
  456. package/dist/components/workflow/WorkflowFlowCanvas.js +0 -705
  457. package/dist/components/workflow/WorkflowFlowCanvas.js.map +0 -1
  458. package/dist/components/workflow/WorkflowFlowCanvas.tsx +0 -1274
  459. package/dist/components/workflow/WorkflowNodeDocsPanel.css +0 -247
  460. package/dist/components/workflow/WorkflowNodeDocsPanel.d.ts +0 -22
  461. package/dist/components/workflow/WorkflowNodeDocsPanel.d.ts.map +0 -1
  462. package/dist/components/workflow/WorkflowNodeDocsPanel.js +0 -97
  463. package/dist/components/workflow/WorkflowNodeDocsPanel.js.map +0 -1
  464. package/dist/components/workflow/WorkflowNodeDocsPanel.tsx +0 -363
  465. package/dist/components/workflow/WorkflowNodeSchemaEditor.d.ts +0 -50
  466. package/dist/components/workflow/WorkflowNodeSchemaEditor.d.ts.map +0 -1
  467. package/dist/components/workflow/WorkflowNodeSchemaEditor.js +0 -309
  468. package/dist/components/workflow/WorkflowNodeSchemaEditor.js.map +0 -1
  469. package/dist/components/workflow/WorkflowNodeSchemaEditor.tsx +0 -808
  470. package/dist/helpers/modulePackageResumeState.d.ts +0 -6
  471. package/dist/helpers/modulePackageResumeState.d.ts.map +0 -1
  472. package/dist/helpers/modulePackageResumeState.js +0 -46
  473. package/dist/helpers/modulePackageResumeState.js.map +0 -1
  474. package/dist/helpers/modulePackageResumeState.ts +0 -57
  475. package/dist/redux/api/workflowDefinitionEditorApi.d.ts +0 -17
  476. package/dist/redux/api/workflowDefinitionEditorApi.d.ts.map +0 -1
  477. package/dist/redux/api/workflowDefinitionEditorApi.js +0 -38
  478. package/dist/redux/api/workflowDefinitionEditorApi.js.map +0 -1
  479. package/dist/redux/api/workflowDefinitionEditorApi.ts +0 -40
  480. package/dist/redux/api/workflowNodeApi.d.ts +0 -6
  481. package/dist/redux/api/workflowNodeApi.d.ts.map +0 -1
  482. package/dist/redux/api/workflowNodeApi.js +0 -14
  483. package/dist/redux/api/workflowNodeApi.js.map +0 -1
  484. package/dist/redux/api/workflowNodeApi.ts +0 -18
  485. package/dist/routes/pages/admin/core/WorkflowDefinitionEditorPage.css +0 -970
  486. package/dist/routes/pages/admin/core/WorkflowDefinitionEditorPage.d.ts +0 -3
  487. package/dist/routes/pages/admin/core/WorkflowDefinitionEditorPage.d.ts.map +0 -1
  488. package/dist/routes/pages/admin/core/WorkflowDefinitionEditorPage.js +0 -1287
  489. package/dist/routes/pages/admin/core/WorkflowDefinitionEditorPage.js.map +0 -1
  490. package/dist/routes/pages/admin/core/WorkflowDefinitionEditorPage.tsx +0 -2572
  491. package/dist/routes/pages/admin/core/WorkflowDefinitionListPage.css +0 -151
  492. package/dist/routes/pages/admin/core/WorkflowDefinitionListPage.d.ts +0 -3
  493. package/dist/routes/pages/admin/core/WorkflowDefinitionListPage.d.ts.map +0 -1
  494. package/dist/routes/pages/admin/core/WorkflowDefinitionListPage.js +0 -250
  495. package/dist/routes/pages/admin/core/WorkflowDefinitionListPage.js.map +0 -1
  496. package/dist/routes/pages/admin/core/WorkflowDefinitionListPage.tsx +0 -455
  497. package/dist/types/workflow-node.d.ts +0 -127
  498. package/dist/types/workflow-node.d.ts.map +0 -1
  499. package/dist/types/workflow-node.js +0 -2
  500. package/dist/types/workflow-node.js.map +0 -1
  501. package/dist/types/workflow-node.ts +0 -162
@@ -1,2572 +0,0 @@
1
- import {
2
- Activity,
3
- ArrowLeft,
4
- BookOpen,
5
- Braces,
6
- ChevronLeft,
7
- ChevronRight,
8
- GitBranchPlus,
9
- Layers3,
10
- Play,
11
- RefreshCw,
12
- Save,
13
- Settings2,
14
- ShieldCheck,
15
- X,
16
- } from "lucide-react";
17
- import React from "react";
18
- import { useNavigate, useParams } from "react-router-dom";
19
- import { useDispatch } from "react-redux";
20
- import qs from "qs";
21
- import YAML from "yaml";
22
- import { createSolidEntityApi } from "../../../../redux/api/solidEntityApi";
23
- import { useGetWorkflowNodeTypesQuery } from "../../../../redux/api/workflowNodeApi";
24
- import {
25
- useExecuteWorkflowDefinitionMutation,
26
- useValidateWorkflowDefinitionMutation,
27
- } from "../../../../redux/api/workflowDefinitionEditorApi";
28
- import { showToast } from "../../../../redux/features/toastSlice";
29
- import {
30
- WorkflowNodeDocsPanel,
31
- type WorkflowDocsModel,
32
- } from "../../../../components/workflow/WorkflowNodeDocsPanel";
33
- import {
34
- WorkflowFlowCanvas,
35
- type WorkflowInsertTarget,
36
- } from "../../../../components/workflow/WorkflowFlowCanvas";
37
- import {
38
- WorkflowNodeEditorDialog,
39
- WorkflowNodePalette,
40
- } from "../../../../components/workflow/WorkflowNodeSchemaEditor";
41
- import type { WorkflowNodeMetadataResponse } from "../../../../types/workflow-node";
42
- import {
43
- SolidButton,
44
- SolidCodeEditor,
45
- SolidDatePicker,
46
- SolidDialog,
47
- SolidDialogBody,
48
- SolidDialogFooter,
49
- SolidInput,
50
- SolidPanel,
51
- SolidSpinner,
52
- SolidTabGroup,
53
- SolidTag,
54
- SolidTextarea,
55
- } from "../../../../components/shad-cn-ui";
56
- import "./WorkflowDefinitionEditorPage.css";
57
-
58
- type WorkflowDefinitionRecord = {
59
- id: number;
60
- key?: string;
61
- displayName?: string;
62
- description?: string;
63
- definitionYaml?: WorkflowDefinitionDsl | string | null;
64
- };
65
-
66
- type WorkflowNodeRecord = {
67
- [key: string]: any;
68
- id: string;
69
- name?: string;
70
- description?: string;
71
- kind: string;
72
- type: string;
73
- disabled?: boolean;
74
- timeoutMs?: number;
75
- retryPolicy?: Record<string, any>;
76
- onError?: "fail" | "continue";
77
- configuration?: Record<string, any>;
78
- metadata?: Record<string, any>;
79
- children?: WorkflowNodeRecord[];
80
- nodes?: WorkflowNodeRecord[];
81
- then?: WorkflowNodeRecord[];
82
- else?: WorkflowNodeRecord[];
83
- branches?: Array<{
84
- id: string;
85
- name?: string;
86
- nodes: WorkflowNodeRecord[];
87
- }>;
88
- };
89
-
90
- type WorkflowDefinitionDsl = {
91
- version?: string;
92
- description?: string;
93
- inputs?: Record<string, any>;
94
- variables?: Record<string, any>;
95
- nodes: WorkflowNodeRecord[];
96
- triggers?: Array<Record<string, any>>;
97
- metadata?: Record<string, any>;
98
- };
99
-
100
- type ValidationState = {
101
- status: "idle" | "validating" | "valid" | "invalid";
102
- source?: "client" | "server";
103
- message?: string;
104
- errors: string[];
105
- };
106
-
107
- type WorkflowDetailTab =
108
- | "overview"
109
- | "topology"
110
- | "executions"
111
- | "edit"
112
- | "revisions"
113
- | "triggers"
114
- | "logs"
115
- | "metrics";
116
-
117
- type WorkflowExecutionRecord = {
118
- id: number;
119
- status?: string | null;
120
- triggerType?: string | null;
121
- startedAt?: string | null;
122
- finishedAt?: string | null;
123
- durationMs?: number | string | null;
124
- createdAt?: string | null;
125
- };
126
-
127
- const createEmptyWorkflowDefinition = (): WorkflowDefinitionDsl => ({
128
- version: "1.0.0",
129
- description: "",
130
- inputs: {},
131
- variables: {},
132
- nodes: [],
133
- triggers: [],
134
- metadata: {},
135
- });
136
-
137
- const TOPOLOGY_SPLIT_STORAGE_KEY = "solid.workflow.editor.topologySplitPercent";
138
-
139
- function readStoredTopologySplitPercent() {
140
- if (typeof window === "undefined") {
141
- return 62;
142
- }
143
-
144
- const storedValue = Number(window.localStorage.getItem(TOPOLOGY_SPLIT_STORAGE_KEY));
145
- return Number.isFinite(storedValue) ? Math.min(78, Math.max(22, storedValue)) : 62;
146
- }
147
-
148
- function serializeWorkflowDefinitionYaml(definition: WorkflowDefinitionDsl) {
149
- return YAML.stringify(definition);
150
- }
151
-
152
- function parseYamlValue<T>(value: string, fallback: T): T {
153
- if (!value.trim()) {
154
- return fallback;
155
- }
156
-
157
- const parsed = YAML.parse(value);
158
- return (parsed ?? fallback) as T;
159
- }
160
-
161
- function normalizeWorkflowDefinition(
162
- definitionYaml: WorkflowDefinitionRecord["definitionYaml"],
163
- ): WorkflowDefinitionDsl {
164
- if (!definitionYaml) {
165
- return createEmptyWorkflowDefinition();
166
- }
167
-
168
- let parsed: any = definitionYaml;
169
- if (typeof definitionYaml === "string") {
170
- try {
171
- parsed = YAML.parse(definitionYaml);
172
- } catch {
173
- return createEmptyWorkflowDefinition();
174
- }
175
- }
176
-
177
- return {
178
- ...createEmptyWorkflowDefinition(),
179
- ...(parsed ?? {}),
180
- nodes: Array.isArray((parsed as any)?.nodes) ? (parsed as any).nodes : [],
181
- triggers: Array.isArray((parsed as any)?.triggers)
182
- ? (parsed as any).triggers
183
- : [],
184
- };
185
- }
186
-
187
- function flattenWorkflowNodeIds(nodes: WorkflowNodeRecord[]): string[] {
188
- return nodes.flatMap((node) => [
189
- String(node.id),
190
- ...flattenWorkflowNodeIds(node.children ?? []),
191
- ...flattenWorkflowNodeIds(node.nodes ?? []),
192
- ...flattenWorkflowNodeIds(node.then ?? []),
193
- ...flattenWorkflowNodeIds(node.else ?? []),
194
- ...(node.branches ?? []).flatMap((branch) =>
195
- flattenWorkflowNodeIds(branch.nodes ?? []),
196
- ),
197
- ]);
198
- }
199
-
200
- function buildNodeId(type: string, definition: WorkflowDefinitionDsl) {
201
- const suffix = type.split(".").pop() ?? "node";
202
- const base = suffix.replace(/[^a-zA-Z0-9]+/g, "");
203
- let attempt = base.charAt(0).toLowerCase() + base.slice(1);
204
- let counter = 1;
205
- const nodeIds = new Set(flattenWorkflowNodeIds(definition.nodes));
206
-
207
- while (nodeIds.has(attempt)) {
208
- counter += 1;
209
- attempt = `${base.charAt(0).toLowerCase() + base.slice(1)}${counter}`;
210
- }
211
-
212
- return attempt;
213
- }
214
-
215
- function buildBranchId(parentNodeId: string, node: WorkflowNodeRecord) {
216
- const existingIds = new Set((node.branches ?? []).map((branch) => branch.id));
217
- let counter = (node.branches ?? []).length + 1;
218
- let nextId = `${parentNodeId}Branch${counter}`;
219
-
220
- while (existingIds.has(nextId)) {
221
- counter += 1;
222
- nextId = `${parentNodeId}Branch${counter}`;
223
- }
224
-
225
- return nextId;
226
- }
227
-
228
- function countNodes(nodes: WorkflowNodeRecord[]): number {
229
- return nodes.reduce(
230
- (sum, node) =>
231
- sum +
232
- 1 +
233
- countNodes(node.children ?? []) +
234
- countNodes(node.nodes ?? []) +
235
- countNodes(node.then ?? []) +
236
- countNodes(node.else ?? []) +
237
- (node.branches ?? []).reduce(
238
- (branchSum, branch) => branchSum + countNodes(branch.nodes ?? []),
239
- 0,
240
- ),
241
- 0,
242
- );
243
- }
244
-
245
- function countTriggers(triggers?: Array<Record<string, any>>): number {
246
- return Array.isArray(triggers) ? triggers.length : 0;
247
- }
248
-
249
- function formatExecutionDate(value?: string | null) {
250
- if (!value) {
251
- return "Not available";
252
- }
253
-
254
- const parsed = new Date(value);
255
- if (Number.isNaN(parsed.getTime())) {
256
- return "Not available";
257
- }
258
-
259
- return parsed.toLocaleString(undefined, {
260
- year: "numeric",
261
- month: "short",
262
- day: "numeric",
263
- hour: "numeric",
264
- minute: "2-digit",
265
- });
266
- }
267
-
268
- function formatDurationMs(value?: number | string | null) {
269
- const numericValue =
270
- typeof value === "string" ? Number(value) : typeof value === "number" ? value : null;
271
-
272
- if (numericValue == null || Number.isNaN(numericValue) || numericValue <= 0) {
273
- return "Not available";
274
- }
275
-
276
- if (numericValue < 1000) {
277
- return `${numericValue} ms`;
278
- }
279
-
280
- const seconds = numericValue / 1000;
281
- if (seconds < 60) {
282
- return `${seconds.toFixed(seconds >= 10 ? 0 : 1)} s`;
283
- }
284
-
285
- const minutes = Math.floor(seconds / 60);
286
- const remainingSeconds = Math.round(seconds % 60);
287
- return `${minutes}m ${remainingSeconds}s`;
288
- }
289
-
290
- function getExecutionStatusCategory(status?: string | null) {
291
- const normalized = (status ?? "").trim().toLowerCase();
292
-
293
- if (["success", "succeeded", "completed", "complete"].includes(normalized)) {
294
- return "success";
295
- }
296
- if (["failed", "error", "errored", "cancelled", "canceled"].includes(normalized)) {
297
- return "failed";
298
- }
299
- if (["running", "in_progress", "in-progress", "started", "processing"].includes(normalized)) {
300
- return "inProgress";
301
- }
302
- if (["created", "pending", "queued", "scheduled"].includes(normalized)) {
303
- return "pending";
304
- }
305
-
306
- return "other";
307
- }
308
-
309
- function buildWorkflowExecutionQueryString(options: {
310
- workflowDefinitionId: number;
311
- startDate?: Date | null;
312
- endDate?: Date | null;
313
- limit?: number;
314
- }) {
315
- const queryData: Record<string, any> = {
316
- limit: options.limit ?? 100,
317
- offset: 0,
318
- sort: ["startedAt:desc", "id:desc"],
319
- filters: {
320
- workflowDefinition: {
321
- id: {
322
- $eq: options.workflowDefinitionId,
323
- },
324
- },
325
- },
326
- };
327
-
328
- if (options.startDate || options.endDate) {
329
- queryData.filters.startedAt = {};
330
- if (options.startDate) {
331
- const startDate = new Date(options.startDate);
332
- startDate.setHours(0, 0, 0, 0);
333
- queryData.filters.startedAt.$gte = startDate.toISOString();
334
- }
335
- if (options.endDate) {
336
- const endDate = new Date(options.endDate);
337
- endDate.setHours(23, 59, 59, 999);
338
- queryData.filters.startedAt.$lte = endDate.toISOString();
339
- }
340
- }
341
-
342
- return qs.stringify(queryData, { encodeValuesOnly: true });
343
- }
344
-
345
- function buildTriggerDocsModel(trigger: Record<string, any>): WorkflowDocsModel {
346
- const triggerEntries = Object.entries(trigger ?? {}).filter(
347
- ([key]) => !["id", "type", "description", "disabled", "name", "label"].includes(key),
348
- );
349
-
350
- return {
351
- title: trigger.label ?? trigger.name ?? trigger.id ?? "Trigger",
352
- subtitle: trigger.type ?? "Trigger",
353
- summary:
354
- trigger.description ??
355
- "Workflow trigger that can launch the workflow on a schedule or external event.",
356
- badges: ["trigger", trigger.disabled ? "disabled" : "enabled"].filter(Boolean),
357
- definitions: [
358
- {
359
- key: "behavior",
360
- label: "Behavior",
361
- content: trigger.disabled
362
- ? "This trigger is currently disabled and will not launch workflow executions until it is enabled."
363
- : "This trigger is currently enabled and may launch workflow executions based on its configuration.",
364
- },
365
- {
366
- key: "configuration",
367
- label: "Configuration",
368
- content: `\`\`\`yaml\n${YAML.stringify(trigger)}\`\`\``,
369
- },
370
- ],
371
- outputs: triggerEntries.map(([key, value]) => ({
372
- key,
373
- label: key,
374
- description:
375
- typeof value === "object"
376
- ? "Structured trigger configuration value."
377
- : `Current value: ${String(value)}`,
378
- valueType: Array.isArray(value)
379
- ? "array"
380
- : typeof value === "boolean"
381
- ? "boolean"
382
- : typeof value === "number"
383
- ? "number"
384
- : typeof value === "object"
385
- ? "object"
386
- : "string",
387
- })),
388
- };
389
- }
390
-
391
- function buildWorkflowDocsModel(definition: WorkflowDefinitionDsl): WorkflowDocsModel {
392
- return {
393
- title: "Workflow Definition",
394
- subtitle: "Workflow-level settings",
395
- summary:
396
- "Top-level inputs, variables, triggers, and description live here. Use workflow settings when the change is not about a single node.",
397
- badges: ["workflow", "settings"],
398
- definitions: [
399
- {
400
- key: "inputs",
401
- label: "Inputs",
402
- content: `\`\`\`yaml\n${YAML.stringify(definition.inputs ?? {})}\`\`\``,
403
- },
404
- {
405
- key: "variables",
406
- label: "Variables",
407
- content: `\`\`\`yaml\n${YAML.stringify(definition.variables ?? {})}\`\`\``,
408
- },
409
- {
410
- key: "triggers",
411
- label: "Triggers",
412
- content: `\`\`\`yaml\n${YAML.stringify(definition.triggers ?? [])}\`\`\``,
413
- },
414
- ],
415
- };
416
- }
417
-
418
- function findNodeById(
419
- nodes: WorkflowNodeRecord[],
420
- nodeId: string,
421
- ): WorkflowNodeRecord | undefined {
422
- for (const node of nodes) {
423
- if (String(node.id) === nodeId) {
424
- return node;
425
- }
426
-
427
- const fromChildren =
428
- findNodeById(node.children ?? [], nodeId) ??
429
- findNodeById(node.nodes ?? [], nodeId) ??
430
- findNodeById(node.then ?? [], nodeId) ??
431
- findNodeById(node.else ?? [], nodeId) ??
432
- (node.branches ?? []).reduce<WorkflowNodeRecord | undefined>(
433
- (found, branch) => found ?? findNodeById(branch.nodes ?? [], nodeId),
434
- undefined,
435
- );
436
-
437
- if (fromChildren) {
438
- return fromChildren;
439
- }
440
- }
441
-
442
- return undefined;
443
- }
444
-
445
- function getFirstNodeId(nodes: WorkflowNodeRecord[]): string {
446
- return nodes[0]?.id ?? "";
447
- }
448
-
449
- function updateNodeById(
450
- nodes: WorkflowNodeRecord[],
451
- nodeId: string,
452
- updater: (node: WorkflowNodeRecord) => WorkflowNodeRecord,
453
- ): WorkflowNodeRecord[] {
454
- return nodes.map((node) => {
455
- if (String(node.id) === nodeId) {
456
- return updater(node);
457
- }
458
-
459
- return {
460
- ...node,
461
- children: node.children
462
- ? updateNodeById(node.children, nodeId, updater)
463
- : node.children,
464
- nodes: node.nodes ? updateNodeById(node.nodes, nodeId, updater) : node.nodes,
465
- then: node.then ? updateNodeById(node.then, nodeId, updater) : node.then,
466
- else: node.else ? updateNodeById(node.else, nodeId, updater) : node.else,
467
- branches: node.branches?.map((branch) => ({
468
- ...branch,
469
- nodes: updateNodeById(branch.nodes ?? [], nodeId, updater),
470
- })),
471
- };
472
- });
473
- }
474
-
475
- function removeNodeById(
476
- nodes: WorkflowNodeRecord[],
477
- nodeId: string,
478
- ): WorkflowNodeRecord[] {
479
- return nodes
480
- .filter((node) => String(node.id) !== nodeId)
481
- .map((node) => ({
482
- ...node,
483
- children: node.children ? removeNodeById(node.children, nodeId) : node.children,
484
- nodes: node.nodes ? removeNodeById(node.nodes, nodeId) : node.nodes,
485
- then: node.then ? removeNodeById(node.then, nodeId) : node.then,
486
- else: node.else ? removeNodeById(node.else, nodeId) : node.else,
487
- branches: node.branches?.map((branch) => ({
488
- ...branch,
489
- nodes: removeNodeById(branch.nodes ?? [], nodeId),
490
- })),
491
- }));
492
- }
493
-
494
- function insertAt<T>(items: T[], index: number, item: T): T[] {
495
- const safeIndex = Math.max(0, Math.min(index, items.length));
496
- return [...items.slice(0, safeIndex), item, ...items.slice(safeIndex)];
497
- }
498
-
499
- function insertNodeIntoDefinition(
500
- definition: WorkflowDefinitionDsl,
501
- target: WorkflowInsertTarget,
502
- nodeToInsert: WorkflowNodeRecord,
503
- ): WorkflowDefinitionDsl {
504
- if (target.scope === "root") {
505
- return {
506
- ...definition,
507
- nodes: insertAt(definition.nodes, target.index, nodeToInsert),
508
- };
509
- }
510
-
511
- return {
512
- ...definition,
513
- nodes: updateNodeById(definition.nodes, target.parentNodeId, (node) => {
514
- if (target.scope === "slot") {
515
- const slotNodes = Array.isArray(node[target.slotKey])
516
- ? (node[target.slotKey] as WorkflowNodeRecord[])
517
- : [];
518
- return {
519
- ...node,
520
- [target.slotKey]: insertAt(slotNodes, target.index, nodeToInsert),
521
- };
522
- }
523
-
524
- return {
525
- ...node,
526
- branches: (node.branches ?? []).map((branch) =>
527
- branch.id === target.branchId
528
- ? {
529
- ...branch,
530
- nodes: insertAt(branch.nodes ?? [], target.index, nodeToInsert),
531
- }
532
- : branch,
533
- ),
534
- };
535
- }),
536
- };
537
- }
538
-
539
- function appendBranchToDefinition(
540
- definition: WorkflowDefinitionDsl,
541
- parentNodeId: string,
542
- ): WorkflowDefinitionDsl {
543
- return {
544
- ...definition,
545
- nodes: updateNodeById(definition.nodes, parentNodeId, (node) => ({
546
- ...node,
547
- branches: [
548
- ...(node.branches ?? []),
549
- {
550
- id: buildBranchId(parentNodeId, node),
551
- name: `Branch ${(node.branches ?? []).length + 1}`,
552
- nodes: [],
553
- },
554
- ],
555
- })),
556
- };
557
- }
558
-
559
- function getFieldValue(value: Record<string, any>, pathOrKey: string) {
560
- const parts = pathOrKey.split(".");
561
- let current: any = value;
562
- for (const part of parts) {
563
- current = current?.[part];
564
- if (current === undefined) {
565
- return undefined;
566
- }
567
- }
568
- return current;
569
- }
570
-
571
- function validateWorkflowDefinitionClient(
572
- definition: WorkflowDefinitionDsl,
573
- nodeTypes: WorkflowNodeMetadataResponse[],
574
- workflowKey: string,
575
- ): string[] {
576
- const errors: string[] = [];
577
- const nodeTypeMap = new Map(nodeTypes.map((item) => [item.type, item]));
578
- const seenNodeIds = new Set<string>();
579
-
580
- if (!workflowKey.trim()) {
581
- errors.push("Workflow key is required.");
582
- }
583
-
584
- if (!Array.isArray(definition.nodes) || !definition.nodes.length) {
585
- errors.push("Workflow definition must contain at least one root node.");
586
- }
587
-
588
- const validateNodeSequence = (nodes: WorkflowNodeRecord[], scopeLabel: string) => {
589
- nodes.forEach((node, index) => {
590
- const prefix = `${scopeLabel} node ${index + 1}`;
591
-
592
- if (!node.id) {
593
- errors.push(`${prefix} is missing an id.`);
594
- } else if (seenNodeIds.has(node.id)) {
595
- errors.push(`Duplicate workflow node id "${node.id}".`);
596
- } else {
597
- seenNodeIds.add(node.id);
598
- }
599
-
600
- if (!node.type) {
601
- errors.push(`${prefix} is missing a type.`);
602
- return;
603
- }
604
-
605
- const nodeType = nodeTypeMap.get(node.type);
606
- if (!nodeType) {
607
- errors.push(`Node "${node.id}" uses unregistered type "${node.type}".`);
608
- return;
609
- }
610
-
611
- const configuration = node.configuration ?? {};
612
- (nodeType.authoring?.configurationFields ?? []).forEach((field) => {
613
- if (!field.required) {
614
- return;
615
- }
616
-
617
- const value = getFieldValue(configuration, field.path ?? field.key);
618
- const isEmptyArray = Array.isArray(value) && value.length === 0;
619
- const isMissing =
620
- value === undefined ||
621
- value === null ||
622
- value === "" ||
623
- isEmptyArray;
624
-
625
- if (isMissing) {
626
- errors.push(
627
- `Node "${node.id}" is missing required field "${field.label ?? field.key}".`,
628
- );
629
- }
630
- });
631
-
632
- (nodeType.authoring?.childSlots ?? []).forEach((slot) => {
633
- if (slot.kind === "branch-collection") {
634
- const branchCount = Array.isArray(node.branches) ? node.branches.length : 0;
635
- if (slot.required && branchCount === 0) {
636
- errors.push(
637
- `Node "${node.id}" requires at least one branch in "${slot.label ?? slot.key}".`,
638
- );
639
- }
640
- if (slot.minItems && branchCount < slot.minItems) {
641
- errors.push(
642
- `Node "${node.id}" requires at least ${slot.minItems} branches in "${slot.label ?? slot.key}".`,
643
- );
644
- }
645
- } else {
646
- const slotNodes = Array.isArray(node[slot.key]) ? node[slot.key] : [];
647
- if (slot.required && slotNodes.length === 0) {
648
- errors.push(
649
- `Node "${node.id}" requires at least one child node in "${slot.label ?? slot.key}".`,
650
- );
651
- }
652
- if (slot.minItems && slotNodes.length < slot.minItems) {
653
- errors.push(
654
- `Node "${node.id}" requires at least ${slot.minItems} nodes in "${slot.label ?? slot.key}".`,
655
- );
656
- }
657
- }
658
- });
659
-
660
- validateNodeSequence(node.children ?? [], `${node.id} children`);
661
- validateNodeSequence(node.nodes ?? [], `${node.id} nodes`);
662
- validateNodeSequence(node.then ?? [], `${node.id} then`);
663
- validateNodeSequence(node.else ?? [], `${node.id} else`);
664
- (node.branches ?? []).forEach((branch, branchIndex) => {
665
- if (!branch.id) {
666
- errors.push(`Node "${node.id}" has a branch without an id.`);
667
- }
668
- validateNodeSequence(
669
- branch.nodes ?? [],
670
- `${node.id} branch ${branch.name ?? branch.id ?? branchIndex + 1}`,
671
- );
672
- });
673
- });
674
- };
675
-
676
- validateNodeSequence(definition.nodes, "root");
677
- return errors;
678
- }
679
-
680
- export function WorkflowDefinitionEditorPage() {
681
- const params = useParams();
682
- const navigate = useNavigate();
683
- const dispatch = useDispatch();
684
-
685
- const entityApi = React.useMemo(
686
- () => createSolidEntityApi("workflowDefinition"),
687
- [],
688
- );
689
- const workflowExecutionApi = React.useMemo(
690
- () => createSolidEntityApi("workflowExecution"),
691
- [],
692
- );
693
- const {
694
- useCreateSolidEntityMutation,
695
- useGetSolidEntityByIdQuery,
696
- useUpdateSolidEntityMutation,
697
- } = entityApi;
698
- const {
699
- useLazyGetSolidEntitiesQuery: useLazyGetWorkflowExecutionsQuery,
700
- } = workflowExecutionApi;
701
-
702
- const workflowDefinitionId = params.id ?? "";
703
- const moduleName = params.moduleName ?? "solid-core";
704
-
705
- const {
706
- data: workflowDefinitionResponse,
707
- isLoading: isWorkflowDefinitionLoading,
708
- refetch,
709
- } = useGetSolidEntityByIdQuery(
710
- { id: workflowDefinitionId, qs: "" },
711
- { skip: !workflowDefinitionId || workflowDefinitionId === "new" },
712
- );
713
- const [createWorkflowDefinition, { isLoading: isCreating }] =
714
- useCreateSolidEntityMutation();
715
- const [updateWorkflowDefinition, { isLoading: isSaving }] =
716
- useUpdateSolidEntityMutation();
717
- const [validateWorkflowDefinition, { isLoading: isServerValidating }] =
718
- useValidateWorkflowDefinitionMutation();
719
- const [executeWorkflowDefinition, { isLoading: isExecuting }] =
720
- useExecuteWorkflowDefinitionMutation();
721
- const [triggerGetWorkflowExecutions, workflowExecutionsQuery] =
722
- useLazyGetWorkflowExecutionsQuery();
723
- const [triggerGetWorkflowExecutionPresence, workflowExecutionPresenceQuery] =
724
- useLazyGetWorkflowExecutionsQuery();
725
-
726
- const {
727
- data: nodeTypes = [],
728
- isLoading: isNodeTypesLoading,
729
- isError: isNodeTypesError,
730
- } = useGetWorkflowNodeTypesQuery();
731
-
732
- const record = workflowDefinitionResponse?.data as
733
- | WorkflowDefinitionRecord
734
- | undefined;
735
-
736
- const [workflowKey, setWorkflowKey] = React.useState("");
737
- const [workflowDisplayName, setWorkflowDisplayName] = React.useState("");
738
- const [workflowDescription, setWorkflowDescription] = React.useState("");
739
- const [definitionDraft, setDefinitionDraft] = React.useState<WorkflowDefinitionDsl>(
740
- createEmptyWorkflowDefinition(),
741
- );
742
- const [codeValue, setCodeValue] = React.useState(
743
- serializeWorkflowDefinitionYaml(createEmptyWorkflowDefinition()),
744
- );
745
- const [codeError, setCodeError] = React.useState<string | null>(null);
746
- const [paletteNodeTypeKey, setPaletteNodeTypeKey] = React.useState<string>("");
747
- const [selectedNodeId, setSelectedNodeId] = React.useState<string>("");
748
- const [selectedTriggerId, setSelectedTriggerId] = React.useState<string>("");
749
- const [editorOpen, setEditorOpen] = React.useState(false);
750
- const [workflowSettingsOpen, setWorkflowSettingsOpen] = React.useState(false);
751
- const [workflowInputsValue, setWorkflowInputsValue] = React.useState("{}");
752
- const [workflowVariablesValue, setWorkflowVariablesValue] = React.useState("{}");
753
- const [workflowTriggersValue, setWorkflowTriggersValue] = React.useState("[]");
754
- const [docsOpen, setDocsOpen] = React.useState(false);
755
- const [docsNodeTypeKey, setDocsNodeTypeKey] = React.useState<string>("");
756
- const [topologyDocsOpen, setTopologyDocsOpen] = React.useState(false);
757
- const [topologyDocsNodeTypeKey, setTopologyDocsNodeTypeKey] =
758
- React.useState<string>("");
759
- const [topologyDocsModel, setTopologyDocsModel] =
760
- React.useState<WorkflowDocsModel | undefined>();
761
- const [detailTab, setDetailTab] = React.useState<WorkflowDetailTab>(
762
- workflowDefinitionId === "new" ? "edit" : "overview",
763
- );
764
- const [activePanel, setActivePanel] = React.useState<"code" | "flow" | "docs">(
765
- "flow",
766
- );
767
- const [toolsOpen, setToolsOpen] = React.useState(false);
768
- const [codePaneOpen, setCodePaneOpen] = React.useState(false);
769
- const [topologyViewOpen, setTopologyViewOpen] = React.useState(true);
770
- const [topologyYamlViewOpen, setTopologyYamlViewOpen] = React.useState(false);
771
- const [topologySplitPercent, setTopologySplitPercent] = React.useState(
772
- readStoredTopologySplitPercent,
773
- );
774
- const topologySplitRef = React.useRef<HTMLDivElement | null>(null);
775
- const [overviewStartDate, setOverviewStartDate] = React.useState<Date | null>(null);
776
- const [overviewEndDate, setOverviewEndDate] = React.useState<Date | null>(null);
777
- const [validationState, setValidationState] = React.useState<ValidationState>({
778
- status: "idle",
779
- errors: [],
780
- });
781
-
782
- React.useEffect(() => {
783
- setDetailTab(workflowDefinitionId === "new" ? "edit" : "overview");
784
- }, [workflowDefinitionId]);
785
-
786
- React.useEffect(() => {
787
- setOverviewStartDate(null);
788
- setOverviewEndDate(null);
789
- }, [workflowDefinitionId]);
790
-
791
- React.useEffect(() => {
792
- if (workflowDefinitionId === "new") {
793
- const emptyDefinition = createEmptyWorkflowDefinition();
794
- setWorkflowKey("");
795
- setWorkflowDisplayName("");
796
- setWorkflowDescription("");
797
- setDefinitionDraft(emptyDefinition);
798
- setCodeValue(serializeWorkflowDefinitionYaml(emptyDefinition));
799
- setCodeError(null);
800
- setSelectedNodeId("");
801
- setSelectedTriggerId("");
802
- setValidationState({ status: "idle", errors: [] });
803
- return;
804
- }
805
-
806
- if (!record) {
807
- return;
808
- }
809
-
810
- const normalized = normalizeWorkflowDefinition(record.definitionYaml);
811
- setWorkflowKey(record.key ?? "");
812
- setWorkflowDisplayName(record.displayName ?? "");
813
- setWorkflowDescription(record.description ?? normalized.description ?? "");
814
- setDefinitionDraft(normalized);
815
- setCodeValue(serializeWorkflowDefinitionYaml(normalized));
816
- setCodeError(null);
817
- setSelectedNodeId(getFirstNodeId(normalized.nodes));
818
- setSelectedTriggerId("");
819
- setValidationState({ status: "idle", errors: [] });
820
- }, [record, workflowDefinitionId]);
821
-
822
- React.useEffect(() => {
823
- if (!paletteNodeTypeKey && nodeTypes.length) {
824
- setPaletteNodeTypeKey(nodeTypes[0].type);
825
- }
826
- }, [nodeTypes, paletteNodeTypeKey]);
827
-
828
- React.useEffect(() => {
829
- if (!selectedNodeId) {
830
- return;
831
- }
832
-
833
- if (!findNodeById(definitionDraft.nodes, selectedNodeId)) {
834
- setSelectedNodeId(getFirstNodeId(definitionDraft.nodes));
835
- }
836
- }, [definitionDraft.nodes, selectedNodeId]);
837
-
838
- React.useEffect(() => {
839
- if (!selectedTriggerId) {
840
- return;
841
- }
842
-
843
- const exists = (definitionDraft.triggers ?? []).some(
844
- (trigger) => String(trigger.id) === selectedTriggerId,
845
- );
846
- if (!exists) {
847
- setSelectedTriggerId("");
848
- }
849
- }, [definitionDraft.triggers, selectedTriggerId]);
850
-
851
- React.useEffect(() => {
852
- if (typeof window === "undefined") {
853
- return;
854
- }
855
-
856
- window.localStorage.setItem(
857
- TOPOLOGY_SPLIT_STORAGE_KEY,
858
- String(Math.round(topologySplitPercent)),
859
- );
860
- }, [topologySplitPercent]);
861
-
862
- React.useEffect(() => {
863
- if (!workflowSettingsOpen) {
864
- return;
865
- }
866
-
867
- setWorkflowInputsValue(YAML.stringify(definitionDraft.inputs ?? {}));
868
- setWorkflowVariablesValue(YAML.stringify(definitionDraft.variables ?? {}));
869
- setWorkflowTriggersValue(YAML.stringify(definitionDraft.triggers ?? []));
870
- }, [definitionDraft, workflowSettingsOpen]);
871
-
872
- const paletteNodeType = React.useMemo(
873
- () => nodeTypes.find((nodeType) => nodeType.type === paletteNodeTypeKey),
874
- [nodeTypes, paletteNodeTypeKey],
875
- );
876
-
877
- const selectedNode = React.useMemo(
878
- () => findNodeById(definitionDraft.nodes, selectedNodeId),
879
- [definitionDraft.nodes, selectedNodeId],
880
- );
881
-
882
- const selectedNodeType = React.useMemo(() => {
883
- if (!selectedNode?.type) {
884
- return undefined;
885
- }
886
- return nodeTypes.find((nodeType) => nodeType.type === selectedNode.type);
887
- }, [nodeTypes, selectedNode]);
888
-
889
- const selectedTrigger = React.useMemo(
890
- () =>
891
- (definitionDraft.triggers ?? []).find(
892
- (trigger) => String(trigger.id) === selectedTriggerId,
893
- ),
894
- [definitionDraft.triggers, selectedTriggerId],
895
- );
896
-
897
- const docsNodeType = React.useMemo(() => {
898
- if (docsNodeTypeKey) {
899
- return nodeTypes.find((nodeType) => nodeType.type === docsNodeTypeKey);
900
- }
901
- return selectedTrigger ? undefined : selectedNodeType ?? paletteNodeType;
902
- }, [
903
- docsNodeTypeKey,
904
- nodeTypes,
905
- paletteNodeType,
906
- selectedNodeType,
907
- selectedTrigger,
908
- ]);
909
-
910
- const docsModel = React.useMemo(() => {
911
- if (selectedTrigger) {
912
- return buildTriggerDocsModel(selectedTrigger);
913
- }
914
- if (!selectedNode && !selectedTrigger) {
915
- return buildWorkflowDocsModel(definitionDraft);
916
- }
917
- return undefined;
918
- }, [definitionDraft, selectedNode, selectedTrigger]);
919
-
920
- const topologyDocsNodeType = React.useMemo(() => {
921
- if (!topologyDocsNodeTypeKey) {
922
- return undefined;
923
- }
924
- return nodeTypes.find((nodeType) => nodeType.type === topologyDocsNodeTypeKey);
925
- }, [nodeTypes, topologyDocsNodeTypeKey]);
926
-
927
- const workflowStats = React.useMemo(
928
- () => ({
929
- nodeCount: countNodes(definitionDraft.nodes),
930
- triggerCount: countTriggers(definitionDraft.triggers),
931
- inputCount:
932
- definitionDraft.inputs && typeof definitionDraft.inputs === "object"
933
- ? Array.isArray(definitionDraft.inputs)
934
- ? definitionDraft.inputs.length
935
- : Object.keys(definitionDraft.inputs).length
936
- : 0,
937
- }),
938
- [definitionDraft],
939
- );
940
-
941
- const numericWorkflowDefinitionId = React.useMemo(() => {
942
- const candidate = record?.id ?? Number(workflowDefinitionId);
943
- const parsedCandidate =
944
- typeof candidate === "number" ? candidate : Number(candidate);
945
- return Number.isFinite(parsedCandidate) ? parsedCandidate : null;
946
- }, [record?.id, workflowDefinitionId]);
947
-
948
- const validationTag = React.useMemo(() => {
949
- if (validationState.status === "valid") {
950
- return { tone: "success" as const, label: "Validated" };
951
- }
952
- if (validationState.status === "invalid") {
953
- return { tone: "danger" as const, label: "Needs fixes" };
954
- }
955
- if (validationState.status === "validating") {
956
- return { tone: undefined, label: "Validating" };
957
- }
958
- return { tone: undefined, label: "Not validated" };
959
- }, [validationState.status]);
960
-
961
- const loadWorkflowExecutions = React.useCallback(async () => {
962
- if (!numericWorkflowDefinitionId) {
963
- return;
964
- }
965
-
966
- await triggerGetWorkflowExecutions(
967
- buildWorkflowExecutionQueryString({
968
- workflowDefinitionId: numericWorkflowDefinitionId,
969
- startDate: overviewStartDate,
970
- endDate: overviewEndDate,
971
- }),
972
- );
973
- }, [
974
- numericWorkflowDefinitionId,
975
- overviewEndDate,
976
- overviewStartDate,
977
- triggerGetWorkflowExecutions,
978
- ]);
979
-
980
- React.useEffect(() => {
981
- if (!numericWorkflowDefinitionId || workflowDefinitionId === "new") {
982
- return;
983
- }
984
-
985
- void triggerGetWorkflowExecutionPresence(
986
- buildWorkflowExecutionQueryString({
987
- workflowDefinitionId: numericWorkflowDefinitionId,
988
- limit: 1,
989
- }),
990
- );
991
- }, [
992
- numericWorkflowDefinitionId,
993
- triggerGetWorkflowExecutionPresence,
994
- workflowDefinitionId,
995
- ]);
996
-
997
- React.useEffect(() => {
998
- if (
999
- detailTab !== "overview" ||
1000
- !numericWorkflowDefinitionId ||
1001
- workflowDefinitionId === "new"
1002
- ) {
1003
- return;
1004
- }
1005
-
1006
- void loadWorkflowExecutions();
1007
- }, [
1008
- detailTab,
1009
- loadWorkflowExecutions,
1010
- numericWorkflowDefinitionId,
1011
- workflowDefinitionId,
1012
- ]);
1013
-
1014
- const executionRecords = React.useMemo(
1015
- () => ((workflowExecutionsQuery.data?.records ?? []) as WorkflowExecutionRecord[]),
1016
- [workflowExecutionsQuery.data?.records],
1017
- );
1018
-
1019
- const hasExecutions = React.useMemo(
1020
- () => (workflowExecutionPresenceQuery.data?.meta?.totalRecords ?? 0) > 0,
1021
- [workflowExecutionPresenceQuery.data?.meta?.totalRecords],
1022
- );
1023
-
1024
- const executionOverview = React.useMemo(() => {
1025
- const totals = {
1026
- total: executionRecords.length,
1027
- success: 0,
1028
- failed: 0,
1029
- inProgress: 0,
1030
- pending: 0,
1031
- other: 0,
1032
- totalDurationMs: 0,
1033
- durationCount: 0,
1034
- };
1035
-
1036
- for (const execution of executionRecords) {
1037
- const category = getExecutionStatusCategory(execution.status);
1038
- totals[category] += 1;
1039
-
1040
- const durationValue =
1041
- typeof execution.durationMs === "string"
1042
- ? Number(execution.durationMs)
1043
- : execution.durationMs;
1044
- if (
1045
- typeof durationValue === "number" &&
1046
- Number.isFinite(durationValue) &&
1047
- durationValue > 0
1048
- ) {
1049
- totals.totalDurationMs += durationValue;
1050
- totals.durationCount += 1;
1051
- }
1052
- }
1053
-
1054
- const terminalCount = totals.success + totals.failed;
1055
- const successRatio = terminalCount ? Math.round((totals.success / terminalCount) * 100) : 0;
1056
- const failedRatio = terminalCount ? Math.round((totals.failed / terminalCount) * 100) : 0;
1057
-
1058
- return {
1059
- ...totals,
1060
- successRatio,
1061
- failedRatio,
1062
- averageDurationMs: totals.durationCount
1063
- ? Math.round(totals.totalDurationMs / totals.durationCount)
1064
- : null,
1065
- latestExecution: executionRecords[0],
1066
- };
1067
- }, [executionRecords]);
1068
-
1069
- const overviewDateFilterLabel = React.useMemo(() => {
1070
- if (!overviewStartDate && !overviewEndDate) {
1071
- return "All dates";
1072
- }
1073
-
1074
- const formatDateOnly = (value: Date | null) =>
1075
- value
1076
- ? value.toLocaleDateString(undefined, {
1077
- year: "numeric",
1078
- month: "short",
1079
- day: "numeric",
1080
- })
1081
- : null;
1082
-
1083
- const start = formatDateOnly(overviewStartDate);
1084
- const end = formatDateOnly(overviewEndDate);
1085
-
1086
- if (start && end) {
1087
- return `${start} - ${end}`;
1088
- }
1089
- if (start) {
1090
- return `From ${start}`;
1091
- }
1092
- return `Until ${end}`;
1093
- }, [overviewEndDate, overviewStartDate]);
1094
-
1095
- const syncDraftToCode = React.useCallback((nextDraft: WorkflowDefinitionDsl) => {
1096
- setDefinitionDraft(nextDraft);
1097
- setCodeValue(serializeWorkflowDefinitionYaml(nextDraft));
1098
- setCodeError(null);
1099
- setValidationState({ status: "idle", errors: [] });
1100
- }, []);
1101
-
1102
- const handleSaveWorkflowSettings = React.useCallback(() => {
1103
- try {
1104
- const nextInputs = parseYamlValue<Record<string, any>>(workflowInputsValue, {});
1105
- const nextVariables = parseYamlValue<Record<string, any>>(workflowVariablesValue, {});
1106
- const nextTriggers = parseYamlValue<Array<Record<string, any>>>(workflowTriggersValue, []);
1107
-
1108
- if (!Array.isArray(nextTriggers)) {
1109
- throw new Error("Triggers must be a YAML sequence.");
1110
- }
1111
-
1112
- const nextDraft: WorkflowDefinitionDsl = {
1113
- ...definitionDraft,
1114
- description: workflowDescription,
1115
- inputs: nextInputs,
1116
- variables: nextVariables,
1117
- triggers: nextTriggers,
1118
- };
1119
-
1120
- syncDraftToCode(nextDraft);
1121
- setWorkflowSettingsOpen(false);
1122
- dispatch(
1123
- showToast({
1124
- severity: "success",
1125
- summary: "Workflow settings updated",
1126
- detail: "Inputs, variables, and triggers were updated in the draft.",
1127
- }),
1128
- );
1129
- } catch (error: any) {
1130
- dispatch(
1131
- showToast({
1132
- severity: "error",
1133
- summary: "Invalid workflow settings",
1134
- detail:
1135
- error?.message ??
1136
- "Fix the workflow-level YAML blocks before saving the settings.",
1137
- }),
1138
- );
1139
- }
1140
- }, [
1141
- definitionDraft,
1142
- dispatch,
1143
- syncDraftToCode,
1144
- workflowDescription,
1145
- workflowInputsValue,
1146
- workflowTriggersValue,
1147
- workflowVariablesValue,
1148
- ]);
1149
-
1150
- const handleCodeChange = (nextValue: string | undefined) => {
1151
- const safeValue = nextValue ?? "";
1152
- setCodeValue(safeValue);
1153
-
1154
- try {
1155
- const parsed = YAML.parse(safeValue);
1156
- const normalized = normalizeWorkflowDefinition(parsed);
1157
- setDefinitionDraft(normalized);
1158
- setCodeError(null);
1159
- setValidationState({ status: "idle", errors: [] });
1160
- } catch (error: any) {
1161
- setCodeError(error?.message ?? "Invalid YAML");
1162
- setValidationState({
1163
- status: "invalid",
1164
- source: "client",
1165
- message: "Definition YAML is invalid.",
1166
- errors: [error?.message ?? "Invalid YAML"],
1167
- });
1168
- }
1169
- };
1170
-
1171
- const startTopologySplitResize = React.useCallback(
1172
- (event: React.MouseEvent<HTMLDivElement>) => {
1173
- event.preventDefault();
1174
- const container = topologySplitRef.current;
1175
- if (!container) {
1176
- return;
1177
- }
1178
-
1179
- const handleMouseMove = (moveEvent: MouseEvent) => {
1180
- const rect = container.getBoundingClientRect();
1181
- if (!rect.width) {
1182
- return;
1183
- }
1184
-
1185
- const nextPercent = ((moveEvent.clientX - rect.left) / rect.width) * 100;
1186
- setTopologySplitPercent(Math.min(78, Math.max(22, nextPercent)));
1187
- };
1188
-
1189
- const handleMouseUp = () => {
1190
- document.removeEventListener("mousemove", handleMouseMove);
1191
- document.removeEventListener("mouseup", handleMouseUp);
1192
- };
1193
-
1194
- document.addEventListener("mousemove", handleMouseMove);
1195
- document.addEventListener("mouseup", handleMouseUp);
1196
- },
1197
- [],
1198
- );
1199
-
1200
- const createNodeFromType = (nodeType: WorkflowNodeMetadataResponse): WorkflowNodeRecord => {
1201
- const nextNode: WorkflowNodeRecord = {
1202
- id: buildNodeId(nodeType.type, definitionDraft),
1203
- kind: nodeType.kind,
1204
- type: nodeType.type,
1205
- name: nodeType.label ?? nodeType.type,
1206
- description: nodeType.description ?? "",
1207
- configuration: nodeType.authoring?.defaultConfiguration ?? {},
1208
- };
1209
-
1210
- (nodeType.authoring?.childSlots ?? []).forEach((slot) => {
1211
- if (slot.kind === "branch-collection") {
1212
- const branchCount = Math.max(slot.minItems ?? 0, slot.required ? 1 : 0);
1213
- nextNode.branches = Array.from({ length: branchCount }, (_, index) => ({
1214
- id: `${nextNode.id}Branch${index + 1}`,
1215
- name: `Branch ${index + 1}`,
1216
- nodes: [],
1217
- }));
1218
- return;
1219
- }
1220
-
1221
- nextNode[slot.key] = nextNode[slot.key] ?? [];
1222
- });
1223
-
1224
- return nextNode;
1225
- };
1226
-
1227
- const validateCurrentDefinition = React.useCallback(
1228
- async (options?: { showSuccessToast?: boolean }) => {
1229
- if (codeError) {
1230
- const nextState: ValidationState = {
1231
- status: "invalid",
1232
- source: "client",
1233
- message: "Definition YAML is invalid.",
1234
- errors: [codeError],
1235
- };
1236
- setValidationState(nextState);
1237
- setActivePanel("code");
1238
- return { valid: false, errors: nextState.errors };
1239
- }
1240
-
1241
- setValidationState({
1242
- status: "validating",
1243
- errors: [],
1244
- message: "Validating workflow definition...",
1245
- });
1246
-
1247
- const clientErrors = validateWorkflowDefinitionClient(
1248
- {
1249
- ...definitionDraft,
1250
- description: workflowDescription,
1251
- },
1252
- nodeTypes,
1253
- workflowKey,
1254
- );
1255
-
1256
- if (clientErrors.length) {
1257
- const nextState: ValidationState = {
1258
- status: "invalid",
1259
- source: "client",
1260
- message: "Client-side validation failed.",
1261
- errors: clientErrors,
1262
- };
1263
- setValidationState(nextState);
1264
- setActivePanel("flow");
1265
- return { valid: false, errors: clientErrors };
1266
- }
1267
-
1268
- try {
1269
- const response: any = await validateWorkflowDefinition({
1270
- definitionYaml: serializeWorkflowDefinitionYaml({
1271
- ...definitionDraft,
1272
- description: workflowDescription,
1273
- }),
1274
- }).unwrap();
1275
-
1276
- const nextState: ValidationState = {
1277
- status: "valid",
1278
- source: "server",
1279
- message: response?.message ?? "Workflow definition is valid.",
1280
- errors: [],
1281
- };
1282
- setValidationState(nextState);
1283
-
1284
- if (options?.showSuccessToast) {
1285
- dispatch(
1286
- showToast({
1287
- severity: "success",
1288
- summary: "Validation passed",
1289
- detail: nextState.message,
1290
- }),
1291
- );
1292
- }
1293
-
1294
- return { valid: true, errors: [] };
1295
- } catch (error: any) {
1296
- const detail =
1297
- error?.data?.message ??
1298
- error?.message ??
1299
- "Workflow validation failed on the server.";
1300
- const nextState: ValidationState = {
1301
- status: "invalid",
1302
- source: "server",
1303
- message: detail,
1304
- errors: [detail],
1305
- };
1306
- setValidationState(nextState);
1307
- setActivePanel("flow");
1308
- return { valid: false, errors: [detail] };
1309
- }
1310
- },
1311
- [
1312
- codeError,
1313
- definitionDraft,
1314
- dispatch,
1315
- nodeTypes,
1316
- validateWorkflowDefinition,
1317
- workflowDescription,
1318
- workflowKey,
1319
- ],
1320
- );
1321
-
1322
- const handleInsertNode = (target: WorkflowInsertTarget) => {
1323
- if (!paletteNodeType) {
1324
- dispatch(
1325
- showToast({
1326
- severity: "warn",
1327
- summary: "Pick a node type",
1328
- detail: "Select a node type from the palette before inserting into the flow.",
1329
- }),
1330
- );
1331
- return;
1332
- }
1333
-
1334
- const nextNode = createNodeFromType(paletteNodeType);
1335
- const nextDraft = insertNodeIntoDefinition(definitionDraft, target, nextNode);
1336
- syncDraftToCode(nextDraft);
1337
- setSelectedNodeId(nextNode.id);
1338
- setDocsNodeTypeKey(nextNode.type);
1339
- setEditorOpen(true);
1340
- setActivePanel("flow");
1341
- };
1342
-
1343
- const handleAddBranch = (parentNodeId: string) => {
1344
- const nextDraft = appendBranchToDefinition(definitionDraft, parentNodeId);
1345
- syncDraftToCode(nextDraft);
1346
- };
1347
-
1348
- const handleUpdateSelectedNode = (nextNode: WorkflowNodeRecord) => {
1349
- if (!selectedNode) {
1350
- return;
1351
- }
1352
-
1353
- const nextDraft = {
1354
- ...definitionDraft,
1355
- nodes: updateNodeById(definitionDraft.nodes, selectedNode.id, () => nextNode),
1356
- };
1357
-
1358
- syncDraftToCode(nextDraft);
1359
- setSelectedNodeId(nextNode.id);
1360
- setDocsNodeTypeKey(nextNode.type);
1361
- };
1362
-
1363
- const handleRemoveNode = (nodeId: string) => {
1364
- const nextDraft = {
1365
- ...definitionDraft,
1366
- nodes: removeNodeById(definitionDraft.nodes, nodeId),
1367
- };
1368
- syncDraftToCode(nextDraft);
1369
- if (selectedNodeId === nodeId) {
1370
- setSelectedNodeId(getFirstNodeId(nextDraft.nodes));
1371
- }
1372
- };
1373
-
1374
- const handleSave = async () => {
1375
- const validation = await validateCurrentDefinition();
1376
- if (!validation.valid) {
1377
- dispatch(
1378
- showToast({
1379
- severity: "error",
1380
- summary: "Validation failed",
1381
- detail: validation.errors[0] ?? "Fix validation errors before saving.",
1382
- }),
1383
- );
1384
- return;
1385
- }
1386
-
1387
- const payload = {
1388
- key: workflowKey,
1389
- displayName: workflowDisplayName,
1390
- description: workflowDescription,
1391
- definitionYaml: serializeWorkflowDefinitionYaml({
1392
- ...definitionDraft,
1393
- description: workflowDescription,
1394
- }),
1395
- };
1396
-
1397
- try {
1398
- if (record?.id) {
1399
- await updateWorkflowDefinition({
1400
- id: record.id,
1401
- data: {
1402
- ...record,
1403
- ...payload,
1404
- },
1405
- }).unwrap();
1406
- dispatch(
1407
- showToast({
1408
- severity: "success",
1409
- summary: "Saved",
1410
- detail: "Workflow definition updated successfully.",
1411
- }),
1412
- );
1413
- refetch();
1414
- } else {
1415
- const result: any = await createWorkflowDefinition(payload).unwrap();
1416
- const createdId = result?.data?.id ?? result?.id;
1417
- dispatch(
1418
- showToast({
1419
- severity: "success",
1420
- summary: "Created",
1421
- detail: "Workflow definition created successfully.",
1422
- }),
1423
- );
1424
- if (createdId) {
1425
- navigate(
1426
- `/admin/core/${moduleName}/workflow-definition/editor/${createdId}`,
1427
- { replace: true },
1428
- );
1429
- }
1430
- }
1431
- } catch (error: any) {
1432
- dispatch(
1433
- showToast({
1434
- severity: "error",
1435
- summary: "Save failed",
1436
- detail:
1437
- error?.data?.message ??
1438
- error?.message ??
1439
- "Failed to save workflow definition.",
1440
- }),
1441
- );
1442
- }
1443
- };
1444
-
1445
- const handleExecute = async () => {
1446
- if (!record?.id) {
1447
- dispatch(
1448
- showToast({
1449
- severity: "warn",
1450
- summary: "Save first",
1451
- detail: "Create the workflow definition before launching execution.",
1452
- }),
1453
- );
1454
- return;
1455
- }
1456
-
1457
- const validation = await validateCurrentDefinition();
1458
- if (!validation.valid) {
1459
- dispatch(
1460
- showToast({
1461
- severity: "error",
1462
- summary: "Execution blocked",
1463
- detail: validation.errors[0] ?? "Workflow validation failed.",
1464
- }),
1465
- );
1466
- return;
1467
- }
1468
-
1469
- try {
1470
- const response: any = await executeWorkflowDefinition({ id: record.id }).unwrap();
1471
- dispatch(
1472
- showToast({
1473
- severity: response?.status === "failed" ? "error" : "success",
1474
- summary:
1475
- response?.status === "failed"
1476
- ? "Execution failed"
1477
- : "Execution started",
1478
- detail:
1479
- response?.executionIdentifier ??
1480
- response?.errorSummary ??
1481
- "Workflow execution request completed.",
1482
- }),
1483
- );
1484
- } catch (error: any) {
1485
- dispatch(
1486
- showToast({
1487
- severity: "error",
1488
- summary: "Execution failed",
1489
- detail:
1490
- error?.data?.message ??
1491
- error?.message ??
1492
- "Failed to execute workflow definition.",
1493
- }),
1494
- );
1495
- }
1496
- };
1497
-
1498
- const renderPlaceholderTab = (label: string, message: string) => (
1499
- <div className="workflow-editor-placeholder">
1500
- <div className="workflow-editor-placeholder__icon">
1501
- <Activity size={20} />
1502
- </div>
1503
- <div className="workflow-editor-placeholder__copy">
1504
- <h3>{label}</h3>
1505
- <p>{message}</p>
1506
- </div>
1507
- </div>
1508
- );
1509
-
1510
- const overviewContent =
1511
- workflowDefinitionId === "new" ? (
1512
- <div className="workflow-editor-overview workflow-editor-overview--empty">
1513
- <div className="workflow-editor-overview-cta">
1514
- <div className="workflow-editor-overview-cta__art">
1515
- <Save size={26} />
1516
- </div>
1517
- <div className="workflow-editor-overview-cta__copy">
1518
- <h2>Save this workflow to unlock the overview.</h2>
1519
- <p>
1520
- Once this definition exists, the overview tab will switch to execution
1521
- analytics, KPI summaries, and date-based filtering.
1522
- </p>
1523
- </div>
1524
- <div className="workflow-editor-overview-cta__actions">
1525
- <SolidButton leftIcon={<Save size={16} />} onClick={handleSave}>
1526
- Save Workflow
1527
- </SolidButton>
1528
- <SolidButton variant="outline" onClick={() => setDetailTab("edit")}>
1529
- Continue Editing
1530
- </SolidButton>
1531
- </div>
1532
- </div>
1533
- </div>
1534
- ) : !hasExecutions ? (
1535
- <div className="workflow-editor-overview workflow-editor-overview--empty">
1536
- <div className="workflow-editor-overview-cta">
1537
- <div className="workflow-editor-overview-cta__art">
1538
- <GitBranchPlus size={28} />
1539
- </div>
1540
- <div className="workflow-editor-overview-cta__copy">
1541
- <h2>{workflowDisplayName || record?.displayName || workflowKey || "Workflow"}</h2>
1542
- <p>
1543
- Run the workflow once to unlock execution history, operational KPIs,
1544
- and workflow activity for this definition.
1545
- </p>
1546
- </div>
1547
- <div className="workflow-editor-overview-cta__actions">
1548
- <SolidButton
1549
- leftIcon={<Play size={16} />}
1550
- loading={isExecuting}
1551
- onClick={() => void handleExecute()}
1552
- >
1553
- Execute Workflow
1554
- </SolidButton>
1555
- <SolidButton variant="outline" onClick={() => setDetailTab("edit")}>
1556
- Open Builder
1557
- </SolidButton>
1558
- </div>
1559
- </div>
1560
-
1561
- <div className="workflow-editor-overview-guides">
1562
- <div className="workflow-editor-overview-guide-card">
1563
- <h3>Overview</h3>
1564
- <p>Execution KPIs and health snapshots appear here after the first successful run.</p>
1565
- </div>
1566
- <div className="workflow-editor-overview-guide-card">
1567
- <h3>Edit</h3>
1568
- <p>Refine YAML, topology, nodes, inputs, and triggers inside the builder workspace.</p>
1569
- </div>
1570
- <div className="workflow-editor-overview-guide-card">
1571
- <h3>Executions</h3>
1572
- <p>Execution history and drill-downs will become available as runs accumulate.</p>
1573
- </div>
1574
- </div>
1575
- </div>
1576
- ) : (
1577
- <div className="workflow-editor-overview">
1578
- <div className="workflow-editor-overview-filterbar">
1579
- <div className="workflow-editor-overview-filterbar__left">
1580
- <div className="workflow-editor-overview-filter">
1581
- <label>Date From</label>
1582
- <SolidDatePicker
1583
- selected={overviewStartDate}
1584
- onChange={(date: Date | null) => setOverviewStartDate(date)}
1585
- placeholderText="Start date"
1586
- />
1587
- </div>
1588
- <div className="workflow-editor-overview-filter">
1589
- <label>Date To</label>
1590
- <SolidDatePicker
1591
- selected={overviewEndDate}
1592
- onChange={(date: Date | null) => setOverviewEndDate(date)}
1593
- placeholderText="End date"
1594
- />
1595
- </div>
1596
- <SolidButton size="small" variant="outline" onClick={loadWorkflowExecutions}>
1597
- Apply
1598
- </SolidButton>
1599
- {(overviewStartDate || overviewEndDate) && (
1600
- <SolidButton
1601
- size="small"
1602
- variant="ghost"
1603
- onClick={() => {
1604
- setOverviewStartDate(null);
1605
- setOverviewEndDate(null);
1606
- }}
1607
- >
1608
- Clear
1609
- </SolidButton>
1610
- )}
1611
- </div>
1612
- <div className="workflow-editor-overview-filterbar__right">
1613
- <SolidTag>{overviewDateFilterLabel}</SolidTag>
1614
- <SolidButton
1615
- size="small"
1616
- variant="outline"
1617
- leftIcon={<RefreshCw size={14} />}
1618
- loading={workflowExecutionsQuery.isFetching}
1619
- onClick={loadWorkflowExecutions}
1620
- >
1621
- Refresh
1622
- </SolidButton>
1623
- </div>
1624
- </div>
1625
-
1626
- <div className="workflow-editor-overview-stats">
1627
- <div className="workflow-editor-overview-stat">
1628
- <span className="workflow-editor-overview-stat-label">Success Ratio</span>
1629
- <strong className="workflow-editor-overview-stat-value">
1630
- {executionOverview.successRatio}%
1631
- </strong>
1632
- <span className="workflow-editor-overview-stat-meta">
1633
- {executionOverview.success} successful runs
1634
- </span>
1635
- </div>
1636
- <div className="workflow-editor-overview-stat">
1637
- <span className="workflow-editor-overview-stat-label">Failed Ratio</span>
1638
- <strong className="workflow-editor-overview-stat-value">
1639
- {executionOverview.failedRatio}%
1640
- </strong>
1641
- <span className="workflow-editor-overview-stat-meta">
1642
- {executionOverview.failed} failed runs
1643
- </span>
1644
- </div>
1645
- <div className="workflow-editor-overview-stat">
1646
- <span className="workflow-editor-overview-stat-label">In Progress</span>
1647
- <strong className="workflow-editor-overview-stat-value">
1648
- {executionOverview.inProgress}
1649
- </strong>
1650
- <span className="workflow-editor-overview-stat-meta">
1651
- Currently running executions
1652
- </span>
1653
- </div>
1654
- <div className="workflow-editor-overview-stat">
1655
- <span className="workflow-editor-overview-stat-label">Pending</span>
1656
- <strong className="workflow-editor-overview-stat-value">
1657
- {executionOverview.pending}
1658
- </strong>
1659
- <span className="workflow-editor-overview-stat-meta">
1660
- Created or queued executions
1661
- </span>
1662
- </div>
1663
- </div>
1664
-
1665
- <div className="workflow-editor-overview-grid">
1666
- <SolidPanel header="Workflow Summary">
1667
- <div className="workflow-editor-overview-section">
1668
- <div className="workflow-editor-overview-kv">
1669
- <span>Workflow</span>
1670
- <strong>{workflowDisplayName || record?.displayName || workflowKey}</strong>
1671
- </div>
1672
- <div className="workflow-editor-overview-kv">
1673
- <span>Total Executions</span>
1674
- <strong>{workflowExecutionPresenceQuery.data?.meta?.totalRecords ?? 0}</strong>
1675
- </div>
1676
- <div className="workflow-editor-overview-kv">
1677
- <span>Executions In Range</span>
1678
- <strong>{workflowExecutionsQuery.data?.meta?.totalRecords ?? 0}</strong>
1679
- </div>
1680
- <div className="workflow-editor-overview-kv">
1681
- <span>Average Duration</span>
1682
- <strong>{formatDurationMs(executionOverview.averageDurationMs)}</strong>
1683
- </div>
1684
- <div className="workflow-editor-overview-description">
1685
- {workflowDescription ||
1686
- record?.description ||
1687
- definitionDraft.description ||
1688
- "No workflow description has been added yet."}
1689
- </div>
1690
- </div>
1691
- </SolidPanel>
1692
-
1693
- <SolidPanel header="Latest Execution">
1694
- {executionOverview.latestExecution ? (
1695
- <div className="workflow-editor-overview-section">
1696
- <div className="workflow-editor-overview-kv">
1697
- <span>Status</span>
1698
- <strong>{executionOverview.latestExecution.status ?? "Unknown"}</strong>
1699
- </div>
1700
- <div className="workflow-editor-overview-kv">
1701
- <span>Started</span>
1702
- <strong>
1703
- {formatExecutionDate(executionOverview.latestExecution.startedAt)}
1704
- </strong>
1705
- </div>
1706
- <div className="workflow-editor-overview-kv">
1707
- <span>Finished</span>
1708
- <strong>
1709
- {formatExecutionDate(executionOverview.latestExecution.finishedAt)}
1710
- </strong>
1711
- </div>
1712
- <div className="workflow-editor-overview-kv">
1713
- <span>Trigger Type</span>
1714
- <strong>{executionOverview.latestExecution.triggerType ?? "manual"}</strong>
1715
- </div>
1716
- </div>
1717
- ) : (
1718
- <div className="workflow-editor-empty-state workflow-editor-empty-state--compact">
1719
- No executions match the current date filter.
1720
- </div>
1721
- )}
1722
- </SolidPanel>
1723
-
1724
- <SolidPanel header="Recent Executions">
1725
- {workflowExecutionsQuery.isFetching && !executionRecords.length ? (
1726
- <div className="workflow-editor-loading">
1727
- <SolidSpinner />
1728
- </div>
1729
- ) : executionRecords.length ? (
1730
- <div className="workflow-editor-overview-list">
1731
- {executionRecords.slice(0, 6).map((execution, index) => (
1732
- <div key={execution.id} className="workflow-editor-overview-list-item">
1733
- <div className="workflow-editor-overview-list-index">{index + 1}</div>
1734
- <div className="workflow-editor-overview-list-copy">
1735
- <strong>{execution.status ?? "Unknown"}</strong>
1736
- <span>{formatExecutionDate(execution.startedAt || execution.createdAt)}</span>
1737
- </div>
1738
- <SolidTag>{formatDurationMs(execution.durationMs)}</SolidTag>
1739
- </div>
1740
- ))}
1741
- </div>
1742
- ) : (
1743
- <div className="workflow-editor-empty-state workflow-editor-empty-state--compact">
1744
- No executions match the current date filter.
1745
- </div>
1746
- )}
1747
- </SolidPanel>
1748
-
1749
- <SolidPanel header="Actions">
1750
- <div className="workflow-editor-overview-actions">
1751
- <SolidButton
1752
- leftIcon={<Play size={16} />}
1753
- loading={isExecuting}
1754
- onClick={() => void handleExecute()}
1755
- >
1756
- Execute Again
1757
- </SolidButton>
1758
- <SolidButton variant="outline" onClick={() => setDetailTab("edit")}>
1759
- Open Builder
1760
- </SolidButton>
1761
- <SolidButton
1762
- variant="outline"
1763
- leftIcon={<Settings2 size={16} />}
1764
- onClick={() => setWorkflowSettingsOpen(true)}
1765
- >
1766
- Workflow Settings
1767
- </SolidButton>
1768
- </div>
1769
- </SolidPanel>
1770
- </div>
1771
- </div>
1772
- );
1773
-
1774
- const hasTopologyGraph =
1775
- definitionDraft.nodes.length || (definitionDraft.triggers?.length ?? 0) > 0;
1776
-
1777
- const topologyCanvasView = hasTopologyGraph ? (
1778
- <div className="workflow-editor-canvas-shell workflow-editor-canvas-shell--readonly">
1779
- <WorkflowFlowCanvas
1780
- definition={definitionDraft}
1781
- nodeTypes={nodeTypes}
1782
- selectedNodeId={selectedNodeId}
1783
- selectedTriggerId={selectedTriggerId}
1784
- onSelectNode={(nodeId) => {
1785
- setSelectedNodeId(nodeId);
1786
- setSelectedTriggerId("");
1787
- const node = findNodeById(definitionDraft.nodes, nodeId);
1788
- if (node?.type) {
1789
- setDocsNodeTypeKey(node.type);
1790
- }
1791
- }}
1792
- onSelectTrigger={(triggerId) => {
1793
- setSelectedTriggerId(triggerId);
1794
- setSelectedNodeId("");
1795
- setDocsNodeTypeKey("");
1796
- }}
1797
- onEditNode={() => {}}
1798
- onDeleteNode={() => {}}
1799
- onViewDocs={(nodeId) => {
1800
- const node = findNodeById(definitionDraft.nodes, nodeId);
1801
- if (node?.type) {
1802
- setSelectedNodeId(nodeId);
1803
- setSelectedTriggerId("");
1804
- setDocsNodeTypeKey(node.type);
1805
- setTopologyDocsNodeTypeKey(node.type);
1806
- setTopologyDocsModel(undefined);
1807
- setTopologyDocsOpen(true);
1808
- }
1809
- }}
1810
- onViewTriggerDocs={(triggerId) => {
1811
- const trigger = (definitionDraft.triggers ?? []).find(
1812
- (item) => String(item.id) === triggerId,
1813
- );
1814
- setSelectedTriggerId(triggerId);
1815
- setSelectedNodeId("");
1816
- setDocsNodeTypeKey("");
1817
- setTopologyDocsNodeTypeKey("");
1818
- setTopologyDocsModel(trigger ? buildTriggerDocsModel(trigger) : undefined);
1819
- setTopologyDocsOpen(true);
1820
- }}
1821
- onInsertNode={() => {}}
1822
- onAddBranch={() => {}}
1823
- readOnly
1824
- />
1825
- </div>
1826
- ) : (
1827
- <div className="workflow-editor-placeholder workflow-editor-placeholder--topology">
1828
- <div className="workflow-editor-placeholder__icon">
1829
- <Activity size={20} />
1830
- </div>
1831
- <div className="workflow-editor-placeholder__copy">
1832
- <h3>Topology</h3>
1833
- <p>Save or add workflow nodes to generate a read-only topology view.</p>
1834
- </div>
1835
- </div>
1836
- );
1837
-
1838
- const topologyYamlEditorView = (
1839
- <div className="workflow-editor-topology-code">
1840
- <div className="workflow-editor-topology-code__header">
1841
- <span>Definition YAML</span>
1842
- {codeError ? (
1843
- <SolidTag tone="danger">Invalid</SolidTag>
1844
- ) : (
1845
- <SolidTag tone="success">Synced</SolidTag>
1846
- )}
1847
- </div>
1848
- <SolidCodeEditor
1849
- language="yaml"
1850
- height="100%"
1851
- fontSize={12}
1852
- value={codeValue}
1853
- onChange={handleCodeChange}
1854
- />
1855
- {codeError ? <div className="workflow-editor-error">{codeError}</div> : null}
1856
- </div>
1857
- );
1858
-
1859
- const topologyContent = (
1860
- <div className="workflow-editor-topology-tab">
1861
- <div className="workflow-editor-topology-actionbar">
1862
- <div className="workflow-editor-topology-actionbar__spacer" />
1863
- <div className="workflow-editor-view-toggle" aria-label="Topology views">
1864
- <button
1865
- type="button"
1866
- className={`workflow-editor-view-toggle__button ${topologyViewOpen ? "is-active" : ""}`}
1867
- aria-label={topologyViewOpen ? "Hide topology view" : "Show topology view"}
1868
- title={topologyViewOpen ? "Hide topology view" : "Show topology view"}
1869
- onClick={() => setTopologyViewOpen((current) => !current)}
1870
- >
1871
- <Layers3 size={14} />
1872
- </button>
1873
- <button
1874
- type="button"
1875
- className={`workflow-editor-view-toggle__button ${topologyYamlViewOpen ? "is-active" : ""}`}
1876
- aria-label={topologyYamlViewOpen ? "Hide YAML editor" : "Show YAML editor"}
1877
- title={topologyYamlViewOpen ? "Hide YAML editor" : "Show YAML editor"}
1878
- onClick={() => setTopologyYamlViewOpen((current) => !current)}
1879
- >
1880
- <Braces size={14} />
1881
- </button>
1882
- </div>
1883
- </div>
1884
-
1885
- {topologyViewOpen && topologyYamlViewOpen ? (
1886
- <div
1887
- ref={topologySplitRef}
1888
- className="workflow-editor-topology-split"
1889
- style={{
1890
- gridTemplateColumns: `${topologySplitPercent}% 0.45rem minmax(0, 1fr)`,
1891
- }}
1892
- >
1893
- <div className="workflow-editor-topology-pane">{topologyCanvasView}</div>
1894
- <div
1895
- className="workflow-editor-topology-resizer"
1896
- role="separator"
1897
- aria-orientation="vertical"
1898
- aria-label="Resize topology and YAML views"
1899
- onMouseDown={startTopologySplitResize}
1900
- />
1901
- <div className="workflow-editor-topology-pane">{topologyYamlEditorView}</div>
1902
- </div>
1903
- ) : topologyViewOpen ? (
1904
- <div className="workflow-editor-topology-single">{topologyCanvasView}</div>
1905
- ) : topologyYamlViewOpen ? (
1906
- <div className="workflow-editor-topology-single">{topologyYamlEditorView}</div>
1907
- ) : (
1908
- <div className="workflow-editor-placeholder">
1909
- <div className="workflow-editor-placeholder__icon">
1910
- <Layers3 size={20} />
1911
- </div>
1912
- <div className="workflow-editor-placeholder__copy">
1913
- <h3>No topology view selected</h3>
1914
- <p>Use the view toggles above to show the topology canvas or YAML editor.</p>
1915
- </div>
1916
- </div>
1917
- )}
1918
- </div>
1919
- );
1920
-
1921
- const detailTabs = [
1922
- { value: "overview", label: "Overview", content: overviewContent },
1923
- {
1924
- value: "topology",
1925
- label: "Topology",
1926
- content: topologyContent,
1927
- },
1928
- {
1929
- value: "executions",
1930
- label: "Executions",
1931
- content: renderPlaceholderTab(
1932
- "Executions",
1933
- "Execution history and drill-downs will land here in the next pass.",
1934
- ),
1935
- },
1936
- { value: "edit", label: "Edit", content: null },
1937
- {
1938
- value: "revisions",
1939
- label: "Revisions",
1940
- content: renderPlaceholderTab(
1941
- "Revisions",
1942
- "Revision history is not wired yet, but the tab shell is ready.",
1943
- ),
1944
- },
1945
- {
1946
- value: "triggers",
1947
- label: "Triggers",
1948
- content: renderPlaceholderTab(
1949
- "Triggers",
1950
- "Trigger management will be added here after the overview pass is settled.",
1951
- ),
1952
- },
1953
- {
1954
- value: "logs",
1955
- label: "Logs",
1956
- content: renderPlaceholderTab(
1957
- "Logs",
1958
- "Workflow-level log browsing will be added in a later pass.",
1959
- ),
1960
- },
1961
- {
1962
- value: "metrics",
1963
- label: "Metrics",
1964
- content: renderPlaceholderTab(
1965
- "Metrics",
1966
- "Metrics will appear here once the backing persistence is introduced.",
1967
- ),
1968
- },
1969
- ] as const;
1970
-
1971
- if (isWorkflowDefinitionLoading || isNodeTypesLoading) {
1972
- return (
1973
- <div className="workflow-editor-page workflow-editor-page--loading">
1974
- <SolidSpinner />
1975
- </div>
1976
- );
1977
- }
1978
-
1979
- if (isNodeTypesError) {
1980
- return (
1981
- <div className="workflow-editor-page">
1982
- <div className="workflow-editor-empty-state">
1983
- Failed to load workflow node types.
1984
- </div>
1985
- </div>
1986
- );
1987
- }
1988
-
1989
- return (
1990
- <div className="workflow-editor-page">
1991
- <div className="workflow-editor-header">
1992
- <div className="workflow-editor-header-main">
1993
- <SolidButton
1994
- size="small"
1995
- variant="ghost"
1996
- leftIcon={<ArrowLeft size={16} />}
1997
- onClick={() =>
1998
- navigate(`/admin/core/${moduleName}/workflow-definition/list`)
1999
- }
2000
- >
2001
- Back
2002
- </SolidButton>
2003
- </div>
2004
- <div className="workflow-editor-header-actions">
2005
- <SolidButton
2006
- size="small"
2007
- variant="outline"
2008
- leftIcon={<Settings2 size={16} />}
2009
- onClick={() => setWorkflowSettingsOpen(true)}
2010
- >
2011
- Workflow
2012
- </SolidButton>
2013
- <SolidButton
2014
- size="small"
2015
- variant="outline"
2016
- leftIcon={<BookOpen size={16} />}
2017
- onClick={() => {
2018
- setDetailTab("edit");
2019
- setDocsOpen(true);
2020
- setActivePanel("docs");
2021
- }}
2022
- >
2023
- Docs
2024
- </SolidButton>
2025
- <SolidButton
2026
- size="small"
2027
- variant="outline"
2028
- leftIcon={<ShieldCheck size={16} />}
2029
- loading={isServerValidating}
2030
- onClick={() => void validateCurrentDefinition({ showSuccessToast: true })}
2031
- >
2032
- Validate
2033
- </SolidButton>
2034
- <SolidButton
2035
- size="small"
2036
- variant="outline"
2037
- leftIcon={<Play size={16} />}
2038
- loading={isExecuting}
2039
- onClick={() => void handleExecute()}
2040
- >
2041
- Run
2042
- </SolidButton>
2043
- <SolidButton
2044
- size="small"
2045
- leftIcon={<Save size={16} />}
2046
- loading={isSaving || isCreating}
2047
- onClick={handleSave}
2048
- >
2049
- Save
2050
- </SolidButton>
2051
- </div>
2052
- </div>
2053
-
2054
- <div className="workflow-editor-detail-tabs">
2055
- <SolidTabGroup
2056
- tabs={detailTabs.map((tab) => ({
2057
- value: tab.value,
2058
- label: tab.label,
2059
- content: tab.value === "edit" ? null : tab.content,
2060
- }))}
2061
- value={detailTab}
2062
- onValueChange={(value) => setDetailTab(value as WorkflowDetailTab)}
2063
- listClassName="workflow-editor-detail-tabs__list"
2064
- panelClassName="workflow-editor-detail-tabs__panel"
2065
- />
2066
- </div>
2067
-
2068
- {detailTab === "edit" ? (
2069
- <>
2070
- <div className="workflow-editor-focus-switcher">
2071
- {(["flow", "code", "docs"] as const).map((panel) => (
2072
- <button
2073
- key={panel}
2074
- type="button"
2075
- className={`workflow-editor-focus-pill ${activePanel === panel ? "is-active" : ""}`}
2076
- onClick={() => setActivePanel(panel)}
2077
- >
2078
- {panel === "flow" ? "Flow" : panel === "code" ? "Code" : "Docs"}
2079
- </button>
2080
- ))}
2081
- </div>
2082
-
2083
- <div
2084
- className={`workflow-editor-shell workflow-editor-shell--two-panel ${codePaneOpen ? "workflow-editor-shell--code-open" : "workflow-editor-shell--code-collapsed"}`}
2085
- >
2086
- <section
2087
- className={`workflow-editor-surface workflow-editor-surface--code ${activePanel === "code" ? "is-active" : ""}`}
2088
- >
2089
- <div className="workflow-editor-surface-header">
2090
- <div>
2091
- <div className="workflow-editor-surface-eyebrow">Code</div>
2092
- <h2 className="workflow-editor-surface-title">Definition YAML</h2>
2093
- </div>
2094
- {codeError ? (
2095
- <SolidTag tone="danger">Invalid YAML</SolidTag>
2096
- ) : (
2097
- <SolidTag tone="success">Synced</SolidTag>
2098
- )}
2099
- </div>
2100
- <div className="workflow-editor-surface-body">
2101
- <SolidPanel header="Workflow Identity">
2102
- <div className="workflow-editor-form-grid">
2103
- <div className="workflow-editor-field">
2104
- <label>Key</label>
2105
- <SolidInput
2106
- value={workflowKey}
2107
- onChange={(event) => setWorkflowKey(event.target.value)}
2108
- />
2109
- </div>
2110
- <div className="workflow-editor-field">
2111
- <label>Display Name</label>
2112
- <SolidInput
2113
- value={workflowDisplayName}
2114
- onChange={(event) => setWorkflowDisplayName(event.target.value)}
2115
- />
2116
- </div>
2117
- </div>
2118
- <div className="workflow-editor-field">
2119
- <label>Description</label>
2120
- <SolidTextarea
2121
- value={workflowDescription}
2122
- onChange={(event) => setWorkflowDescription(event.target.value)}
2123
- />
2124
- </div>
2125
- </SolidPanel>
2126
-
2127
- <SolidPanel header="Definition YAML">
2128
- <SolidCodeEditor
2129
- language="yaml"
2130
- height="calc(100vh - 390px)"
2131
- value={codeValue}
2132
- onChange={handleCodeChange}
2133
- />
2134
- {codeError ? (
2135
- <div className="workflow-editor-error">{codeError}</div>
2136
- ) : null}
2137
- </SolidPanel>
2138
- </div>
2139
- </section>
2140
-
2141
- <section
2142
- className={`workflow-editor-surface workflow-editor-surface--flow ${activePanel !== "code" ? "is-active" : ""}`}
2143
- >
2144
- <div className="workflow-editor-surface-header">
2145
- <div className="workflow-editor-flow-header-main">
2146
- <div className="workflow-editor-surface-eyebrow">Flow</div>
2147
- <div className="workflow-editor-flow-header-title-row">
2148
- <h2 className="workflow-editor-surface-title">Topology Builder</h2>
2149
- <SolidTag tone={validationTag.tone}>{validationTag.label}</SolidTag>
2150
- <SolidTag>{workflowStats.nodeCount} nodes</SolidTag>
2151
- {workflowStats.triggerCount ? (
2152
- <SolidTag>{workflowStats.triggerCount} triggers</SolidTag>
2153
- ) : null}
2154
- {paletteNodeType?.label ? (
2155
- <SolidTag>{paletteNodeType.label}</SolidTag>
2156
- ) : null}
2157
- </div>
2158
- <div className="workflow-editor-flow-header-selection">
2159
- {selectedNode && selectedNodeType ? (
2160
- <>
2161
- <strong>{selectedNode.name ?? selectedNode.id}</strong>
2162
- <span className="workflow-editor-node-card-subtitle">
2163
- {selectedNodeType.label ?? selectedNode.type}
2164
- </span>
2165
- </>
2166
- ) : selectedTrigger ? (
2167
- <>
2168
- <strong>
2169
- {selectedTrigger.label ??
2170
- selectedTrigger.name ??
2171
- selectedTrigger.id}
2172
- </strong>
2173
- <span className="workflow-editor-node-card-subtitle">
2174
- {selectedTrigger.type ?? "Trigger"}
2175
- </span>
2176
- </>
2177
- ) : (
2178
- <span className="workflow-editor-flow-toolbar__empty">
2179
- Select a node or trigger to inspect it.
2180
- </span>
2181
- )}
2182
- </div>
2183
- </div>
2184
- <div className="workflow-editor-surface-header-actions">
2185
- <SolidButton
2186
- size="small"
2187
- variant="outline"
2188
- leftIcon={
2189
- codePaneOpen ? (
2190
- <ChevronLeft size={14} />
2191
- ) : (
2192
- <ChevronRight size={14} />
2193
- )
2194
- }
2195
- onClick={() => setCodePaneOpen((current) => !current)}
2196
- >
2197
- {codePaneOpen ? "Hide code" : "Show code"}
2198
- </SolidButton>
2199
- <SolidButton
2200
- size="small"
2201
- variant="outline"
2202
- leftIcon={<Braces size={14} />}
2203
- onClick={() => {
2204
- setCodePaneOpen(true);
2205
- setActivePanel("code");
2206
- }}
2207
- >
2208
- Code
2209
- </SolidButton>
2210
- <SolidButton
2211
- size="small"
2212
- variant="outline"
2213
- leftIcon={<Layers3 size={14} />}
2214
- onClick={() => setToolsOpen((current) => !current)}
2215
- >
2216
- {toolsOpen ? "Hide library" : "Library"}
2217
- </SolidButton>
2218
- <SolidButton
2219
- size="small"
2220
- variant="outline"
2221
- leftIcon={<BookOpen size={14} />}
2222
- onClick={() => {
2223
- setDocsOpen(true);
2224
- setActivePanel("docs");
2225
- }}
2226
- >
2227
- {docsNodeType || docsModel ? "View docs" : "Open docs"}
2228
- </SolidButton>
2229
- <SolidButton
2230
- size="small"
2231
- variant="outline"
2232
- leftIcon={<Settings2 size={14} />}
2233
- onClick={() => setWorkflowSettingsOpen(true)}
2234
- >
2235
- Workflow
2236
- </SolidButton>
2237
- </div>
2238
- </div>
2239
- <div className="workflow-editor-surface-body workflow-editor-surface-body--flow">
2240
- <div className="workflow-editor-flow-workspace">
2241
- {toolsOpen ? (
2242
- <aside className="workflow-editor-tools-drawer">
2243
- <div className="workflow-editor-tools-drawer__header">
2244
- <div>
2245
- <div className="workflow-editor-surface-eyebrow">
2246
- Builder Tools
2247
- </div>
2248
- <h3 className="workflow-editor-surface-title">
2249
- Node Library & Inspector
2250
- </h3>
2251
- </div>
2252
- <SolidButton
2253
- size="small"
2254
- variant="ghost"
2255
- onClick={() => setToolsOpen(false)}
2256
- >
2257
- <X size={16} />
2258
- </SolidButton>
2259
- </div>
2260
-
2261
- <div className="workflow-editor-tools-drawer__body">
2262
- <SolidPanel header="Node Types">
2263
- <WorkflowNodePalette
2264
- nodeTypes={nodeTypes}
2265
- value={paletteNodeType?.type}
2266
- onSelect={(nodeType) => {
2267
- setPaletteNodeTypeKey(nodeType.type);
2268
- setDocsNodeTypeKey(nodeType.type);
2269
- }}
2270
- />
2271
- </SolidPanel>
2272
-
2273
- <SolidPanel header="Selection">
2274
- {selectedNode && selectedNodeType ? (
2275
- <div className="workflow-editor-selected-node-summary">
2276
- <div>
2277
- <strong>{selectedNode.name ?? selectedNode.id}</strong>
2278
- <div className="workflow-editor-node-card-subtitle">
2279
- {selectedNodeType.label ?? selectedNode.type}
2280
- </div>
2281
- </div>
2282
- <div className="workflow-editor-selected-node-actions">
2283
- <SolidButton
2284
- size="small"
2285
- variant="outline"
2286
- onClick={() => {
2287
- setDocsNodeTypeKey(selectedNode.type);
2288
- setDocsOpen(true);
2289
- setActivePanel("docs");
2290
- }}
2291
- >
2292
- Docs
2293
- </SolidButton>
2294
- <SolidButton
2295
- size="small"
2296
- onClick={() => setEditorOpen(true)}
2297
- >
2298
- Edit
2299
- </SolidButton>
2300
- </div>
2301
- </div>
2302
- ) : selectedTrigger ? (
2303
- <div className="workflow-editor-selected-node-summary">
2304
- <div>
2305
- <strong>
2306
- {selectedTrigger.label ??
2307
- selectedTrigger.name ??
2308
- selectedTrigger.id}
2309
- </strong>
2310
- <div className="workflow-editor-node-card-subtitle">
2311
- {selectedTrigger.type ?? "Trigger"}
2312
- </div>
2313
- </div>
2314
- <div className="workflow-editor-selected-node-actions">
2315
- <SolidButton
2316
- size="small"
2317
- variant="outline"
2318
- onClick={() => {
2319
- setDocsOpen(true);
2320
- setActivePanel("docs");
2321
- }}
2322
- >
2323
- Docs
2324
- </SolidButton>
2325
- <SolidButton
2326
- size="small"
2327
- onClick={() => setWorkflowSettingsOpen(true)}
2328
- >
2329
- Workflow
2330
- </SolidButton>
2331
- </div>
2332
- </div>
2333
- ) : (
2334
- <div className="workflow-editor-empty-state workflow-editor-empty-state--compact">
2335
- Select a node or trigger on the canvas to inspect it.
2336
- </div>
2337
- )}
2338
- </SolidPanel>
2339
-
2340
- <SolidPanel header="Validation">
2341
- <div className="workflow-editor-validation-summary">
2342
- <div
2343
- className={`workflow-editor-validation-state workflow-editor-validation-state--${validationState.status}`}
2344
- >
2345
- {validationState.message ??
2346
- "Validation has not been run yet."}
2347
- </div>
2348
- {validationState.errors.length ? (
2349
- <ul className="workflow-editor-validation-list">
2350
- {validationState.errors.map((error) => (
2351
- <li key={error}>{error}</li>
2352
- ))}
2353
- </ul>
2354
- ) : null}
2355
- </div>
2356
- </SolidPanel>
2357
- </div>
2358
- </aside>
2359
- ) : null}
2360
-
2361
- <div className="workflow-editor-flow-main">
2362
- <div className="workflow-editor-canvas-shell">
2363
- <WorkflowFlowCanvas
2364
- definition={definitionDraft}
2365
- nodeTypes={nodeTypes}
2366
- selectedNodeId={selectedNodeId}
2367
- selectedTriggerId={selectedTriggerId}
2368
- activePaletteNodeType={paletteNodeType}
2369
- onSelectNode={(nodeId) => {
2370
- setSelectedNodeId(nodeId);
2371
- setSelectedTriggerId("");
2372
- const node = findNodeById(definitionDraft.nodes, nodeId);
2373
- if (node?.type) {
2374
- setDocsNodeTypeKey(node.type);
2375
- }
2376
- }}
2377
- onSelectTrigger={(triggerId) => {
2378
- setSelectedTriggerId(triggerId);
2379
- setSelectedNodeId("");
2380
- setDocsNodeTypeKey("");
2381
- }}
2382
- onEditNode={(nodeId) => {
2383
- setSelectedNodeId(nodeId);
2384
- setSelectedTriggerId("");
2385
- const node = findNodeById(definitionDraft.nodes, nodeId);
2386
- if (node?.type) {
2387
- setDocsNodeTypeKey(node.type);
2388
- }
2389
- setEditorOpen(true);
2390
- }}
2391
- onDeleteNode={handleRemoveNode}
2392
- onViewDocs={(nodeId) => {
2393
- const node = findNodeById(definitionDraft.nodes, nodeId);
2394
- if (node?.type) {
2395
- setSelectedNodeId(nodeId);
2396
- setDocsNodeTypeKey(node.type);
2397
- setDocsOpen(true);
2398
- setActivePanel("docs");
2399
- }
2400
- }}
2401
- onViewTriggerDocs={(triggerId) => {
2402
- setSelectedTriggerId(triggerId);
2403
- setSelectedNodeId("");
2404
- setDocsNodeTypeKey("");
2405
- setDocsOpen(true);
2406
- setActivePanel("docs");
2407
- }}
2408
- onInsertNode={handleInsertNode}
2409
- onAddBranch={handleAddBranch}
2410
- />
2411
- </div>
2412
- </div>
2413
- </div>
2414
- </div>
2415
-
2416
- {docsOpen ? (
2417
- <aside
2418
- className={`workflow-editor-docs-drawer ${activePanel === "docs" ? "is-active" : ""}`}
2419
- >
2420
- <div className="workflow-editor-docs-drawer__header">
2421
- <div>
2422
- <div className="workflow-editor-surface-eyebrow">Docs</div>
2423
- <h3 className="workflow-editor-surface-title">
2424
- {docsNodeType?.label ?? docsModel?.title ?? "Documentation"}
2425
- </h3>
2426
- </div>
2427
- <SolidButton
2428
- size="small"
2429
- variant="ghost"
2430
- onClick={() => setDocsOpen(false)}
2431
- >
2432
- <X size={16} />
2433
- </SolidButton>
2434
- </div>
2435
- <div className="workflow-editor-docs-drawer__body">
2436
- {docsNodeType || docsModel ? (
2437
- <WorkflowNodeDocsPanel
2438
- nodeType={docsNodeType}
2439
- docsModel={docsModel}
2440
- />
2441
- ) : (
2442
- <div className="workflow-editor-empty-state">
2443
- Pick a node, trigger, or workflow surface to open its documentation.
2444
- </div>
2445
- )}
2446
- </div>
2447
- </aside>
2448
- ) : null}
2449
- </section>
2450
- </div>
2451
- </>
2452
- ) : null}
2453
-
2454
- {selectedNode && selectedNodeType ? (
2455
- <WorkflowNodeEditorDialog
2456
- open={editorOpen}
2457
- onOpenChange={setEditorOpen}
2458
- nodeType={selectedNodeType}
2459
- nodeValue={selectedNode}
2460
- onNodeSubmit={(nextValue) => {
2461
- handleUpdateSelectedNode(nextValue);
2462
- setEditorOpen(false);
2463
- }}
2464
- title={`${selectedNode.name ?? selectedNode.id} · ${selectedNodeType.label ?? selectedNodeType.type}`}
2465
- />
2466
- ) : null}
2467
-
2468
- <SolidDialog
2469
- open={topologyDocsOpen}
2470
- onOpenChange={(open) => {
2471
- setTopologyDocsOpen(open);
2472
- if (!open) {
2473
- setTopologyDocsNodeTypeKey("");
2474
- setTopologyDocsModel(undefined);
2475
- }
2476
- }}
2477
- header="Node Documentation"
2478
- className="workflow-editor-topology-docs-dialog"
2479
- style={{ width: "min(920px, 94vw)", maxWidth: "96vw" }}
2480
- >
2481
- <SolidDialogBody>
2482
- <div className="workflow-editor-topology-docs-dialog__body">
2483
- {topologyDocsNodeType || topologyDocsModel ? (
2484
- <WorkflowNodeDocsPanel
2485
- nodeType={topologyDocsNodeType}
2486
- docsModel={topologyDocsModel}
2487
- />
2488
- ) : (
2489
- <div className="workflow-editor-empty-state workflow-editor-empty-state--compact">
2490
- Documentation is not available for this topology item yet.
2491
- </div>
2492
- )}
2493
- </div>
2494
- </SolidDialogBody>
2495
- </SolidDialog>
2496
-
2497
- <SolidDialog
2498
- open={workflowSettingsOpen}
2499
- onOpenChange={setWorkflowSettingsOpen}
2500
- header="Workflow Settings"
2501
- className="solid-workflow-node-editor-dialog solid-workflow-node-editor-dialog--full"
2502
- style={{ width: "min(1200px, 94vw)", maxWidth: "96vw" }}
2503
- >
2504
- <SolidDialogBody>
2505
- <div className="workflow-editor-workflow-settings">
2506
- <SolidPanel header="Workflow Identity">
2507
- <div className="workflow-editor-form-grid">
2508
- <div className="workflow-editor-field">
2509
- <label>Key</label>
2510
- <SolidInput
2511
- value={workflowKey}
2512
- onChange={(event) => setWorkflowKey(event.target.value)}
2513
- />
2514
- </div>
2515
- <div className="workflow-editor-field">
2516
- <label>Display Name</label>
2517
- <SolidInput
2518
- value={workflowDisplayName}
2519
- onChange={(event) => setWorkflowDisplayName(event.target.value)}
2520
- />
2521
- </div>
2522
- </div>
2523
- <div className="workflow-editor-field">
2524
- <label>Description</label>
2525
- <SolidTextarea
2526
- value={workflowDescription}
2527
- onChange={(event) => setWorkflowDescription(event.target.value)}
2528
- />
2529
- </div>
2530
- </SolidPanel>
2531
-
2532
- <SolidPanel header="Inputs">
2533
- <SolidCodeEditor
2534
- language="yaml"
2535
- height="220px"
2536
- value={workflowInputsValue}
2537
- onChange={(value) => setWorkflowInputsValue(value ?? "{}")}
2538
- />
2539
- </SolidPanel>
2540
-
2541
- <SolidPanel header="Variables">
2542
- <SolidCodeEditor
2543
- language="yaml"
2544
- height="220px"
2545
- value={workflowVariablesValue}
2546
- onChange={(value) => setWorkflowVariablesValue(value ?? "{}")}
2547
- />
2548
- </SolidPanel>
2549
-
2550
- <SolidPanel header="Triggers">
2551
- <SolidCodeEditor
2552
- language="yaml"
2553
- height="260px"
2554
- value={workflowTriggersValue}
2555
- onChange={(value) => setWorkflowTriggersValue(value ?? "[]")}
2556
- />
2557
- </SolidPanel>
2558
- </div>
2559
- </SolidDialogBody>
2560
- <SolidDialogFooter>
2561
- <SolidButton
2562
- variant="secondary"
2563
- onClick={() => setWorkflowSettingsOpen(false)}
2564
- >
2565
- Cancel
2566
- </SolidButton>
2567
- <SolidButton onClick={handleSaveWorkflowSettings}>Apply</SolidButton>
2568
- </SolidDialogFooter>
2569
- </SolidDialog>
2570
- </div>
2571
- );
2572
- }