@acorex/modules 21.0.0-next.40 → 21.0.0-next.42

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 (234) hide show
  1. package/fesm2022/{acorex-modules-ai-management-acorex-modules-ai-management-Bqfx8OTv.mjs → acorex-modules-ai-management-acorex-modules-ai-management-D7_4LOGV.mjs} +3486 -1149
  2. package/fesm2022/acorex-modules-ai-management-acorex-modules-ai-management-D7_4LOGV.mjs.map +1 -0
  3. package/fesm2022/{acorex-modules-ai-management-agent-registry-tool-configurator-widget-edit.component-DyczMN-R.mjs → acorex-modules-ai-management-agent-registry-tool-configurator-widget-edit.component-C7TQMwX4.mjs} +4 -3
  4. package/fesm2022/acorex-modules-ai-management-agent-registry-tool-configurator-widget-edit.component-C7TQMwX4.mjs.map +1 -0
  5. package/fesm2022/{acorex-modules-ai-management-agent.entity-CpSXisAh.mjs → acorex-modules-ai-management-agent.entity-DwPIKib2.mjs} +20 -17
  6. package/fesm2022/acorex-modules-ai-management-agent.entity-DwPIKib2.mjs.map +1 -0
  7. package/fesm2022/{acorex-modules-ai-management-ai-delegated-agent-transcript-popup.component-CYk2rB36.mjs → acorex-modules-ai-management-ai-delegated-agent-transcript-popup.component-D2GJ5qD1.mjs} +28 -6
  8. package/fesm2022/acorex-modules-ai-management-ai-delegated-agent-transcript-popup.component-D2GJ5qD1.mjs.map +1 -0
  9. package/fesm2022/{acorex-modules-ai-management-assist-delegated-agent-configurator-widget-edit.component-BDcW8BRI.mjs → acorex-modules-ai-management-assist-delegated-agent-configurator-widget-edit.component-BozVAuLO.mjs} +6 -9
  10. package/fesm2022/acorex-modules-ai-management-assist-delegated-agent-configurator-widget-edit.component-BozVAuLO.mjs.map +1 -0
  11. package/fesm2022/{acorex-modules-ai-management-assist.entity-7uTePpME.mjs → acorex-modules-ai-management-assist.entity-CuToMDS_.mjs} +10 -11
  12. package/fesm2022/acorex-modules-ai-management-assist.entity-CuToMDS_.mjs.map +1 -0
  13. package/fesm2022/acorex-modules-ai-management-index-DaGJVOFw.mjs +2 -0
  14. package/fesm2022/{acorex-modules-ai-management-index-DUojDUau.mjs.map → acorex-modules-ai-management-index-DaGJVOFw.mjs.map} +1 -1
  15. package/fesm2022/{acorex-modules-ai-management-model.entity-C9J3trsK.mjs → acorex-modules-ai-management-model.entity-vUNlioDw.mjs} +20 -17
  16. package/fesm2022/acorex-modules-ai-management-model.entity-vUNlioDw.mjs.map +1 -0
  17. package/fesm2022/{acorex-modules-ai-management-open-ai-endpoint.entity-kHsxkjEd.mjs → acorex-modules-ai-management-open-ai-endpoint.entity-BpxRR5ir.mjs} +28 -9
  18. package/fesm2022/acorex-modules-ai-management-open-ai-endpoint.entity-BpxRR5ir.mjs.map +1 -0
  19. package/fesm2022/acorex-modules-ai-management.mjs +1 -1
  20. package/fesm2022/{acorex-modules-asset-management-acorex-modules-asset-management-BRap9yt6.mjs → acorex-modules-asset-management-acorex-modules-asset-management-DrIhRaZ6.mjs} +84 -99
  21. package/fesm2022/acorex-modules-asset-management-acorex-modules-asset-management-DrIhRaZ6.mjs.map +1 -0
  22. package/fesm2022/{acorex-modules-asset-management-asset-rental-history.entity-B_QZI3Cy.mjs → acorex-modules-asset-management-asset-rental-history.entity-95NBXoex.mjs} +2 -2
  23. package/fesm2022/{acorex-modules-asset-management-asset-rental-history.entity-B_QZI3Cy.mjs.map → acorex-modules-asset-management-asset-rental-history.entity-95NBXoex.mjs.map} +1 -1
  24. package/fesm2022/acorex-modules-asset-management-asset-state-history.entity-C-z103la.mjs +258 -0
  25. package/fesm2022/acorex-modules-asset-management-asset-state-history.entity-C-z103la.mjs.map +1 -0
  26. package/fesm2022/{acorex-modules-asset-management-asset-status.rules-BL0Osjqv.mjs → acorex-modules-asset-management-asset-status.rules-B7KwWQEe.mjs} +2 -2
  27. package/fesm2022/acorex-modules-asset-management-asset-status.rules-B7KwWQEe.mjs.map +1 -0
  28. package/fesm2022/{acorex-modules-asset-management-asset-system-assignment.entity-BRz8vItS.mjs → acorex-modules-asset-management-asset-system-assignment.entity-HqZtfJpe.mjs} +2 -2
  29. package/fesm2022/{acorex-modules-asset-management-asset-system-assignment.entity-BRz8vItS.mjs.map → acorex-modules-asset-management-asset-system-assignment.entity-HqZtfJpe.mjs.map} +1 -1
  30. package/fesm2022/{acorex-modules-asset-management-asset-system-type.entity-b_o5UnuE.mjs → acorex-modules-asset-management-asset-system-type.entity-fvrbyjXb.mjs} +2 -2
  31. package/fesm2022/{acorex-modules-asset-management-asset-system-type.entity-b_o5UnuE.mjs.map → acorex-modules-asset-management-asset-system-type.entity-fvrbyjXb.mjs.map} +1 -1
  32. package/fesm2022/{acorex-modules-asset-management-asset-system.entity-C6ak4u9z.mjs → acorex-modules-asset-management-asset-system.entity-DVAaXNWx.mjs} +13 -3
  33. package/fesm2022/acorex-modules-asset-management-asset-system.entity-DVAaXNWx.mjs.map +1 -0
  34. package/fesm2022/{acorex-modules-asset-management-asset-type-section-component.entity-BQjGo1s1.mjs → acorex-modules-asset-management-asset-type-section-component.entity-n-bxBcGz.mjs} +2 -2
  35. package/fesm2022/{acorex-modules-asset-management-asset-type-section-component.entity-BQjGo1s1.mjs.map → acorex-modules-asset-management-asset-type-section-component.entity-n-bxBcGz.mjs.map} +1 -1
  36. package/fesm2022/{acorex-modules-asset-management-asset-type-section.entity-C1DJZZFy.mjs → acorex-modules-asset-management-asset-type-section.entity-BF7N699p.mjs} +2 -2
  37. package/fesm2022/{acorex-modules-asset-management-asset-type-section.entity-C1DJZZFy.mjs.map → acorex-modules-asset-management-asset-type-section.entity-BF7N699p.mjs.map} +1 -1
  38. package/fesm2022/{acorex-modules-asset-management-asset-type.entity-CtOnArR9.mjs → acorex-modules-asset-management-asset-type.entity-Dt61Rs4F.mjs} +2 -2
  39. package/fesm2022/{acorex-modules-asset-management-asset-type.entity-CtOnArR9.mjs.map → acorex-modules-asset-management-asset-type.entity-Dt61Rs4F.mjs.map} +1 -1
  40. package/fesm2022/{acorex-modules-asset-management-asset.entity-BaET-kSd.mjs → acorex-modules-asset-management-asset.entity-BzlsaEwC.mjs} +35 -10
  41. package/fesm2022/acorex-modules-asset-management-asset.entity-BzlsaEwC.mjs.map +1 -0
  42. package/fesm2022/{acorex-modules-asset-management-assetLifecycleState.provider-DZ5r2zx7.mjs → acorex-modules-asset-management-assetLifecycle-state.provider-DZ5r2zx7.mjs} +1 -1
  43. package/fesm2022/acorex-modules-asset-management-assetLifecycle-state.provider-DZ5r2zx7.mjs.map +1 -0
  44. package/fesm2022/acorex-modules-asset-management.mjs +1 -1
  45. package/fesm2022/acorex-modules-common.mjs +33 -3
  46. package/fesm2022/acorex-modules-common.mjs.map +1 -1
  47. package/fesm2022/acorex-modules-conversation.mjs +270 -206
  48. package/fesm2022/acorex-modules-conversation.mjs.map +1 -1
  49. package/fesm2022/{acorex-modules-dashboard-management-acorex-modules-dashboard-management-yqfev--M.mjs → acorex-modules-dashboard-management-acorex-modules-dashboard-management-DLndkp6w.mjs} +23 -39
  50. package/fesm2022/acorex-modules-dashboard-management-acorex-modules-dashboard-management-DLndkp6w.mjs.map +1 -0
  51. package/fesm2022/{acorex-modules-dashboard-management-index-CYnWQ2od.mjs → acorex-modules-dashboard-management-index-c8QzHHtG.mjs} +2 -2
  52. package/fesm2022/{acorex-modules-dashboard-management-index-CYnWQ2od.mjs.map → acorex-modules-dashboard-management-index-c8QzHHtG.mjs.map} +1 -1
  53. package/fesm2022/acorex-modules-dashboard-management.mjs +1 -1
  54. package/fesm2022/acorex-modules-document-management.mjs +114 -22
  55. package/fesm2022/acorex-modules-document-management.mjs.map +1 -1
  56. package/fesm2022/{acorex-modules-human-capital-management-acorex-modules-human-capital-management-Ck9q-IWW.mjs → acorex-modules-human-capital-management-acorex-modules-human-capital-management-Bgsi3FHG.mjs} +21 -19
  57. package/fesm2022/acorex-modules-human-capital-management-acorex-modules-human-capital-management-Bgsi3FHG.mjs.map +1 -0
  58. package/fesm2022/{acorex-modules-human-capital-management-approve-leave-request.command-qYSPyG_q.mjs → acorex-modules-human-capital-management-approve-leave-request.command-CxpTmb-1.mjs} +2 -2
  59. package/fesm2022/{acorex-modules-human-capital-management-approve-leave-request.command-qYSPyG_q.mjs.map → acorex-modules-human-capital-management-approve-leave-request.command-CxpTmb-1.mjs.map} +1 -1
  60. package/fesm2022/{acorex-modules-human-capital-management-assign-position-assignment.command-Da3u1fo5.mjs → acorex-modules-human-capital-management-assign-position-assignment.command-jLGe49dJ.mjs} +2 -2
  61. package/fesm2022/{acorex-modules-human-capital-management-assign-position-assignment.command-Da3u1fo5.mjs.map → acorex-modules-human-capital-management-assign-position-assignment.command-jLGe49dJ.mjs.map} +1 -1
  62. package/fesm2022/{acorex-modules-human-capital-management-cancel-leave-request.command-DstI60jo.mjs → acorex-modules-human-capital-management-cancel-leave-request.command-ChNGu90e.mjs} +2 -2
  63. package/fesm2022/{acorex-modules-human-capital-management-cancel-leave-request.command-DstI60jo.mjs.map → acorex-modules-human-capital-management-cancel-leave-request.command-ChNGu90e.mjs.map} +1 -1
  64. package/fesm2022/{acorex-modules-human-capital-management-employee.entity-DjMQm3VC.mjs → acorex-modules-human-capital-management-employee.entity-4k7F7_ON.mjs} +18 -16
  65. package/fesm2022/acorex-modules-human-capital-management-employee.entity-4k7F7_ON.mjs.map +1 -0
  66. package/fesm2022/{acorex-modules-human-capital-management-employment-type.entity-v8WzEHiE.mjs → acorex-modules-human-capital-management-employment-type.entity-Jo2fB9R3.mjs} +2 -2
  67. package/fesm2022/{acorex-modules-human-capital-management-employment-type.entity-v8WzEHiE.mjs.map → acorex-modules-human-capital-management-employment-type.entity-Jo2fB9R3.mjs.map} +1 -1
  68. package/fesm2022/{acorex-modules-human-capital-management-leave-request.entity-B9Bf-Nnm.mjs → acorex-modules-human-capital-management-leave-request.entity-DhLUXnJu.mjs} +2 -2
  69. package/fesm2022/{acorex-modules-human-capital-management-leave-request.entity-B9Bf-Nnm.mjs.map → acorex-modules-human-capital-management-leave-request.entity-DhLUXnJu.mjs.map} +1 -1
  70. package/fesm2022/{acorex-modules-human-capital-management-leave-type.entity-Bpfd_hNb.mjs → acorex-modules-human-capital-management-leave-type.entity-C-lN2bb0.mjs} +2 -2
  71. package/fesm2022/{acorex-modules-human-capital-management-leave-type.entity-Bpfd_hNb.mjs.map → acorex-modules-human-capital-management-leave-type.entity-C-lN2bb0.mjs.map} +1 -1
  72. package/fesm2022/{acorex-modules-human-capital-management-position-assignment.entity-f0IDrLSn.mjs → acorex-modules-human-capital-management-position-assignment.entity-BD1jN4Mx.mjs} +2 -2
  73. package/fesm2022/{acorex-modules-human-capital-management-position-assignment.entity-f0IDrLSn.mjs.map → acorex-modules-human-capital-management-position-assignment.entity-BD1jN4Mx.mjs.map} +1 -1
  74. package/fesm2022/{acorex-modules-human-capital-management-reject-leave-request.command-DxNsroYI.mjs → acorex-modules-human-capital-management-reject-leave-request.command-D0G6UrqI.mjs} +2 -2
  75. package/fesm2022/{acorex-modules-human-capital-management-reject-leave-request.command-DxNsroYI.mjs.map → acorex-modules-human-capital-management-reject-leave-request.command-D0G6UrqI.mjs.map} +1 -1
  76. package/fesm2022/{acorex-modules-human-capital-management-revoke-position-assignment.command-C3J9pcfh.mjs → acorex-modules-human-capital-management-revoke-position-assignment.command-CYzqQXja.mjs} +2 -2
  77. package/fesm2022/{acorex-modules-human-capital-management-revoke-position-assignment.command-C3J9pcfh.mjs.map → acorex-modules-human-capital-management-revoke-position-assignment.command-CYzqQXja.mjs.map} +1 -1
  78. package/fesm2022/acorex-modules-human-capital-management.mjs +1 -1
  79. package/fesm2022/{acorex-modules-maintenance-management-acorex-modules-maintenance-management-CfHMiVos.mjs → acorex-modules-maintenance-management-acorex-modules-maintenance-management-B5wf4zMI.mjs} +400 -147
  80. package/fesm2022/acorex-modules-maintenance-management-acorex-modules-maintenance-management-B5wf4zMI.mjs.map +1 -0
  81. package/fesm2022/{acorex-modules-maintenance-management-failure-effect.entity-DKbARwJh.mjs → acorex-modules-maintenance-management-failure-effect.entity-Cv5KnboB.mjs} +2 -2
  82. package/fesm2022/{acorex-modules-maintenance-management-failure-effect.entity-DKbARwJh.mjs.map → acorex-modules-maintenance-management-failure-effect.entity-Cv5KnboB.mjs.map} +1 -1
  83. package/fesm2022/{acorex-modules-maintenance-management-failure-mode-asset-type.entity-Br0lvFfu.mjs → acorex-modules-maintenance-management-failure-mode-asset-type.entity-BBL3-hfv.mjs} +2 -2
  84. package/fesm2022/{acorex-modules-maintenance-management-failure-mode-asset-type.entity-Br0lvFfu.mjs.map → acorex-modules-maintenance-management-failure-mode-asset-type.entity-BBL3-hfv.mjs.map} +1 -1
  85. package/fesm2022/{acorex-modules-maintenance-management-failure-mode-mechanism.entity-Dydg4AJ7.mjs → acorex-modules-maintenance-management-failure-mode-mechanism.entity-nxOdHZxu.mjs} +2 -2
  86. package/fesm2022/{acorex-modules-maintenance-management-failure-mode-mechanism.entity-Dydg4AJ7.mjs.map → acorex-modules-maintenance-management-failure-mode-mechanism.entity-nxOdHZxu.mjs.map} +1 -1
  87. package/fesm2022/{acorex-modules-maintenance-management-failure-mode-solution.entity-DHiVJHFj.mjs → acorex-modules-maintenance-management-failure-mode-solution.entity-ApD80Scc.mjs} +2 -2
  88. package/fesm2022/{acorex-modules-maintenance-management-failure-mode-solution.entity-DHiVJHFj.mjs.map → acorex-modules-maintenance-management-failure-mode-solution.entity-ApD80Scc.mjs.map} +1 -1
  89. package/fesm2022/{acorex-modules-maintenance-management-failure-register-cause.entity-CZfm0U8u.mjs → acorex-modules-maintenance-management-failure-register-cause.entity-CibfwJLG.mjs} +2 -2
  90. package/fesm2022/{acorex-modules-maintenance-management-failure-register-cause.entity-CZfm0U8u.mjs.map → acorex-modules-maintenance-management-failure-register-cause.entity-CibfwJLG.mjs.map} +1 -1
  91. package/fesm2022/{acorex-modules-maintenance-management-failure-register-effect.entity-DbCAFveJ.mjs → acorex-modules-maintenance-management-failure-register-effect.entity-DpoqULBf.mjs} +2 -2
  92. package/fesm2022/{acorex-modules-maintenance-management-failure-register-effect.entity-DbCAFveJ.mjs.map → acorex-modules-maintenance-management-failure-register-effect.entity-DpoqULBf.mjs.map} +1 -1
  93. package/fesm2022/{acorex-modules-maintenance-management-failure-register-mechanism.entity-D83Yo6dT.mjs → acorex-modules-maintenance-management-failure-register-mechanism.entity-0-J2Hkmn.mjs} +2 -2
  94. package/fesm2022/{acorex-modules-maintenance-management-failure-register-mechanism.entity-D83Yo6dT.mjs.map → acorex-modules-maintenance-management-failure-register-mechanism.entity-0-J2Hkmn.mjs.map} +1 -1
  95. package/fesm2022/{acorex-modules-maintenance-management-failure-register.entity-zKGo9bOs.mjs → acorex-modules-maintenance-management-failure-register.entity-C4Az4Rr9.mjs} +23 -53
  96. package/fesm2022/acorex-modules-maintenance-management-failure-register.entity-C4Az4Rr9.mjs.map +1 -0
  97. package/fesm2022/{acorex-modules-maintenance-management-failure-severity.entity-Cnvdmt0N.mjs → acorex-modules-maintenance-management-failure-severity.entity-BZo6UUun.mjs} +2 -2
  98. package/fesm2022/{acorex-modules-maintenance-management-failure-severity.entity-Cnvdmt0N.mjs.map → acorex-modules-maintenance-management-failure-severity.entity-BZo6UUun.mjs.map} +1 -1
  99. package/fesm2022/{acorex-modules-maintenance-management-maintenance-template.entity-CzX0phT-.mjs → acorex-modules-maintenance-management-maintenance-template.entity-DxYY0hpG.mjs} +14 -11
  100. package/fesm2022/acorex-modules-maintenance-management-maintenance-template.entity-DxYY0hpG.mjs.map +1 -0
  101. package/fesm2022/acorex-modules-maintenance-management-work-order-list-command-DTKNtyBF.mjs +54 -0
  102. package/fesm2022/acorex-modules-maintenance-management-work-order-list-command-DTKNtyBF.mjs.map +1 -0
  103. package/fesm2022/acorex-modules-maintenance-management.mjs +1 -1
  104. package/fesm2022/{acorex-modules-organization-management-acorex-modules-organization-management-CnAHfj2t.mjs → acorex-modules-organization-management-acorex-modules-organization-management-Bu8fRj_5.mjs} +48 -22
  105. package/fesm2022/acorex-modules-organization-management-acorex-modules-organization-management-Bu8fRj_5.mjs.map +1 -0
  106. package/fesm2022/acorex-modules-organization-management-add-position-to-business-unit.command-Qej_boIY.mjs +109 -0
  107. package/fesm2022/acorex-modules-organization-management-add-position-to-business-unit.command-Qej_boIY.mjs.map +1 -0
  108. package/fesm2022/{acorex-modules-organization-management-business-unit.entity-Dpf7-aeM.mjs → acorex-modules-organization-management-business-unit.entity-BfQ_7JAq.mjs} +2 -2
  109. package/fesm2022/{acorex-modules-organization-management-business-unit.entity-Dpf7-aeM.mjs.map → acorex-modules-organization-management-business-unit.entity-BfQ_7JAq.mjs.map} +1 -1
  110. package/fesm2022/{acorex-modules-organization-management-chart.entity-CQX81AiE.mjs → acorex-modules-organization-management-chart.entity-CNQGGfHV.mjs} +2 -2
  111. package/fesm2022/{acorex-modules-organization-management-chart.entity-CQX81AiE.mjs.map → acorex-modules-organization-management-chart.entity-CNQGGfHV.mjs.map} +1 -1
  112. package/fesm2022/{acorex-modules-organization-management-company.entity-D-RWQ_8O.mjs → acorex-modules-organization-management-company.entity-D_nTKLzu.mjs} +2 -2
  113. package/fesm2022/{acorex-modules-organization-management-company.entity-D-RWQ_8O.mjs.map → acorex-modules-organization-management-company.entity-D_nTKLzu.mjs.map} +1 -1
  114. package/fesm2022/{acorex-modules-organization-management-entity.provider-BdaKwTZq.mjs → acorex-modules-organization-management-entity.provider-B4uYixLQ.mjs} +15 -15
  115. package/fesm2022/{acorex-modules-organization-management-entity.provider-BdaKwTZq.mjs.map → acorex-modules-organization-management-entity.provider-B4uYixLQ.mjs.map} +1 -1
  116. package/fesm2022/{acorex-modules-organization-management-feature-definition.provider-EzMuHJ2K.mjs → acorex-modules-organization-management-feature-definition.provider-COjc6knz.mjs} +2 -2
  117. package/fesm2022/{acorex-modules-organization-management-feature-definition.provider-EzMuHJ2K.mjs.map → acorex-modules-organization-management-feature-definition.provider-COjc6knz.mjs.map} +1 -1
  118. package/fesm2022/{acorex-modules-organization-management-job-definition-pages-component.provider-C8_Ab3Q7.mjs → acorex-modules-organization-management-job-definition-pages-component.provider-gDpII9TZ.mjs} +3 -3
  119. package/fesm2022/{acorex-modules-organization-management-job-definition-pages-component.provider-C8_Ab3Q7.mjs.map → acorex-modules-organization-management-job-definition-pages-component.provider-gDpII9TZ.mjs.map} +1 -1
  120. package/fesm2022/{acorex-modules-organization-management-job-definition-responsibilities-page.component-DHUlvoOO.mjs → acorex-modules-organization-management-job-definition-responsibilities-page.component-CjXV4wrM.mjs} +3 -3
  121. package/fesm2022/{acorex-modules-organization-management-job-definition-responsibilities-page.component-DHUlvoOO.mjs.map → acorex-modules-organization-management-job-definition-responsibilities-page.component-CjXV4wrM.mjs.map} +1 -1
  122. package/fesm2022/{acorex-modules-organization-management-job-definition-skills-page.component-BpVESnnH.mjs → acorex-modules-organization-management-job-definition-skills-page.component-2XBgMms-.mjs} +2 -2
  123. package/fesm2022/{acorex-modules-organization-management-job-definition-skills-page.component-BpVESnnH.mjs.map → acorex-modules-organization-management-job-definition-skills-page.component-2XBgMms-.mjs.map} +1 -1
  124. package/fesm2022/{acorex-modules-organization-management-job-definition.entity-H8VAbZ_r.mjs → acorex-modules-organization-management-job-definition.entity-f0JnkdjP.mjs} +2 -2
  125. package/fesm2022/{acorex-modules-organization-management-job-definition.entity-H8VAbZ_r.mjs.map → acorex-modules-organization-management-job-definition.entity-f0JnkdjP.mjs.map} +1 -1
  126. package/fesm2022/{acorex-modules-organization-management-job-level.datasource-Dxfq0cGw.mjs → acorex-modules-organization-management-job-level.datasource-ByHluGvc.mjs} +2 -2
  127. package/fesm2022/{acorex-modules-organization-management-job-level.datasource-Dxfq0cGw.mjs.map → acorex-modules-organization-management-job-level.datasource-ByHluGvc.mjs.map} +1 -1
  128. package/fesm2022/{acorex-modules-organization-management-job-level.entity-Bdja794J.mjs → acorex-modules-organization-management-job-level.entity-BJJJQxCp.mjs} +2 -2
  129. package/fesm2022/{acorex-modules-organization-management-job-level.entity-Bdja794J.mjs.map → acorex-modules-organization-management-job-level.entity-BJJJQxCp.mjs.map} +1 -1
  130. package/fesm2022/{acorex-modules-organization-management-menu.provider-DnvNM-pk.mjs → acorex-modules-organization-management-menu.provider-Dd_Z58sY.mjs} +2 -2
  131. package/fesm2022/{acorex-modules-organization-management-menu.provider-DnvNM-pk.mjs.map → acorex-modules-organization-management-menu.provider-Dd_Z58sY.mjs.map} +1 -1
  132. package/fesm2022/{acorex-modules-organization-management-org-chart.page-COkMtxFO.mjs → acorex-modules-organization-management-org-chart.page-fudrNddI.mjs} +2 -2
  133. package/fesm2022/{acorex-modules-organization-management-org-chart.page-COkMtxFO.mjs.map → acorex-modules-organization-management-org-chart.page-fudrNddI.mjs.map} +1 -1
  134. package/fesm2022/{acorex-modules-organization-management-permission-definition.provider-BDLIuqxU.mjs → acorex-modules-organization-management-permission-definition.provider-CoB_RGSa.mjs} +2 -2
  135. package/fesm2022/{acorex-modules-organization-management-permission-definition.provider-BDLIuqxU.mjs.map → acorex-modules-organization-management-permission-definition.provider-CoB_RGSa.mjs.map} +1 -1
  136. package/fesm2022/{acorex-modules-organization-management-position.entity-BpbzqtEY.mjs → acorex-modules-organization-management-position.entity-T1DY1fZn.mjs} +2 -2
  137. package/fesm2022/{acorex-modules-organization-management-position.entity-BpbzqtEY.mjs.map → acorex-modules-organization-management-position.entity-T1DY1fZn.mjs.map} +1 -1
  138. package/fesm2022/{acorex-modules-organization-management-responsibilities-matrix-widget-edit.component-CGkXAtH2.mjs → acorex-modules-organization-management-responsibilities-matrix-widget-edit.component-CIPzMi3d.mjs} +2 -2
  139. package/fesm2022/{acorex-modules-organization-management-responsibilities-matrix-widget-edit.component-CGkXAtH2.mjs.map → acorex-modules-organization-management-responsibilities-matrix-widget-edit.component-CIPzMi3d.mjs.map} +1 -1
  140. package/fesm2022/{acorex-modules-organization-management-responsibilities-matrix-widget-view.component-Dw-tX5XI.mjs → acorex-modules-organization-management-responsibilities-matrix-widget-view.component-DzdTNVP6.mjs} +2 -2
  141. package/fesm2022/{acorex-modules-organization-management-responsibilities-matrix-widget-view.component-Dw-tX5XI.mjs.map → acorex-modules-organization-management-responsibilities-matrix-widget-view.component-DzdTNVP6.mjs.map} +1 -1
  142. package/fesm2022/{acorex-modules-organization-management-responsibilities-matrix.component-D_ClGAIJ.mjs → acorex-modules-organization-management-responsibilities-matrix.component-C850Dz47.mjs} +2 -2
  143. package/fesm2022/{acorex-modules-organization-management-responsibilities-matrix.component-D_ClGAIJ.mjs.map → acorex-modules-organization-management-responsibilities-matrix.component-C850Dz47.mjs.map} +1 -1
  144. package/fesm2022/{acorex-modules-organization-management-responsibility-level.entity-CzkogsDv.mjs → acorex-modules-organization-management-responsibility-level.entity-CVxWva5x.mjs} +2 -2
  145. package/fesm2022/{acorex-modules-organization-management-responsibility-level.entity-CzkogsDv.mjs.map → acorex-modules-organization-management-responsibility-level.entity-CVxWva5x.mjs.map} +1 -1
  146. package/fesm2022/{acorex-modules-organization-management-responsibility.entity-DfKM6HV7.mjs → acorex-modules-organization-management-responsibility.entity-BmDZhqNl.mjs} +2 -2
  147. package/fesm2022/{acorex-modules-organization-management-responsibility.entity-DfKM6HV7.mjs.map → acorex-modules-organization-management-responsibility.entity-BmDZhqNl.mjs.map} +1 -1
  148. package/fesm2022/{acorex-modules-organization-management-settings.provider-DaeJkP0y.mjs → acorex-modules-organization-management-settings.provider-wwGKyBrV.mjs} +2 -2
  149. package/fesm2022/{acorex-modules-organization-management-settings.provider-DaeJkP0y.mjs.map → acorex-modules-organization-management-settings.provider-wwGKyBrV.mjs.map} +1 -1
  150. package/fesm2022/{acorex-modules-organization-management-team-business-unit.entity-Cm9qcAG7.mjs → acorex-modules-organization-management-team-business-unit.entity-BmXLb4RI.mjs} +2 -2
  151. package/fesm2022/{acorex-modules-organization-management-team-business-unit.entity-Cm9qcAG7.mjs.map → acorex-modules-organization-management-team-business-unit.entity-BmXLb4RI.mjs.map} +1 -1
  152. package/fesm2022/{acorex-modules-organization-management-team-member-role.entity-B3xgLE6N.mjs → acorex-modules-organization-management-team-member-role.entity-C4DGSm2r.mjs} +2 -2
  153. package/fesm2022/{acorex-modules-organization-management-team-member-role.entity-B3xgLE6N.mjs.map → acorex-modules-organization-management-team-member-role.entity-C4DGSm2r.mjs.map} +1 -1
  154. package/fesm2022/{acorex-modules-organization-management-team-member.entity-Dk9t9S1r.mjs → acorex-modules-organization-management-team-member.entity-CvVHEzIU.mjs} +2 -2
  155. package/fesm2022/{acorex-modules-organization-management-team-member.entity-Dk9t9S1r.mjs.map → acorex-modules-organization-management-team-member.entity-CvVHEzIU.mjs.map} +1 -1
  156. package/fesm2022/{acorex-modules-organization-management-team.entity-BbcFYP20.mjs → acorex-modules-organization-management-team.entity-urjULfNp.mjs} +6 -9
  157. package/fesm2022/acorex-modules-organization-management-team.entity-urjULfNp.mjs.map +1 -0
  158. package/fesm2022/acorex-modules-organization-management.mjs +1 -1
  159. package/fesm2022/{acorex-modules-platform-management-acorex-modules-platform-management-Dl-3IE-C.mjs → acorex-modules-platform-management-acorex-modules-platform-management-CZMqG3Eq.mjs} +10 -2
  160. package/fesm2022/{acorex-modules-platform-management-acorex-modules-platform-management-Dl-3IE-C.mjs.map → acorex-modules-platform-management-acorex-modules-platform-management-CZMqG3Eq.mjs.map} +1 -1
  161. package/fesm2022/acorex-modules-platform-management-list-registered-data-sources.query-DdDvT0uh.mjs +81 -0
  162. package/fesm2022/acorex-modules-platform-management-list-registered-data-sources.query-DdDvT0uh.mjs.map +1 -0
  163. package/fesm2022/{acorex-modules-platform-management-menu-list.component-Brwqsawl.mjs → acorex-modules-platform-management-menu-list.component-BRA7Q50z.mjs} +2 -2
  164. package/fesm2022/{acorex-modules-platform-management-menu-list.component-Brwqsawl.mjs.map → acorex-modules-platform-management-menu-list.component-BRA7Q50z.mjs.map} +1 -1
  165. package/fesm2022/acorex-modules-platform-management.mjs +1 -1
  166. package/fesm2022/{acorex-modules-product-catalog-product.entity-aVWXuhlQ.mjs → acorex-modules-product-catalog-product.entity-BbB7GAg7.mjs} +3 -2
  167. package/fesm2022/acorex-modules-product-catalog-product.entity-BbB7GAg7.mjs.map +1 -0
  168. package/fesm2022/acorex-modules-product-catalog.mjs +1 -1
  169. package/fesm2022/acorex-modules-security-management.mjs +231 -137
  170. package/fesm2022/acorex-modules-security-management.mjs.map +1 -1
  171. package/fesm2022/acorex-modules-supplier-management.mjs +1 -0
  172. package/fesm2022/acorex-modules-supplier-management.mjs.map +1 -1
  173. package/fesm2022/acorex-modules-task-management-acorex-modules-task-management-it-Lf0L_.mjs +6066 -0
  174. package/fesm2022/acorex-modules-task-management-acorex-modules-task-management-it-Lf0L_.mjs.map +1 -0
  175. package/fesm2022/{acorex-modules-task-management-task-board.page-DA2563QE.mjs → acorex-modules-task-management-task-board.page-DF4XWz_0.mjs} +260 -87
  176. package/fesm2022/acorex-modules-task-management-task-board.page-DF4XWz_0.mjs.map +1 -0
  177. package/fesm2022/acorex-modules-task-management.mjs +1 -5860
  178. package/fesm2022/acorex-modules-task-management.mjs.map +1 -1
  179. package/fesm2022/acorex-modules-tenant-management.mjs +6 -15
  180. package/fesm2022/acorex-modules-tenant-management.mjs.map +1 -1
  181. package/fesm2022/{acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-BYJpDQRs.mjs → acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-Dj6LkQeZ.mjs} +5 -5
  182. package/fesm2022/{acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-BYJpDQRs.mjs.map → acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-Dj6LkQeZ.mjs.map} +1 -1
  183. package/fesm2022/{acorex-modules-workflow-management-index-C9Qc07oK.mjs → acorex-modules-workflow-management-index-CHySddpP.mjs} +2 -64
  184. package/fesm2022/acorex-modules-workflow-management-index-CHySddpP.mjs.map +1 -0
  185. package/fesm2022/{acorex-modules-workflow-management-index-Bx2uYraH.mjs → acorex-modules-workflow-management-index-Eh5DDK-V.mjs} +3 -3
  186. package/fesm2022/{acorex-modules-workflow-management-index-Bx2uYraH.mjs.map → acorex-modules-workflow-management-index-Eh5DDK-V.mjs.map} +1 -1
  187. package/fesm2022/{acorex-modules-workflow-management-index-D8fjNgQJ.mjs → acorex-modules-workflow-management-index-V4OesZTq.mjs} +6 -6
  188. package/fesm2022/{acorex-modules-workflow-management-index-D8fjNgQJ.mjs.map → acorex-modules-workflow-management-index-V4OesZTq.mjs.map} +1 -1
  189. package/fesm2022/{acorex-modules-workflow-management-workflow-definition.entity-DqPVpcSv.mjs → acorex-modules-workflow-management-workflow-definition.entity-CjQQpjdB.mjs} +1 -16
  190. package/fesm2022/{acorex-modules-workflow-management-workflow-definition.entity-DqPVpcSv.mjs.map → acorex-modules-workflow-management-workflow-definition.entity-CjQQpjdB.mjs.map} +1 -1
  191. package/fesm2022/{acorex-modules-workflow-management-workflow-instance.entity-D-KnWlsU.mjs → acorex-modules-workflow-management-workflow-instance.entity-B_V3uMSI.mjs} +30 -20
  192. package/fesm2022/acorex-modules-workflow-management-workflow-instance.entity-B_V3uMSI.mjs.map +1 -0
  193. package/fesm2022/{acorex-modules-workflow-management-workflow-task-popover.component-NpUx0sB5.mjs → acorex-modules-workflow-management-workflow-task-popover.component-l37iXJIY.mjs} +19 -15
  194. package/fesm2022/acorex-modules-workflow-management-workflow-task-popover.component-l37iXJIY.mjs.map +1 -0
  195. package/fesm2022/acorex-modules-workflow-management.mjs +31 -2390
  196. package/fesm2022/acorex-modules-workflow-management.mjs.map +1 -1
  197. package/package.json +2 -2
  198. package/types/acorex-modules-ai-management.d.ts +544 -67
  199. package/types/acorex-modules-asset-management.d.ts +51 -14
  200. package/types/acorex-modules-common.d.ts +24 -3
  201. package/types/acorex-modules-dashboard-management.d.ts +23 -12
  202. package/types/acorex-modules-document-management.d.ts +18 -2
  203. package/types/acorex-modules-human-capital-management.d.ts +1 -1
  204. package/types/acorex-modules-maintenance-management.d.ts +4 -7
  205. package/types/acorex-modules-reservation-management.d.ts +6 -5
  206. package/types/acorex-modules-task-management.d.ts +34 -5
  207. package/types/acorex-modules-workflow-management.d.ts +16 -549
  208. package/fesm2022/acorex-modules-ai-management-acorex-modules-ai-management-Bqfx8OTv.mjs.map +0 -1
  209. package/fesm2022/acorex-modules-ai-management-agent-registry-tool-configurator-widget-edit.component-DyczMN-R.mjs.map +0 -1
  210. package/fesm2022/acorex-modules-ai-management-agent.entity-CpSXisAh.mjs.map +0 -1
  211. package/fesm2022/acorex-modules-ai-management-ai-delegated-agent-transcript-popup.component-CYk2rB36.mjs.map +0 -1
  212. package/fesm2022/acorex-modules-ai-management-assist-delegated-agent-configurator-widget-edit.component-BDcW8BRI.mjs.map +0 -1
  213. package/fesm2022/acorex-modules-ai-management-assist.entity-7uTePpME.mjs.map +0 -1
  214. package/fesm2022/acorex-modules-ai-management-index-DUojDUau.mjs +0 -2
  215. package/fesm2022/acorex-modules-ai-management-model.entity-C9J3trsK.mjs.map +0 -1
  216. package/fesm2022/acorex-modules-ai-management-open-ai-endpoint.entity-kHsxkjEd.mjs.map +0 -1
  217. package/fesm2022/acorex-modules-asset-management-acorex-modules-asset-management-BRap9yt6.mjs.map +0 -1
  218. package/fesm2022/acorex-modules-asset-management-asset-status.rules-BL0Osjqv.mjs.map +0 -1
  219. package/fesm2022/acorex-modules-asset-management-asset-system.entity-C6ak4u9z.mjs.map +0 -1
  220. package/fesm2022/acorex-modules-asset-management-asset.entity-BaET-kSd.mjs.map +0 -1
  221. package/fesm2022/acorex-modules-asset-management-assetLifecycleState.provider-DZ5r2zx7.mjs.map +0 -1
  222. package/fesm2022/acorex-modules-dashboard-management-acorex-modules-dashboard-management-yqfev--M.mjs.map +0 -1
  223. package/fesm2022/acorex-modules-human-capital-management-acorex-modules-human-capital-management-Ck9q-IWW.mjs.map +0 -1
  224. package/fesm2022/acorex-modules-human-capital-management-employee.entity-DjMQm3VC.mjs.map +0 -1
  225. package/fesm2022/acorex-modules-maintenance-management-acorex-modules-maintenance-management-CfHMiVos.mjs.map +0 -1
  226. package/fesm2022/acorex-modules-maintenance-management-failure-register.entity-zKGo9bOs.mjs.map +0 -1
  227. package/fesm2022/acorex-modules-maintenance-management-maintenance-template.entity-CzX0phT-.mjs.map +0 -1
  228. package/fesm2022/acorex-modules-organization-management-acorex-modules-organization-management-CnAHfj2t.mjs.map +0 -1
  229. package/fesm2022/acorex-modules-organization-management-team.entity-BbcFYP20.mjs.map +0 -1
  230. package/fesm2022/acorex-modules-product-catalog-product.entity-aVWXuhlQ.mjs.map +0 -1
  231. package/fesm2022/acorex-modules-task-management-task-board.page-DA2563QE.mjs.map +0 -1
  232. package/fesm2022/acorex-modules-workflow-management-index-C9Qc07oK.mjs.map +0 -1
  233. package/fesm2022/acorex-modules-workflow-management-workflow-instance.entity-D-KnWlsU.mjs.map +0 -1
  234. package/fesm2022/acorex-modules-workflow-management-workflow-task-popover.component-NpUx0sB5.mjs.map +0 -1
@@ -1,49 +1,26 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, inject, NgModule, InjectionToken, Inject, makeEnvironmentProviders, Injector, runInInjectionContext, output, ViewEncapsulation, ChangeDetectionStrategy, Component, DestroyRef, signal, computed, effect, viewChild } from '@angular/core';
2
+ import { Injectable, inject, NgModule, InjectionToken, Inject, makeEnvironmentProviders, Injector, runInInjectionContext } from '@angular/core';
3
3
  import { AXPCommonMenuKeys, AXPWidgetsList } from '@acorex/modules/common';
4
- import { AXPSessionService, AXPAuthGuard, AXP_PERMISSION_DEFINITION_PROVIDER } from '@acorex/platform/auth';
5
- import { AXPEntityService, AXPEntityFormBuilderService, AXPEntityDefinitionRegistryService, entityDetailsCrudActions, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
4
+ import { AXPSessionService, AXP_PERMISSION_DEFINITION_PROVIDER } from '@acorex/platform/auth';
5
+ import { AXPEntityService, AXPEntityFormBuilderService, AXPEntityDefinitionRegistryService, entityDetailsCrudActions, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
6
6
  import { firstValueFrom } from 'rxjs';
7
7
  import { AXMCalendarManagementModule } from '@acorex/modules/calendar-management';
8
8
  import { AXPEntityCommandScope, AXPStatusProvider, AXPSystemStatusType, systemStatusToDefinition, AXPSystemStatuses, AXP_STATUS_PROVIDERS, AXP_MENU_PROVIDER } from '@acorex/platform/common';
9
9
  import { AXPSystemActionType, AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, AXP_MODULE_MANIFEST_PROVIDER, provideLazyProvider } from '@acorex/platform/core';
10
- import { AXP_PAGE_COMPONENT_PROVIDER, AXPPropertyViewerComponent, AXPThemeLayoutBlockComponent, AXPThemeLayoutHeaderComponent, AXPThemeLayoutToolbarComponent, AXPThemeLayoutStartSideComponent } from '@acorex/platform/layout/components';
10
+ import { AXP_PAGE_COMPONENT_PROVIDER } from '@acorex/platform/layout/components';
11
11
  import { AXPDomainModule } from '@acorex/platform/domain';
12
- import { AXPWidgetGroupEnum, AXP_WIDGETS_EDITOR_CATEGORY, AXPWidgetSerializationHelper, AXPWidgetCoreModule, AXP_WIDGET_DEFINITION_PROVIDER, mapAXPPropertyToWidgetProperty } from '@acorex/platform/layout/widget-core';
12
+ import { AXPWidgetGroupEnum, AXP_WIDGETS_EDITOR_CATEGORY, AXPWidgetSerializationHelper, AXPWidgetCoreModule, AXP_WIDGET_DEFINITION_PROVIDER } from '@acorex/platform/layout/widget-core';
13
13
  import { AXPBarChartWidget, AXPHeatmapChartWidget, AXPDonutChartWidget, AXPLineChartWidget, AXPGaugeChartWidget, AXPFunnelChartWidget, AXPKpiDetailsWidget, AXPKpiProgressWidget, AXPKpiSegmentedWidget, AXPKpiStatCardWidget } from '@acorex/modules/dashboard-management';
14
14
  import { AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY } from '@acorex/platform/layout/widgets';
15
15
  import { provideCommandSetups } from '@acorex/platform/runtime';
16
- import { AXPWorkflowManager, AXPWorkflowDefinitionService, AXP_WORKFLOW_PROVIDER, AXP_ACTIVITY_CATEGORY_PROVIDER, AXP_ACTIVITY_PROVIDER, AXP_WORKFLOW_CATEGORY_PROVIDER, AXPActivityDefinitionService } from '@acorex/platform/workflow';
17
- import { ROUTES, ActivatedRoute, Router } from '@angular/router';
16
+ import { AXPWorkflowManager, AXPWorkflowDefinitionService, AXP_WORKFLOW_PROVIDER, AXP_ACTIVITY_CATEGORY_PROVIDER, AXP_ACTIVITY_PROVIDER, AXP_WORKFLOW_CATEGORY_PROVIDER } from '@acorex/platform/workflow';
18
17
  import { AXDialogService } from '@acorex/components/dialog';
19
- import * as i5$1 from '@acorex/core/translation';
20
- import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
18
+ import { AXTranslationService } from '@acorex/core/translation';
21
19
  import { AXPopupService } from '@acorex/components/popup';
22
20
  import { AXPDialogRendererComponent, AXPLayoutBuilderService } from '@acorex/platform/layout/builder';
23
21
  import { cloneDeep } from 'lodash-es';
24
22
  import { AXToastService } from '@acorex/components/toast';
25
23
  import { AXPWorkflowTaskProvider, AXP_WORKFLOW_TASK_PROVIDER } from '@acorex/modules/task-management';
26
- import * as i2 from '@acorex/components/button';
27
- import { AXButtonModule } from '@acorex/components/button';
28
- import * as i2$1 from '@acorex/components/button-group';
29
- import { AXButtonGroupModule } from '@acorex/components/button-group';
30
- import * as i3 from '@acorex/components/decorators';
31
- import { AXDecoratorModule } from '@acorex/components/decorators';
32
- import * as i5 from '@acorex/components/search-box';
33
- import { AXSearchBoxModule } from '@acorex/components/search-box';
34
- import { AXSelectBoxModule } from '@acorex/components/select-box';
35
- import * as i6 from '@acorex/components/switch';
36
- import { AXSwitchModule } from '@acorex/components/switch';
37
- import { AXTabsModule } from '@acorex/components/tabs';
38
- import * as i4 from '@acorex/components/text-box';
39
- import { AXTextBoxModule } from '@acorex/components/text-box';
40
- import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageLayoutBase } from '@acorex/platform/layout/views';
41
- import * as i7 from '@angular/common';
42
- import { CommonModule } from '@angular/common';
43
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
44
- import { FormsModule } from '@angular/forms';
45
- import * as i1 from '@acorex/components/tree-view-legacy';
46
- import { AXTreeViewLegacyModule } from '@acorex/components/tree-view-legacy';
47
24
 
48
25
  const config = {
49
26
  i18n: 'workflow-management',
@@ -179,9 +156,9 @@ class AXMWorkflowManagementModuleEntityProvider {
179
156
  if (moduleName === RootConfig.module.name) {
180
157
  switch (entityName) {
181
158
  case RootConfig.entities.workflowDefinition.name:
182
- return (await import('./acorex-modules-workflow-management-workflow-definition.entity-DqPVpcSv.mjs')).factory();
159
+ return (await import('./acorex-modules-workflow-management-workflow-definition.entity-CjQQpjdB.mjs')).factory();
183
160
  case RootConfig.entities.workflowInstance.name:
184
- return (await import('./acorex-modules-workflow-management-workflow-instance.entity-D-KnWlsU.mjs')).factory();
161
+ return (await import('./acorex-modules-workflow-management-workflow-instance.entity-B_V3uMSI.mjs')).factory();
185
162
  case RootConfig.entities.activityDefinition.name:
186
163
  return (await import('./acorex-modules-workflow-management-activity-definition.entity-B3DkgDQb.mjs')).factory();
187
164
  case RootConfig.entities.automation.name:
@@ -206,7 +183,6 @@ const AXPWorkflowManagementMenuKeys = {
206
183
  Workflow: 'workflow-management:workflow',
207
184
  WorkflowDefinitions: 'workflow-management:workflow-definitions',
208
185
  WorkflowInstances: 'workflow-management:workflow-instances',
209
- WorkflowStudio: 'workflow-management:workflow-studio',
210
186
  Activities: 'workflow-management:activities',
211
187
  };
212
188
 
@@ -221,7 +197,6 @@ class AXMMenuProvider {
221
197
  return;
222
198
  }
223
199
  const module = RootConfig.module;
224
- const appName = this.sessionService.application?.name ?? module.name;
225
200
  const workflowsMenu = context.find(AXPCommonMenuKeys.Workflows);
226
201
  if (!workflowsMenu.exists) {
227
202
  context.find(AXPCommonMenuKeys.Administration).addItems([
@@ -256,16 +231,6 @@ class AXMMenuProvider {
256
231
  features: [module.name],
257
232
  },
258
233
  },
259
- {
260
- name: AXPWorkflowManagementMenuKeys.WorkflowStudio,
261
- text: '@workflow-management:workflow-studio.menus.workflow-studio.title',
262
- path: `/${appName}/workflow-management/studio`,
263
- priority: 3,
264
- icon: 'fa-light fa-wrench',
265
- policy: {
266
- features: [module.name],
267
- },
268
- },
269
234
  ]);
270
235
  }
271
236
  }
@@ -1022,10 +987,10 @@ const AXMActivityCommandConfiguratorWidget = {
1022
987
  ],
1023
988
  components: {
1024
989
  edit: {
1025
- component: () => import('./acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-BYJpDQRs.mjs').then((c) => c.AXMActivityCommandConfiguratorWidgetEditComponent),
990
+ component: () => import('./acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-Dj6LkQeZ.mjs').then((c) => c.AXMActivityCommandConfiguratorWidgetEditComponent),
1026
991
  },
1027
992
  designer: {
1028
- component: () => import('./acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-BYJpDQRs.mjs').then((c) => c.AXMActivityCommandConfiguratorWidgetEditComponent),
993
+ component: () => import('./acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-Dj6LkQeZ.mjs').then((c) => c.AXMActivityCommandConfiguratorWidgetEditComponent),
1029
994
  },
1030
995
  column: {
1031
996
  component: () => import('./acorex-modules-workflow-management-activity-command-configurator-widget-column.component-CDo0QVFy.mjs').then((c) => c.AXMActivityCommandConfiguratorWidgetColumnComponent),
@@ -2594,9 +2559,7 @@ class AXPGenericWorkflowTaskProvider extends AXPWorkflowTaskProvider {
2594
2559
  if (payload.activityType === 'workflow-activity:cartable') {
2595
2560
  return assigned.length === 0 && candidates.length > 0;
2596
2561
  }
2597
- return (payload.activityType === 'workflow-activity:human-task' &&
2598
- assigned.length === 0 &&
2599
- candidates.length > 0);
2562
+ return payload.activityType === 'workflow-activity:human-task' && assigned.length === 0 && candidates.length > 0;
2600
2563
  }
2601
2564
  normalizeUserIdList(value) {
2602
2565
  if (!value || value.length === 0)
@@ -2666,8 +2629,7 @@ class AXPGenericWorkflowTaskProvider extends AXPWorkflowTaskProvider {
2666
2629
  // Get payload from entity (payload object or parse payloadJson)
2667
2630
  let payload;
2668
2631
  try {
2669
- const raw = bookmark.payload ??
2670
- (bookmark.payloadJson ? JSON.parse(bookmark.payloadJson) : null);
2632
+ const raw = bookmark.payload ?? (bookmark.payloadJson ? JSON.parse(bookmark.payloadJson) : null);
2671
2633
  payload =
2672
2634
  typeof raw === 'object' && raw !== null
2673
2635
  ? raw
@@ -2723,11 +2685,13 @@ class AXPGenericWorkflowTaskProvider extends AXPWorkflowTaskProvider {
2723
2685
  mapBookmarkToTask(instance, bookmark, payload) {
2724
2686
  // Extract dates
2725
2687
  const dueDate = payload.dueDate
2726
- ? (typeof payload.dueDate === 'string' ? new Date(payload.dueDate) : payload.dueDate)
2727
- : (instance.createdAt ? new Date(instance.createdAt) : new Date());
2728
- const startDate = instance.createdAt
2729
- ? new Date(instance.createdAt)
2730
- : dueDate;
2688
+ ? typeof payload.dueDate === 'string'
2689
+ ? new Date(payload.dueDate)
2690
+ : payload.dueDate
2691
+ : instance.createdAt
2692
+ ? new Date(instance.createdAt)
2693
+ : new Date();
2694
+ const startDate = instance.createdAt ? new Date(instance.createdAt) : dueDate;
2731
2695
  // If startDate and endDate are the same, set endDate to one day after startDate
2732
2696
  let endDate = dueDate;
2733
2697
  if (startDate.getTime() === dueDate.getTime()) {
@@ -2910,10 +2874,7 @@ class AXPGenericWorkflowTaskProvider extends AXPWorkflowTaskProvider {
2910
2874
  }
2911
2875
  // Extract actions from payload
2912
2876
  if (payload.actions) {
2913
- const allActions = [
2914
- ...(payload.actions.prefix || []),
2915
- ...(payload.actions.suffix || []),
2916
- ];
2877
+ const allActions = [...(payload.actions.prefix || []), ...(payload.actions.suffix || [])];
2917
2878
  for (const action of allActions) {
2918
2879
  const actionName = action.command?.name || action.name || 'unknown';
2919
2880
  actions.push({
@@ -2993,7 +2954,7 @@ class AXPGenericWorkflowTaskProvider extends AXPWorkflowTaskProvider {
2993
2954
  //#endregion
2994
2955
  //#region ---- Component ----
2995
2956
  getComponent() {
2996
- return () => import('./acorex-modules-workflow-management-workflow-task-popover.component-NpUx0sB5.mjs').then((m) => m.AXMWorkflowTaskPopoverComponent);
2957
+ return () => import('./acorex-modules-workflow-management-workflow-task-popover.component-l37iXJIY.mjs').then((m) => m.AXMWorkflowTaskPopoverComponent);
2997
2958
  }
2998
2959
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPGenericWorkflowTaskProvider, deps: [{ token: AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
2999
2960
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPGenericWorkflowTaskProvider }); }
@@ -3034,13 +2995,6 @@ function provideTaskWorkflow() {
3034
2995
  providers.push(provider);
3035
2996
  }
3036
2997
  }
3037
- if (providers.length === 0) {
3038
- providers.push(runInInjectionContext(injector, () => new AXPGenericWorkflowTaskProvider({
3039
- name: 'workflow-tasks-all',
3040
- title: 'Workflow tasks',
3041
- icon: 'fa-light fa-inbox',
3042
- })));
3043
- }
3044
2998
  return providers;
3045
2999
  })();
3046
3000
  },
@@ -3049,26 +3003,6 @@ function provideTaskWorkflow() {
3049
3003
  ]);
3050
3004
  }
3051
3005
 
3052
- function routesFactory() {
3053
- const config = inject(AXP_ENTITY_CONFIG_TOKEN);
3054
- const routes = [
3055
- {
3056
- path: ':app/workflow-management/studio',
3057
- loadComponent: () => {
3058
- return config.viewers.root();
3059
- },
3060
- canActivate: [AXPAuthGuard],
3061
- data: { reuse: true },
3062
- children: [
3063
- {
3064
- path: '',
3065
- loadComponent: () => Promise.resolve().then(function () { return workflowStudio_component; }).then((c) => c.WorkflowStudioComponent),
3066
- },
3067
- ],
3068
- },
3069
- ];
3070
- return routes;
3071
- }
3072
3006
  class AXMWorkflowManagementModule {
3073
3007
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMWorkflowManagementModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
3074
3008
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: AXMWorkflowManagementModule, imports: [AXMCalendarManagementModule,
@@ -3078,23 +3012,14 @@ class AXMWorkflowManagementModule {
3078
3012
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMWorkflowManagementModule, providers: [
3079
3013
  { provide: AXP_WIDGET_DEFINITION_PROVIDER, useClass: AXMWorkflowManagementWidgetsProvider, multi: true },
3080
3014
  { provide: AXP_WIDGET_DEFINITION_PROVIDER, useClass: AXMWorkflowDashboardWidgetsProvider, multi: true },
3081
- {
3082
- provide: ROUTES,
3083
- multi: true,
3084
- useFactory: routesFactory,
3085
- },
3086
3015
  provideCommandSetups([
3087
3016
  {
3088
3017
  key: 'WorkflowManagement.WorkflowDefinition:ExecuteWithInput',
3089
- command: () => import('./acorex-modules-workflow-management-index-C9Qc07oK.mjs').then((c) => c.ExecuteWorkflowWithInputCommand),
3018
+ command: () => import('./acorex-modules-workflow-management-index-CHySddpP.mjs').then((c) => c.ExecuteWorkflowWithInputCommand),
3090
3019
  },
3091
3020
  {
3092
3021
  key: 'WorkflowManagement.WorkflowDefinition:Execute',
3093
- command: () => import('./acorex-modules-workflow-management-index-C9Qc07oK.mjs').then((c) => c.ExecuteWorkflowCommand),
3094
- },
3095
- {
3096
- key: 'WorkflowManagement.WorkflowDefinition:EditInStudio',
3097
- command: () => import('./acorex-modules-workflow-management-index-C9Qc07oK.mjs').then((c) => c.EditInStudioCommand),
3022
+ command: () => import('./acorex-modules-workflow-management-index-CHySddpP.mjs').then((c) => c.ExecuteWorkflowCommand),
3098
3023
  },
3099
3024
  {
3100
3025
  key: 'WorkflowManagement.WorkflowDefinition:Activities:Save',
@@ -3140,8 +3065,8 @@ class AXMWorkflowManagementModule {
3140
3065
  useClass: AXMWorkflowManagementModuleEntityProvider,
3141
3066
  multi: true,
3142
3067
  },
3143
- provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-Bx2uYraH.mjs').then((m) => m.AXMWorkflowInstanceActivityInstancesPageComponentProvider)),
3144
- provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-D8fjNgQJ.mjs').then((m) => m.AXMWorkflowDefinitionActivitiesPageComponentProvider)),
3068
+ provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-Eh5DDK-V.mjs').then((m) => m.AXMWorkflowInstanceActivityInstancesPageComponentProvider)),
3069
+ provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-V4OesZTq.mjs').then((m) => m.AXMWorkflowDefinitionActivitiesPageComponentProvider)),
3145
3070
  // Automation condition builder: default automation.rules(refType, refId); modules override for their refTypes
3146
3071
  {
3147
3072
  provide: AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER,
@@ -3240,23 +3165,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3240
3165
  providers: [
3241
3166
  { provide: AXP_WIDGET_DEFINITION_PROVIDER, useClass: AXMWorkflowManagementWidgetsProvider, multi: true },
3242
3167
  { provide: AXP_WIDGET_DEFINITION_PROVIDER, useClass: AXMWorkflowDashboardWidgetsProvider, multi: true },
3243
- {
3244
- provide: ROUTES,
3245
- multi: true,
3246
- useFactory: routesFactory,
3247
- },
3248
3168
  provideCommandSetups([
3249
3169
  {
3250
3170
  key: 'WorkflowManagement.WorkflowDefinition:ExecuteWithInput',
3251
- command: () => import('./acorex-modules-workflow-management-index-C9Qc07oK.mjs').then((c) => c.ExecuteWorkflowWithInputCommand),
3171
+ command: () => import('./acorex-modules-workflow-management-index-CHySddpP.mjs').then((c) => c.ExecuteWorkflowWithInputCommand),
3252
3172
  },
3253
3173
  {
3254
3174
  key: 'WorkflowManagement.WorkflowDefinition:Execute',
3255
- command: () => import('./acorex-modules-workflow-management-index-C9Qc07oK.mjs').then((c) => c.ExecuteWorkflowCommand),
3256
- },
3257
- {
3258
- key: 'WorkflowManagement.WorkflowDefinition:EditInStudio',
3259
- command: () => import('./acorex-modules-workflow-management-index-C9Qc07oK.mjs').then((c) => c.EditInStudioCommand),
3175
+ command: () => import('./acorex-modules-workflow-management-index-CHySddpP.mjs').then((c) => c.ExecuteWorkflowCommand),
3260
3176
  },
3261
3177
  {
3262
3178
  key: 'WorkflowManagement.WorkflowDefinition:Activities:Save',
@@ -3302,8 +3218,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3302
3218
  useClass: AXMWorkflowManagementModuleEntityProvider,
3303
3219
  multi: true,
3304
3220
  },
3305
- provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-Bx2uYraH.mjs').then((m) => m.AXMWorkflowInstanceActivityInstancesPageComponentProvider)),
3306
- provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-D8fjNgQJ.mjs').then((m) => m.AXMWorkflowDefinitionActivitiesPageComponentProvider)),
3221
+ provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-Eh5DDK-V.mjs').then((m) => m.AXMWorkflowInstanceActivityInstancesPageComponentProvider)),
3222
+ provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-V4OesZTq.mjs').then((m) => m.AXMWorkflowDefinitionActivitiesPageComponentProvider)),
3307
3223
  // Automation condition builder: default automation.rules(refType, refId); modules override for their refTypes
3308
3224
  {
3309
3225
  provide: AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER,
@@ -3395,2284 +3311,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3395
3311
  // Entity exports - services and modules removed, handled by middleware
3396
3312
  // Exporting entity types for use in feature components
3397
3313
 
3398
- //#region ---- Imports ----
3399
- //#endregion
3400
- class AXMActivityCategoriesTreeComponent {
3401
- constructor() {
3402
- //#region ---- Services & Dependencies ----
3403
- this.activityDefinitionService = inject(AXPActivityDefinitionService);
3404
- this.multiLanguageResolver = inject(AXTranslationService);
3405
- //#endregion
3406
- //#region ---- Output Events ----
3407
- this.categoryClick = output();
3408
- this.activityClick = output();
3409
- /** Emitted when user starts dragging an activity (so parent can set draggedActivity for canvas drop). */
3410
- this.activityDragStart = output();
3411
- //#endregion
3412
- //#region ---- Lazy Tree Data (same pattern as report-categories-tree) ----
3413
- this.provideLazyTreeView = async (selectedItemId) => {
3414
- if (selectedItemId !== undefined && selectedItemId !== null) {
3415
- const parentId = String(selectedItemId);
3416
- if (parentId.startsWith('activity_')) {
3417
- return [];
3418
- }
3419
- const categories = await this.activityDefinitionService.getCategories(parentId);
3420
- const categoryItems = categories.map((item) => ({
3421
- id: item.id,
3422
- title: this.multiLanguageResolver.resolve(item.title) || item.id,
3423
- hasChild: (item.childrenCount ?? 0) > 0 || (item.itemsCount ?? 0) > 0,
3424
- item,
3425
- type: 'category',
3426
- expanded: false,
3427
- }));
3428
- const activities = await this.activityDefinitionService.getActivitiesByCategoryId(parentId);
3429
- const definitionItems = activities.map((item) => ({
3430
- id: `activity_${item.type ?? item.name}`,
3431
- title: this.multiLanguageResolver.resolve(item.title) || item.name || item.type || '',
3432
- hasChild: false,
3433
- item,
3434
- type: 'definition',
3435
- expanded: false,
3436
- }));
3437
- return [...categoryItems, ...definitionItems];
3438
- }
3439
- const categories = await this.activityDefinitionService.getCategories();
3440
- return categories.map((item) => ({
3441
- id: item.id,
3442
- title: this.multiLanguageResolver.resolve(item.title) || item.id,
3443
- hasChild: (item.childrenCount ?? 0) > 0 || (item.itemsCount ?? 0) > 0,
3444
- item,
3445
- type: 'category',
3446
- expanded: false,
3447
- }));
3448
- };
3449
- }
3450
- //#endregion
3451
- //#region ---- Event Handlers ----
3452
- handleNodeClick(event) {
3453
- const node = event.data;
3454
- if (node.type === 'category' && node.item) {
3455
- this.categoryClick.emit(node.item);
3456
- }
3457
- else if (node.type === 'definition' && node.item) {
3458
- this.activityClick.emit(node.item);
3459
- }
3460
- }
3461
- onActivityDragStart(event, item) {
3462
- if (item.type !== 'definition' || !item.item)
3463
- return;
3464
- event.stopPropagation();
3465
- if (event.dataTransfer) {
3466
- event.dataTransfer.effectAllowed = 'copy';
3467
- event.dataTransfer.setData('text/plain', item.item.type);
3468
- }
3469
- this.activityDragStart.emit({ event, activity: item.item });
3470
- }
3471
- /**
3472
- * Normalize FontAwesome icon for display: prepend 'fa-light ' when missing style prefix.
3473
- */
3474
- getActivityIconClass(icon) {
3475
- if (!icon?.trim())
3476
- return 'fa-light fa-puzzle-piece';
3477
- const trimmed = icon.trim();
3478
- const hasStylePrefix = /^(fa-light|fas|far|fal|fa-solid|fa-regular|fa-brands|fa-duotone)(\s|$)/i.test(trimmed);
3479
- return hasStylePrefix ? trimmed : `fa-light ${trimmed}`;
3480
- }
3481
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMActivityCategoriesTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3482
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXMActivityCategoriesTreeComponent, isStandalone: true, selector: "axp-activity-categories-tree", outputs: { categoryClick: "categoryClick", activityClick: "activityClick", activityDragStart: "activityDragStart" }, host: { classAttribute: "axp-activity-categories-tree" }, ngImport: i0, template: "<ax-tree-view-legacy\n [showCheckbox]=\"false\"\n [itemTemplate]=\"itemTemplate\"\n [textField]=\"'title'\"\n [hasChildField]=\"'hasChild'\"\n [valueField]=\"'id'\"\n [expandedField]=\"'expanded'\"\n [items]=\"provideLazyTreeView\"\n (onNodeClick)=\"handleNodeClick($event)\"\n>\n</ax-tree-view-legacy>\n\n<ng-template #itemTemplate let-item>\n @if (item.type === 'category') {\n <span class=\"__tree-item __category\">\n <i class=\"fas fa-folder ax-text-warning __icon\"></i>\n <span class=\"__title\">{{ item.title }}</span>\n </span>\n } @else {\n <span\n class=\"__tree-item __activity\"\n draggable=\"true\"\n (dragstart)=\"onActivityDragStart($event, item)\"\n >\n <i class=\"__icon ax-text-primary\" [class]=\"getActivityIconClass(item.item?.icon)\"></i>\n <span class=\"__title\">{{ item.title }}</span>\n </span>\n }\n</ng-template>\n", styles: [".axp-activity-categories-tree{height:100%;width:100%}.axp-activity-categories-tree .__tree-item{display:flex;align-items:center;gap:.5rem}.axp-activity-categories-tree .__tree-item .__icon{flex-shrink:0}.axp-activity-categories-tree .__tree-item .__title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.axp-activity-categories-tree .__activity{cursor:grab}.axp-activity-categories-tree .__activity:active{cursor:grabbing}\n"], dependencies: [{ kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXTreeViewLegacyModule }, { kind: "component", type: i1.AXTreeViewLegacyComponent, selector: "ax-tree-view-legacy", inputs: ["items", "showCheckbox", "hasCheckboxField", "selectionMode", "selectionBehavior", "selectionScope", "focusNodeEnabled", "valueField", "textField", "visibleField", "disableField", "hasChildField", "selectedField", "expandedField", "tooltipField", "childrenField", "activeField", "indeterminateField", "parentField", "iconField", "toggleIcons", "look", "showEmptyNodeMassage", "itemTemplate", "emptyTemplate", "expandOn"], outputs: ["onSelectionChanged", "onItemSelectedChanged", "onNodeClick", "onCollapsedChanged", "onNodedbClick"] }, { kind: "ngmodule", type: AXTranslationModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
3483
- }
3484
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMActivityCategoriesTreeComponent, decorators: [{
3485
- type: Component,
3486
- args: [{ selector: 'axp-activity-categories-tree', standalone: true, imports: [AXDecoratorModule, AXTreeViewLegacyModule, AXTranslationModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'axp-activity-categories-tree' }, template: "<ax-tree-view-legacy\n [showCheckbox]=\"false\"\n [itemTemplate]=\"itemTemplate\"\n [textField]=\"'title'\"\n [hasChildField]=\"'hasChild'\"\n [valueField]=\"'id'\"\n [expandedField]=\"'expanded'\"\n [items]=\"provideLazyTreeView\"\n (onNodeClick)=\"handleNodeClick($event)\"\n>\n</ax-tree-view-legacy>\n\n<ng-template #itemTemplate let-item>\n @if (item.type === 'category') {\n <span class=\"__tree-item __category\">\n <i class=\"fas fa-folder ax-text-warning __icon\"></i>\n <span class=\"__title\">{{ item.title }}</span>\n </span>\n } @else {\n <span\n class=\"__tree-item __activity\"\n draggable=\"true\"\n (dragstart)=\"onActivityDragStart($event, item)\"\n >\n <i class=\"__icon ax-text-primary\" [class]=\"getActivityIconClass(item.item?.icon)\"></i>\n <span class=\"__title\">{{ item.title }}</span>\n </span>\n }\n</ng-template>\n", styles: [".axp-activity-categories-tree{height:100%;width:100%}.axp-activity-categories-tree .__tree-item{display:flex;align-items:center;gap:.5rem}.axp-activity-categories-tree .__tree-item .__icon{flex-shrink:0}.axp-activity-categories-tree .__tree-item .__title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.axp-activity-categories-tree .__activity{cursor:grab}.axp-activity-categories-tree .__activity:active{cursor:grabbing}\n"] }]
3487
- }], propDecorators: { categoryClick: [{ type: i0.Output, args: ["categoryClick"] }], activityClick: [{ type: i0.Output, args: ["activityClick"] }], activityDragStart: [{ type: i0.Output, args: ["activityDragStart"] }] } });
3488
-
3489
- class WorkflowStudioComponent extends AXPPageLayoutBaseComponent {
3490
- constructor() {
3491
- super(...arguments);
3492
- //#region ---- Services & Dependencies ----
3493
- this.workflowManager = inject(AXPWorkflowManager);
3494
- this.activityDefinitionService = inject(AXPActivityDefinitionService);
3495
- this.entityService = inject(AXPEntityService);
3496
- this.translationService = inject(AXTranslationService);
3497
- this.activatedRoute = inject(ActivatedRoute);
3498
- this.router = inject(Router);
3499
- this.workflowDefinitionService = inject(AXPWorkflowDefinitionService);
3500
- this.layoutBuilder = inject(AXPLayoutBuilderService);
3501
- this.destroyRef = inject(DestroyRef);
3502
- //#endregion
3503
- //#region ---- State ----
3504
- this.activeTab = signal('json', ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
3505
- this.selectedCategory = signal(null, ...(ngDevMode ? [{ debugName: "selectedCategory" }] : /* istanbul ignore next */ []));
3506
- this.selectedActivity = signal(null, ...(ngDevMode ? [{ debugName: "selectedActivity" }] : /* istanbul ignore next */ []));
3507
- this.workflowJson = signal(this.getEmptyWorkflow(), ...(ngDevMode ? [{ debugName: "workflowJson" }] : /* istanbul ignore next */ []));
3508
- this.visualNodes = signal([], ...(ngDevMode ? [{ debugName: "visualNodes" }] : /* istanbul ignore next */ []));
3509
- this.selectedNode = signal(null, ...(ngDevMode ? [{ debugName: "selectedNode" }] : /* istanbul ignore next */ []));
3510
- this.isExecuting = signal(false, ...(ngDevMode ? [{ debugName: "isExecuting" }] : /* istanbul ignore next */ []));
3511
- this.executionLogs = signal([], ...(ngDevMode ? [{ debugName: "executionLogs" }] : /* istanbul ignore next */ []));
3512
- // Execution Dialog State
3513
- this.showExecutionDialog = signal(false, ...(ngDevMode ? [{ debugName: "showExecutionDialog" }] : /* istanbul ignore next */ []));
3514
- this.workflowInstanceState = signal(null, ...(ngDevMode ? [{ debugName: "workflowInstanceState" }] : /* istanbul ignore next */ []));
3515
- // UI State
3516
- this.showPropertiesPanel = signal(true, ...(ngDevMode ? [{ debugName: "showPropertiesPanel" }] : /* istanbul ignore next */ []));
3517
- /** When true, workflow changes can trigger auto-save (e.g. apply to JSON); actual persist is up to the host. */
3518
- this.autoSaveEnabled = signal(false, ...(ngDevMode ? [{ debugName: "autoSaveEnabled" }] : /* istanbul ignore next */ []));
3519
- /** Activity definition for the selected node (loaded when selection changes). */
3520
- this.activityDefinitionForSelected = signal(null, ...(ngDevMode ? [{ debugName: "activityDefinitionForSelected" }] : /* istanbul ignore next */ []));
3521
- /** Cache key for property viewer tabs so we keep stable refs and avoid re-render/focus loss on value change. */
3522
- this.lastPropertyViewerStructKey = null;
3523
- /** Cached tabs; updated only when selected node identity or def structure changes. */
3524
- this.cachedPropertyViewerTabs = signal([], ...(ngDevMode ? [{ debugName: "cachedPropertyViewerTabs" }] : /* istanbul ignore next */ []));
3525
- /** Tabs for the property viewer (platform widget-based rendering). Stable refs to prevent focus loss. */
3526
- this.propertyViewerTabs = computed(() => this.cachedPropertyViewerTabs(), ...(ngDevMode ? [{ debugName: "propertyViewerTabs" }] : /* istanbul ignore next */ []));
3527
- this.updatePropertyViewerTabsEffect = effect(() => {
3528
- const def = this.activityDefinitionForSelected();
3529
- const node = this.selectedNode();
3530
- if (!node) {
3531
- this.lastPropertyViewerStructKey = null;
3532
- this.cachedPropertyViewerTabs.set([]);
3533
- return;
3534
- }
3535
- const structKey = `${node.id}:${node.type}:${def?.inputs?.length ?? 0}`;
3536
- if (this.lastPropertyViewerStructKey === structKey)
3537
- return;
3538
- this.lastPropertyViewerStructKey = structKey;
3539
- this.cachedPropertyViewerTabs.set(this.buildPropertyViewerTabs(def, node));
3540
- }, ...(ngDevMode ? [{ debugName: "updatePropertyViewerTabsEffect" }] : /* istanbul ignore next */ []));
3541
- this.propertyViewerRef = viewChild(AXPPropertyViewerComponent, ...(ngDevMode ? [{ debugName: "propertyViewerRef" }] : /* istanbul ignore next */ []));
3542
- this.loadActivityDefinitionForSelectedEffect = effect(() => {
3543
- const node = this.selectedNode();
3544
- if (!node) {
3545
- this.activityDefinitionForSelected.set(null);
3546
- return;
3547
- }
3548
- this.activityDefinitionService.getActivityByName(node.type).then((def) => {
3549
- this.activityDefinitionForSelected.set(def ?? null);
3550
- });
3551
- }, ...(ngDevMode ? [{ debugName: "loadActivityDefinitionForSelectedEffect" }] : /* istanbul ignore next */ []));
3552
- this.initPropertyViewerContextEffect = effect(() => {
3553
- const viewer = this.propertyViewerRef();
3554
- const node = this.selectedNode();
3555
- const tabs = this.propertyViewerTabs();
3556
- if (viewer && node && tabs.length > 0) {
3557
- viewer.initializeContext({ ...node, properties: { ...node.properties } });
3558
- }
3559
- }, ...(ngDevMode ? [{ debugName: "initPropertyViewerContextEffect" }] : /* istanbul ignore next */ []));
3560
- // Workflow Settings
3561
- this.workflowSettings = signal({
3562
- definitionId: '',
3563
- name: '',
3564
- description: '',
3565
- inputs: [],
3566
- outputs: [],
3567
- variables: [],
3568
- outcomes: ['Done'],
3569
- usableAsActivity: false,
3570
- autoUpdateConsumingWorkflows: false,
3571
- version: 1,
3572
- isLatest: true,
3573
- isPublished: false,
3574
- toolVersion: '1.0.0',
3575
- providerName: 'WorkflowStudio',
3576
- }, ...(ngDevMode ? [{ debugName: "workflowSettings" }] : /* istanbul ignore next */ []));
3577
- /** Data source for variable type select (settings modal). */
3578
- this.variableTypeOptions = [
3579
- { value: 'string', label: 'String' },
3580
- { value: 'number', label: 'Number' },
3581
- { value: 'boolean', label: 'Boolean' },
3582
- { value: 'object', label: 'Object' },
3583
- { value: 'array', label: 'Array' },
3584
- ];
3585
- // Canvas state
3586
- this.canvasOffset = { x: 0, y: 0 };
3587
- this.isDraggingCanvas = false;
3588
- this.dragStartPos = { x: 0, y: 0 };
3589
- this.draggedActivity = null;
3590
- this.draggedNode = null;
3591
- this.nodeDragOffset = { x: 0, y: 0 };
3592
- this.connectionSource = null;
3593
- /** Canvas area element for zoom/center/auto-layout. */
3594
- this.canvasAreaRef = viewChild('canvasAreaRef', ...(ngDevMode ? [{ debugName: "canvasAreaRef" }] : /* istanbul ignore next */ []));
3595
- /**
3596
- * دسترسی به Object برای استفاده در template
3597
- */
3598
- this.Object = Object;
3599
- /**
3600
- * دسترسی به typeof برای استفاده در template
3601
- */
3602
- this.typeof = (value) => typeof value;
3603
- /**
3604
- * دسترسی به JSON برای استفاده در template
3605
- */
3606
- this.JSON = JSON;
3607
- }
3608
- async ngOnInit() {
3609
- // Page layout initialization
3610
- await super.ngOnInit();
3611
- // Load workflow from query parameter if provided
3612
- await this.loadWorkflowFromRoute();
3613
- }
3614
- /**
3615
- * Load workflow from route query parameter
3616
- */
3617
- async loadWorkflowFromRoute() {
3618
- // Read from snapshot (for initial load)
3619
- const workflowName = this.activatedRoute.snapshot.queryParams['workflow'];
3620
- if (!workflowName) {
3621
- return;
3622
- }
3623
- await this.loadWorkflowByName(workflowName);
3624
- // Subscribe to query param changes (like drive component)
3625
- this.activatedRoute.queryParams.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(async (params) => {
3626
- const newWorkflowName = params['workflow'];
3627
- if (newWorkflowName && newWorkflowName !== workflowName) {
3628
- await this.loadWorkflowByName(newWorkflowName);
3629
- }
3630
- });
3631
- }
3632
- /**
3633
- * Update a single workflow setting field (for signal-based form binding).
3634
- */
3635
- updateWorkflowSetting(key, value) {
3636
- this.workflowSettings.update((s) => ({ ...s, [key]: value }));
3637
- }
3638
- /**
3639
- * Handle JSON editor input (textarea value -> workflowJson signal).
3640
- */
3641
- onWorkflowJsonInput(ev) {
3642
- const value = ev.target.value;
3643
- this.workflowJson.set(value);
3644
- }
3645
- //#region ---- Workflow definition display (multi-language) ----
3646
- /**
3647
- * Resolves workflow definition title for studio UI strings (settings, graph root label).
3648
- */
3649
- resolveWorkflowDefinitionTitle(workflowDef) {
3650
- const raw = workflowDef.title;
3651
- if (raw == null || raw === '') {
3652
- return workflowDef.name || 'Root';
3653
- }
3654
- return typeof raw === 'string'
3655
- ? raw
3656
- : (this.translationService.resolve(raw) ?? workflowDef.name ?? 'Root');
3657
- }
3658
- /**
3659
- * Resolves workflow definition description for studio settings (current locale string).
3660
- */
3661
- resolveWorkflowDefinitionDescription(workflowDef) {
3662
- const raw = workflowDef.description;
3663
- if (raw == null || raw === '') {
3664
- return '';
3665
- }
3666
- return typeof raw === 'string' ? raw : (this.translationService.resolve(raw) ?? '');
3667
- }
3668
- //#endregion
3669
- /**
3670
- * Load workflow by name
3671
- */
3672
- async loadWorkflowByName(workflowName) {
3673
- try {
3674
- this.addLog('info', `Loading workflow: ${workflowName}...`);
3675
- // Try to get workflow from entity service first
3676
- const workflowEntityService = this.entityService
3677
- .withEntity(RootConfig.module.name, RootConfig.entities.workflowDefinition.name)
3678
- .data();
3679
- const result = await workflowEntityService.query({
3680
- skip: 0,
3681
- take: 1,
3682
- filter: {
3683
- logic: 'and',
3684
- filters: [
3685
- {
3686
- field: 'name',
3687
- operator: { type: 'equal' },
3688
- value: workflowName,
3689
- },
3690
- ],
3691
- },
3692
- });
3693
- let workflowDef = null;
3694
- if (result.items && result.items.length > 0) {
3695
- workflowDef = result.items[0];
3696
- }
3697
- else {
3698
- // Try workflow definition service
3699
- workflowDef = await this.workflowDefinitionService.getWorkflowByName(workflowName);
3700
- }
3701
- if (!workflowDef) {
3702
- this.addLog('warning', `Workflow '${workflowName}' not found`);
3703
- return;
3704
- }
3705
- // Convert workflow definition to studio JSON format
3706
- const studioJson = this.convertWorkflowDefinitionToStudioJson(workflowDef);
3707
- this.workflowJson.set(JSON.stringify(studioJson, null, 2));
3708
- // Update workflow settings
3709
- this.workflowSettings.set({
3710
- definitionId: workflowDef.id || workflowDef.definitionId || workflowDef.name,
3711
- name: workflowDef.name || '',
3712
- description: this.resolveWorkflowDefinitionDescription(workflowDef),
3713
- inputs: (workflowDef.inputs || []).map((input) => this.mapDefinitionInputToWorkflowInput(input)),
3714
- outputs: (workflowDef.outputs || []).map((output) => this.mapDefinitionOutputToWorkflowOutput(output)),
3715
- variables: workflowDef.variables || [],
3716
- outcomes: workflowDef.outcomes || ['Done'],
3717
- usableAsActivity: workflowDef.extensions?.elsa?.options?.usableAsActivity || false,
3718
- autoUpdateConsumingWorkflows: workflowDef.extensions?.elsa?.options?.autoUpdateConsumingWorkflows || false,
3719
- version: workflowDef.version || 1,
3720
- isLatest: workflowDef.isLatest !== undefined ? workflowDef.isLatest : true,
3721
- isPublished: workflowDef.statusId === AXPSystemStatusType.Published,
3722
- toolVersion: workflowDef.toolVersion || '1.0.0',
3723
- providerName: workflowDef.providerName || 'ACoreX',
3724
- });
3725
- this.addLog('success', `Workflow '${workflowName}' loaded successfully`);
3726
- // If visual tab is active, convert to visual
3727
- if (this.activeTab() === 'visual') {
3728
- this.jsonToVisual();
3729
- }
3730
- }
3731
- catch (error) {
3732
- this.addLog('error', `Failed to load workflow: ${error.message}`);
3733
- console.error('[WorkflowStudio] Error loading workflow:', error);
3734
- }
3735
- }
3736
- /**
3737
- * Convert workflow definition to studio JSON format
3738
- */
3739
- convertWorkflowDefinitionToStudioJson(workflowDef) {
3740
- // Convert graph format to root activity format
3741
- const graph = workflowDef.graph;
3742
- if (!graph) {
3743
- return this.getEmptyWorkflow();
3744
- }
3745
- // Build root activity structure
3746
- const rootActivity = {
3747
- id: graph.startActivityId || 'root',
3748
- type: 'workflow-activity:sequence',
3749
- name: this.resolveWorkflowDefinitionTitle(workflowDef),
3750
- children: [],
3751
- };
3752
- // Convert activities to children
3753
- const activities = graph.activities || [];
3754
- const connections = graph.connections || [];
3755
- // Build activity map
3756
- const activityMap = new Map();
3757
- activities.forEach((activity) => {
3758
- activityMap.set(activity.id, {
3759
- id: activity.id,
3760
- type: activity.name || activity.type,
3761
- name: activity.customProperties?.nodeId || activity.id,
3762
- properties: activity.inputs || {},
3763
- children: [],
3764
- });
3765
- });
3766
- // Build connections tree
3767
- const startActivity = activityMap.get(graph.startActivityId);
3768
- if (startActivity) {
3769
- rootActivity.children.push(startActivity);
3770
- // Follow connections to build tree
3771
- const processed = new Set();
3772
- const processActivity = (activityId) => {
3773
- if (processed.has(activityId)) {
3774
- return;
3775
- }
3776
- processed.add(activityId);
3777
- const activity = activityMap.get(activityId);
3778
- if (!activity) {
3779
- return;
3780
- }
3781
- // Find outgoing connections
3782
- const outgoingConnections = connections.filter((conn) => conn.source.activtyName === activityId);
3783
- outgoingConnections.forEach((conn) => {
3784
- const targetActivity = activityMap.get(conn.target.activtyName);
3785
- if (targetActivity && !processed.has(targetActivity.id)) {
3786
- activity.children.push(targetActivity);
3787
- processActivity(targetActivity.id);
3788
- }
3789
- });
3790
- };
3791
- processActivity(graph.startActivityId);
3792
- }
3793
- return {
3794
- id: workflowDef.id || workflowDef.name || 'workflow',
3795
- name: workflowDef.name || '',
3796
- description: this.resolveWorkflowDefinitionDescription(workflowDef),
3797
- version: workflowDef.version || 1,
3798
- root: rootActivity,
3799
- };
3800
- }
3801
- //#endregion
3802
- //#region ---- Page Layout Overrides ----
3803
- async getPageTitle() {
3804
- return await this.translationService.translateAsync('@workflow-management:workflow-studio.menus.workflow-studio.title');
3805
- }
3806
- async getPageDescription() {
3807
- return await this.translationService.translateAsync('@workflow-management:workflow-studio.menus.workflow-studio.description');
3808
- }
3809
- async getPrimaryMenuItems() {
3810
- return [
3811
- {
3812
- name: 'execute-workflow',
3813
- title: '@workflow-management:workflow-studio.actions.execute-workflow.title',
3814
- icon: 'fa-light fa-play',
3815
- color: 'success',
3816
- disabled: this.isExecuting(),
3817
- command: { name: 'execute-workflow' },
3818
- },
3819
- {
3820
- name: 'workflow-settings',
3821
- title: '@workflow-management:workflow-studio.actions.settings.title',
3822
- icon: 'fa-light fa-cog',
3823
- color: 'default',
3824
- command: { name: 'workflow-settings' },
3825
- },
3826
- {
3827
- name: 'export-workflow',
3828
- title: '@workflow-management:workflow-studio.actions.export.title',
3829
- icon: 'fa-light fa-download',
3830
- color: 'default',
3831
- command: { name: 'export-workflow' },
3832
- },
3833
- ];
3834
- }
3835
- async getSecondaryMenuItems() {
3836
- return [
3837
- {
3838
- name: 'format-json',
3839
- title: '@workflow-management:workflow-studio.actions.format-json.title',
3840
- icon: 'fa-light fa-code',
3841
- color: 'default',
3842
- command: { name: 'format-json' },
3843
- },
3844
- {
3845
- name: 'clear-canvas',
3846
- title: '@workflow-management:workflow-studio.actions.clear-canvas.title',
3847
- icon: 'fa-light fa-trash',
3848
- color: 'danger',
3849
- visible: this.activeTab() === 'visual',
3850
- command: { name: 'clear-canvas' },
3851
- },
3852
- ];
3853
- }
3854
- async execute(command) {
3855
- switch (command.name) {
3856
- case 'execute-workflow':
3857
- this.openExecutionDialog();
3858
- break;
3859
- case 'workflow-settings':
3860
- this.openWorkflowSettings();
3861
- break;
3862
- case 'export-workflow':
3863
- this.downloadWorkflowDefinition();
3864
- break;
3865
- case 'format-json':
3866
- this.formatJson();
3867
- break;
3868
- case 'clear-canvas':
3869
- this.clearCanvas();
3870
- break;
3871
- }
3872
- }
3873
- //#endregion
3874
- //#region ---- Category & Activity Loading ----
3875
- /**
3876
- * Handle category selection from tree
3877
- */
3878
- onCategoryClick(category) {
3879
- this.selectedCategory.set(category);
3880
- this.selectedActivity.set(null);
3881
- }
3882
- /**
3883
- * Handle activity selection from tree
3884
- */
3885
- onActivityClick(activity) {
3886
- this.selectedActivity.set(activity);
3887
- this.addLog('info', `Activity selected: ${activity.name}`);
3888
- }
3889
- /**
3890
- * Handle drag start from activity tree – set draggedActivity so canvas drop can add the node.
3891
- */
3892
- onActivityDragStartFromTree(payload) {
3893
- this.draggedActivity = this.convertActivityDefinitionToInfo(payload.activity);
3894
- if (payload.event.dataTransfer) {
3895
- payload.event.dataTransfer.effectAllowed = 'copy';
3896
- payload.event.dataTransfer.setData('text/plain', payload.activity.type);
3897
- }
3898
- }
3899
- /**
3900
- * Convert AXPActivityDefinition to ActivityInfo
3901
- */
3902
- mapDefinitionInputToWorkflowInput(input) {
3903
- const titleRaw = input.title ?? input.name;
3904
- const titleStr = typeof titleRaw === 'string' ? titleRaw : (this.translationService.resolve(titleRaw) ?? String(input.name));
3905
- const descRaw = input.description;
3906
- const descStr = descRaw == null ? undefined : typeof descRaw === 'string' ? descRaw : this.translationService.resolve(descRaw);
3907
- if (input.dataType != null && input.interface != null) {
3908
- return {
3909
- name: input.name,
3910
- title: titleStr,
3911
- description: descStr,
3912
- schema: {
3913
- dataType: input.dataType,
3914
- interface: input.interface,
3915
- },
3916
- validations: input.validations,
3917
- };
3918
- }
3919
- if (input.schema) {
3920
- return {
3921
- name: input.name,
3922
- title: titleStr,
3923
- description: descStr,
3924
- schema: input.schema,
3925
- validations: input.validations,
3926
- };
3927
- }
3928
- return {
3929
- name: input.name,
3930
- title: input.name,
3931
- description: descStr,
3932
- schema: { dataType: input.typeName || 'string', defaultValue: input.defaultValue },
3933
- validations: input.isRequired ? [{ rule: 'required' }] : undefined,
3934
- };
3935
- }
3936
- mapDefinitionOutputToWorkflowOutput(output) {
3937
- const titleRaw = output.title ?? output.name;
3938
- const titleStr = typeof titleRaw === 'string' ? titleRaw : (this.translationService.resolve(titleRaw) ?? String(output.name));
3939
- const descStr = output.description == null
3940
- ? undefined
3941
- : typeof output.description === 'string'
3942
- ? output.description
3943
- : this.translationService.resolve(output.description);
3944
- if (output.dataType != null && output.interface != null) {
3945
- return {
3946
- name: output.name,
3947
- title: titleStr,
3948
- description: descStr,
3949
- schema: { dataType: output.dataType, interface: output.interface },
3950
- path: output.path,
3951
- metadata: output.metadata,
3952
- };
3953
- }
3954
- if (output.schema) {
3955
- return {
3956
- name: output.name,
3957
- title: titleStr,
3958
- description: descStr,
3959
- schema: output.schema,
3960
- path: output.path,
3961
- metadata: output.metadata,
3962
- };
3963
- }
3964
- return {
3965
- name: output.name,
3966
- title: titleStr,
3967
- description: descStr,
3968
- schema: { dataType: output.typeName || 'string' },
3969
- };
3970
- }
3971
- convertActivityDefinitionToInfo(activity) {
3972
- const properties = (activity.inputs || []).map((input) => ({
3973
- name: input.name,
3974
- type: this.getPropertyTypeFromDataType(input.dataType),
3975
- required: !!input.validations?.some((v) => v.rule === 'required'),
3976
- description: this.translationService.resolve(input.description) ?? undefined,
3977
- defaultValue: undefined,
3978
- }));
3979
- const defaultProperties = {};
3980
- properties.forEach((prop) => {
3981
- if (prop.defaultValue !== undefined) {
3982
- defaultProperties[prop.name] = prop.defaultValue;
3983
- }
3984
- });
3985
- return {
3986
- type: activity.type,
3987
- name: activity.name,
3988
- description: this.translationService.resolve(activity.description) || '',
3989
- icon: this.normalizeActivityIcon(activity.icon),
3990
- properties,
3991
- defaultProperties,
3992
- };
3993
- }
3994
- /**
3995
- * Normalize FontAwesome icon: if missing style prefix (e.g. fa-light, fas), prepend 'fa-light ' so short values like 'fa-shield-alt' render.
3996
- */
3997
- normalizeActivityIcon(icon) {
3998
- if (!icon?.trim())
3999
- return 'fa-light fa-circle';
4000
- const trimmed = icon.trim();
4001
- const hasStylePrefix = /^(fa-light|fas|far|fal|fa-solid|fa-regular|fa-brands|fa-duotone)(\s|$)/i.test(trimmed);
4002
- return hasStylePrefix ? trimmed : `fa-light ${trimmed}`;
4003
- }
4004
- /**
4005
- * Map {@link AXPProperty.dataType} to visual editor property type.
4006
- */
4007
- getPropertyTypeFromDataType(dataType) {
4008
- if (dataType === 'array')
4009
- return 'array';
4010
- if (dataType === 'object')
4011
- return 'object';
4012
- if (dataType === 'boolean')
4013
- return 'boolean';
4014
- if (dataType === 'number' || dataType === 'integer')
4015
- return 'number';
4016
- if (dataType === 'blob')
4017
- return 'any';
4018
- return 'string';
4019
- }
4020
- /**
4021
- * Get category color
4022
- */
4023
- getCategoryColor(categoryId) {
4024
- const colorMap = {
4025
- 'workflow-markers': '#10B981',
4026
- 'control-flow': '#3B82F6',
4027
- 'user-interaction': '#8B5CF6',
4028
- data: '#10B981',
4029
- navigation: '#F59E0B',
4030
- events: '#EF4444',
4031
- http: '#06B6D4',
4032
- };
4033
- return colorMap[categoryId] || '#64748B';
4034
- }
4035
- /**
4036
- * Get empty workflow JSON
4037
- */
4038
- getEmptyWorkflow() {
4039
- return JSON.stringify({
4040
- id: 'new-workflow',
4041
- name: '',
4042
- description: '',
4043
- version: 1,
4044
- root: {
4045
- id: 'root',
4046
- type: 'workflow-activity:sequence',
4047
- name: 'Root',
4048
- children: [],
4049
- },
4050
- }, null, 2);
4051
- }
4052
- //#endregion
4053
- /**
4054
- * Sync visualizer with JSON changes
4055
- */
4056
- syncVisualizerWithJson() {
4057
- try {
4058
- if (this.activeTab() === 'visual') {
4059
- this.jsonToVisual();
4060
- }
4061
- }
4062
- catch (err) {
4063
- console.error('[WorkflowStudio] Error syncing visualizer:', err);
4064
- }
4065
- }
4066
- //#region ---- Workflow Execution ----
4067
- /**
4068
- * Open execution dialog
4069
- */
4070
- openExecutionDialog() {
4071
- this.showExecutionDialog.set(true);
4072
- this.workflowInstanceState.set(null);
4073
- }
4074
- /**
4075
- * Close execution dialog
4076
- */
4077
- closeExecutionDialog() {
4078
- this.showExecutionDialog.set(false);
4079
- this.workflowInstanceState.set(null);
4080
- }
4081
- /**
4082
- * Start workflow execution
4083
- */
4084
- async startWorkflowExecution() {
4085
- await this.runWorkflow();
4086
- }
4087
- /**
4088
- * اجرای workflow
4089
- */
4090
- async runWorkflow() {
4091
- this.isExecuting.set(true);
4092
- this.executionLogs.set([]);
4093
- this.workflowInstanceState.set({
4094
- status: 'running',
4095
- startTime: new Date(),
4096
- currentState: null,
4097
- });
4098
- this.addLog('info', 'شروع اجرای Workflow...');
4099
- try {
4100
- // Parse JSON
4101
- const workflowDef = JSON.parse(this.workflowJson());
4102
- const logMessage = await this.translationService.translateAsync('@workflow-management:test-pages.messages.info.json-parsed');
4103
- this.addLog('success', logMessage, workflowDef);
4104
- // Save workflow definition to entity service first
4105
- const workflowId = workflowDef.id || `workflow-${Date.now()}`;
4106
- const definitionToSave = this.exportWorkflowDefinition();
4107
- if (!definitionToSave) {
4108
- throw new Error('Failed to export workflow definition');
4109
- }
4110
- // Save or update workflow definition
4111
- try {
4112
- const existing = await this.entityService
4113
- .withEntity(RootConfig.module.name, RootConfig.entities.workflowDefinition.name)
4114
- .data()
4115
- .byKey(workflowId);
4116
- if (existing) {
4117
- await this.entityService
4118
- .withEntity(RootConfig.module.name, RootConfig.entities.workflowDefinition.name)
4119
- .data()
4120
- .update(workflowId, definitionToSave);
4121
- }
4122
- else {
4123
- await this.entityService
4124
- .withEntity(RootConfig.module.name, RootConfig.entities.workflowDefinition.name)
4125
- .data()
4126
- .create({ ...definitionToSave, id: workflowId });
4127
- }
4128
- const saveMessage = await this.translationService.translateAsync('@workflow-management:test-pages.messages.success.workflow-saved');
4129
- this.addLog('success', saveMessage);
4130
- }
4131
- catch (saveError) {
4132
- // Continue execution even if save fails
4133
- const saveErrorMessage = await this.translationService.translateAsync('@workflow-management:test-pages.messages.warning.save-failed');
4134
- this.addLog('warning', `${saveErrorMessage}: ${saveError.message}`);
4135
- }
4136
- // اجرای workflow
4137
- const executingMessage = await this.translationService.translateAsync('@workflow-management:test-pages.messages.info.executing');
4138
- this.addLog('info', executingMessage);
4139
- // Start workflow execution using the workflow name
4140
- const workflowName = definitionToSave.name || workflowId;
4141
- let result = await this.workflowManager.start(workflowName, {});
4142
- this.addLog('info', `Workflow started. Instance ID: ${result.instanceId}`, result);
4143
- if (!result.instanceId) {
4144
- this.addLog('error', '❌ Workflow با خطا مواجه شد', result);
4145
- return;
4146
- }
4147
- // Handle workflow execution loop - execute all frontend tasks
4148
- let currentResult = result;
4149
- let taskCount = 0;
4150
- while (currentResult.nextTask) {
4151
- taskCount++;
4152
- const task = currentResult.nextTask;
4153
- this.addLog('info', `📋 Task ${taskCount}: ${task.activityType} (${task.activityName || task.activityId})`, task);
4154
- try {
4155
- // Execute frontend task
4156
- this.addLog('info', `⚡ Executing task: ${task.activityType}...`);
4157
- // const { output, outcome } = await this.workflowManager.execute(task);
4158
- // this.addLog('success', `✅ Task executed. Outcome: ${outcome}`, { output, outcome });
4159
- // Complete task and get next
4160
- this.addLog('info', `🔄 Completing task and getting next...`);
4161
- // currentResult = await this.workflowManager.complete(
4162
- // currentResult.instanceId!,
4163
- // task,
4164
- // outcome,
4165
- // output
4166
- // );
4167
- if (!currentResult.instanceId) {
4168
- this.addLog('error', '❌ Task completion failed', currentResult);
4169
- break;
4170
- }
4171
- if (currentResult.nextTask) {
4172
- this.addLog('info', `➡️ Next task available: ${currentResult.nextTask.activityType}`);
4173
- }
4174
- else {
4175
- this.addLog('success', '✅ No more tasks. Workflow completed!');
4176
- }
4177
- }
4178
- catch (error) {
4179
- this.addLog('error', `❌ Error executing task: ${error.message}`, error);
4180
- currentResult = {
4181
- ...currentResult,
4182
- success: false,
4183
- error: error.message || 'Task execution failed',
4184
- };
4185
- break;
4186
- }
4187
- }
4188
- // نتیجه
4189
- this.workflowInstanceState.set({
4190
- status: 'finished',
4191
- finalResult: currentResult,
4192
- startTime: this.workflowInstanceState().startTime || new Date(),
4193
- endTime: new Date(),
4194
- result: currentResult,
4195
- currentState: currentResult.state?.output?.['taskStatus'] || currentResult.state?.output?.['currentState'],
4196
- });
4197
- if (currentResult.success) {
4198
- this.addLog('success', `✅ Workflow با موفقیت اجرا شد! (${taskCount} task(s) executed)`, currentResult);
4199
- }
4200
- else {
4201
- this.addLog('error', '❌ Workflow با خطا مواجه شد: ' + (currentResult.error || 'Unknown error'), currentResult);
4202
- }
4203
- }
4204
- catch (error) {
4205
- this.addLog('error', '❌ خطا در اجرای Workflow: ' + error.message, error);
4206
- this.workflowInstanceState.set({
4207
- status: 'error',
4208
- error: error.message,
4209
- startTime: this.workflowInstanceState().startTime,
4210
- });
4211
- }
4212
- finally {
4213
- this.isExecuting.set(false);
4214
- }
4215
- }
4216
- /**
4217
- * اضافه کردن لاگ
4218
- */
4219
- addLog(level, message, data) {
4220
- const logs = this.executionLogs();
4221
- logs.push({
4222
- timestamp: new Date(),
4223
- level,
4224
- message,
4225
- data,
4226
- });
4227
- this.executionLogs.set([...logs]);
4228
- }
4229
- /**
4230
- * کپی کردن نمونه activity
4231
- */
4232
- copyActivityTemplate(activity) {
4233
- const template = {
4234
- id: `${activity.type.toLowerCase()}-${Date.now()}`,
4235
- type: activity.type,
4236
- name: activity.name,
4237
- properties: {},
4238
- };
4239
- // کپی در کلیپ‌بورد
4240
- navigator.clipboard.writeText(JSON.stringify(template, null, 2));
4241
- this.addLog('success', `✂️ Template برای ${activity.name} کپی شد!`);
4242
- }
4243
- /**
4244
- * فرمت کردن JSON
4245
- */
4246
- formatJson() {
4247
- try {
4248
- const parsed = JSON.parse(this.workflowJson());
4249
- this.workflowJson.set(JSON.stringify(parsed, null, 2));
4250
- this.addLog('success', '✨ JSON فرمت شد');
4251
- }
4252
- catch (error) {
4253
- this.addLog('error', '❌ خطا در فرمت: ' + error.message);
4254
- }
4255
- }
4256
- /**
4257
- * Open workflow settings dialog built with Layout Builder (platform widgets / Acorex).
4258
- */
4259
- openWorkflowSettings() {
4260
- this.syncWorkflowSettingsFromJson();
4261
- const settings = this.workflowSettings();
4262
- const dialogContext = {
4263
- name: settings.name,
4264
- definitionId: settings.definitionId,
4265
- description: settings.description ?? '',
4266
- inputsJson: JSON.stringify(settings.inputs, null, 2),
4267
- outputsJson: JSON.stringify(settings.outputs, null, 2),
4268
- variablesJson: JSON.stringify(settings.variables, null, 2),
4269
- outcomesJson: Array.isArray(settings.outcomes) ? settings.outcomes.join(', ') : 'Done',
4270
- version: settings.version,
4271
- isLatest: settings.isLatest,
4272
- isPublished: settings.isPublished,
4273
- usableAsActivity: settings.usableAsActivity,
4274
- autoUpdateConsumingWorkflows: settings.autoUpdateConsumingWorkflows,
4275
- toolVersion: settings.toolVersion ?? '1.0.0',
4276
- providerName: settings.providerName ?? 'WorkflowStudio',
4277
- };
4278
- this.layoutBuilder
4279
- .create()
4280
- .dialog((dialog) => {
4281
- dialog
4282
- .setTitle('@workflow-management:workflow-studio.settings.title')
4283
- .setSize('lg')
4284
- .setCloseButton(true)
4285
- .setContext(dialogContext)
4286
- .content((flex) => {
4287
- flex
4288
- .setDirection('column')
4289
- .setGap('12px')
4290
- .fieldset((general) => {
4291
- general
4292
- .setTitle('@workflow-management:workflow-studio.settings.tabs.general')
4293
- .formField('@workflow-management:workflow-studio.settings.sections.general.fields.name.title', (field) => {
4294
- field.path('name');
4295
- field.textBox({
4296
- placeholder: '@workflow-management:workflow-studio.settings.sections.general.fields.name.placeholder',
4297
- });
4298
- })
4299
- .formField('@workflow-management:workflow-studio.settings.sections.general.fields.definition-id.title', (field) => {
4300
- field.path('definitionId');
4301
- field.textBox({
4302
- placeholder: '@workflow-management:workflow-studio.settings.sections.general.fields.definition-id.placeholder',
4303
- });
4304
- })
4305
- .formField('@workflow-management:workflow-studio.settings.sections.general.fields.description.title', (field) => {
4306
- field.path('description');
4307
- field.largeTextBox({
4308
- placeholder: '@workflow-management:workflow-studio.settings.sections.general.fields.description.placeholder',
4309
- rows: 4,
4310
- });
4311
- });
4312
- })
4313
- .fieldset((inputs) => {
4314
- inputs
4315
- .setTitle('@workflow-management:workflow-studio.settings.tabs.inputs')
4316
- .formField('@workflow-management:workflow-studio.settings.sections.inputs.fields.inputs-json', (field) => {
4317
- field.path('inputsJson');
4318
- field.largeTextBox({ rows: 12 });
4319
- });
4320
- })
4321
- .fieldset((outputs) => {
4322
- outputs
4323
- .setTitle('@workflow-management:workflow-studio.settings.tabs.outputs')
4324
- .formField('@workflow-management:workflow-studio.settings.sections.outputs.fields.outputs-json', (field) => {
4325
- field.path('outputsJson');
4326
- field.largeTextBox({ rows: 12 });
4327
- });
4328
- })
4329
- .fieldset((variables) => {
4330
- variables
4331
- .setTitle('@workflow-management:workflow-studio.settings.tabs.variables')
4332
- .formField('@workflow-management:workflow-studio.settings.sections.variables.fields.variables-json', (field) => {
4333
- field.path('variablesJson');
4334
- field.largeTextBox({ rows: 12 });
4335
- });
4336
- })
4337
- .fieldset((advanced) => {
4338
- advanced
4339
- .setTitle('@workflow-management:workflow-studio.settings.tabs.advanced')
4340
- .formField('@workflow-management:workflow-studio.settings.sections.advanced.fields.version', (field) => {
4341
- field.path('version');
4342
- field.numberBox({ min: 1 });
4343
- })
4344
- .formField('@workflow-management:workflow-studio.settings.sections.advanced.fields.is-latest', (field) => {
4345
- field.path('isLatest');
4346
- field.toggleSwitch();
4347
- })
4348
- .formField('@workflow-management:workflow-studio.settings.sections.advanced.fields.is-published', (field) => {
4349
- field.path('isPublished');
4350
- field.toggleSwitch();
4351
- })
4352
- .formField('@workflow-management:workflow-studio.settings.sections.advanced.fields.usable-as-activity', (field) => {
4353
- field.path('usableAsActivity');
4354
- field.toggleSwitch();
4355
- })
4356
- .formField('@workflow-management:workflow-studio.settings.sections.advanced.fields.auto-update-consuming', (field) => {
4357
- field.path('autoUpdateConsumingWorkflows');
4358
- field.toggleSwitch();
4359
- })
4360
- .formField('@workflow-management:workflow-studio.settings.sections.advanced.fields.tool-version', (field) => {
4361
- field.path('toolVersion');
4362
- field.textBox({ placeholder: '1.0.0' });
4363
- })
4364
- .formField('@workflow-management:workflow-studio.settings.sections.advanced.fields.provider-name', (field) => {
4365
- field.path('providerName');
4366
- field.textBox({ placeholder: 'WorkflowStudio' });
4367
- })
4368
- .formField('@workflow-management:workflow-studio.settings.sections.advanced.fields.outcomes-label', (field) => {
4369
- field.path('outcomesJson');
4370
- field.textBox({
4371
- placeholder: '@workflow-management:workflow-studio.settings.sections.advanced.fields.outcomes-placeholder',
4372
- });
4373
- });
4374
- });
4375
- })
4376
- .setActions((actions) => {
4377
- actions
4378
- .cancel('@workflow-management:workflow-studio.settings.actions.cancel')
4379
- .submit('@workflow-management:workflow-studio.settings.actions.save');
4380
- })
4381
- .onAction(async (dialogRef) => {
4382
- const action = dialogRef.action();
4383
- if (action === 'cancel')
4384
- return;
4385
- const ctx = dialogRef.context();
4386
- if (!ctx)
4387
- return;
4388
- let inputs = [];
4389
- let outputs = [];
4390
- let variables = [];
4391
- let outcomes = ['Done'];
4392
- try {
4393
- if (typeof ctx.inputsJson === 'string' && ctx.inputsJson.trim()) {
4394
- inputs = JSON.parse(ctx.inputsJson);
4395
- }
4396
- }
4397
- catch {
4398
- this.addLog('error', 'Invalid inputs JSON');
4399
- }
4400
- try {
4401
- if (typeof ctx.outputsJson === 'string' && ctx.outputsJson.trim()) {
4402
- outputs = JSON.parse(ctx.outputsJson);
4403
- }
4404
- }
4405
- catch {
4406
- this.addLog('error', 'Invalid outputs JSON');
4407
- }
4408
- try {
4409
- if (typeof ctx.variablesJson === 'string' && ctx.variablesJson.trim()) {
4410
- variables = JSON.parse(ctx.variablesJson);
4411
- }
4412
- }
4413
- catch {
4414
- this.addLog('error', 'Invalid variables JSON');
4415
- }
4416
- if (typeof ctx.outcomesJson === 'string' && ctx.outcomesJson.trim()) {
4417
- outcomes = ctx.outcomesJson
4418
- .split(',')
4419
- .map((s) => s.trim())
4420
- .filter(Boolean);
4421
- }
4422
- if (outcomes.length === 0)
4423
- outcomes = ['Done'];
4424
- const newSettings = {
4425
- definitionId: String(ctx.definitionId ?? ''),
4426
- name: String(ctx.name ?? ''),
4427
- description: String(ctx.description ?? ''),
4428
- inputs,
4429
- outputs,
4430
- variables,
4431
- outcomes,
4432
- version: Number(ctx.version) || 1,
4433
- isLatest: Boolean(ctx.isLatest),
4434
- isPublished: Boolean(ctx.isPublished),
4435
- usableAsActivity: Boolean(ctx.usableAsActivity),
4436
- autoUpdateConsumingWorkflows: Boolean(ctx.autoUpdateConsumingWorkflows),
4437
- toolVersion: String(ctx.toolVersion ?? '1.0.0'),
4438
- providerName: String(ctx.providerName ?? 'WorkflowStudio'),
4439
- };
4440
- this.workflowSettings.set(newSettings);
4441
- this.applyWorkflowSettingsToJson();
4442
- });
4443
- })
4444
- .show();
4445
- }
4446
- /**
4447
- * Sync workflowSettings from current workflow JSON (used before opening settings dialog).
4448
- */
4449
- syncWorkflowSettingsFromJson() {
4450
- try {
4451
- const workflow = JSON.parse(this.workflowJson());
4452
- this.workflowSettings.set({
4453
- definitionId: workflow.definitionId || workflow.id || '',
4454
- name: workflow.name || '',
4455
- description: this.resolveWorkflowDefinitionDescription(workflow),
4456
- inputs: (workflow.inputs || []).map((input) => this.mapDefinitionInputToWorkflowInput(input)),
4457
- outputs: (workflow.outputs || []).map((output) => this.mapDefinitionOutputToWorkflowOutput(output)),
4458
- variables: workflow.variables || [],
4459
- outcomes: workflow.outcomes || ['Done'],
4460
- usableAsActivity: workflow.options?.usableAsActivity || false,
4461
- autoUpdateConsumingWorkflows: workflow.options?.autoUpdateConsumingWorkflows || false,
4462
- version: workflow.version || 1,
4463
- isLatest: workflow.isLatest !== undefined ? workflow.isLatest : true,
4464
- isPublished: workflow.isPublished || false,
4465
- toolVersion: workflow.toolVersion || '1.0.0',
4466
- providerName: workflow.providerName || 'WorkflowStudio',
4467
- });
4468
- }
4469
- catch {
4470
- this.workflowSettings.set({
4471
- definitionId: '',
4472
- name: '',
4473
- description: '',
4474
- inputs: [],
4475
- outputs: [],
4476
- variables: [],
4477
- outcomes: ['Done'],
4478
- usableAsActivity: false,
4479
- autoUpdateConsumingWorkflows: false,
4480
- version: 1,
4481
- isLatest: true,
4482
- isPublished: false,
4483
- toolVersion: '1.0.0',
4484
- providerName: 'WorkflowStudio',
4485
- });
4486
- }
4487
- }
4488
- /**
4489
- * Apply current workflowSettings to workflow JSON (used after saving from dialog).
4490
- */
4491
- applyWorkflowSettingsToJson() {
4492
- try {
4493
- const workflow = JSON.parse(this.workflowJson());
4494
- const settings = this.workflowSettings();
4495
- workflow.definitionId = settings.definitionId;
4496
- workflow.name = settings.name;
4497
- workflow.description = settings.description;
4498
- workflow.version = settings.version;
4499
- workflow.isLatest = settings.isLatest;
4500
- workflow.isPublished = settings.isPublished;
4501
- workflow.toolVersion = settings.toolVersion;
4502
- workflow.providerName = settings.providerName;
4503
- workflow.options = {
4504
- usableAsActivity: settings.usableAsActivity,
4505
- autoUpdateConsumingWorkflows: settings.autoUpdateConsumingWorkflows,
4506
- };
4507
- workflow.variables = settings.variables.map((v) => ({
4508
- id: v.name,
4509
- name: v.name,
4510
- typeName: v.typeName,
4511
- value: v.value,
4512
- storageDriverType: 'Memory',
4513
- }));
4514
- workflow.inputs = settings.inputs.map((i) => ({
4515
- name: i.name,
4516
- title: i.title,
4517
- description: i.description,
4518
- dataType: i.schema.dataType,
4519
- interface: i.schema.interface ?? { type: 'text-editor', options: {} },
4520
- validations: i.validations,
4521
- }));
4522
- workflow.outputs = settings.outputs.map((o) => ({
4523
- name: o.name,
4524
- title: o.title,
4525
- description: o.description,
4526
- dataType: o.schema.dataType,
4527
- interface: o.schema.interface ?? { type: 'text-editor', options: {} },
4528
- path: o.path,
4529
- metadata: o.metadata,
4530
- }));
4531
- workflow.outcomes = settings.outcomes;
4532
- workflow.customProperties = workflow.customProperties || {};
4533
- workflow.isReadonly = false;
4534
- workflow.isSystem = false;
4535
- this.workflowJson.set(JSON.stringify(workflow, null, 2));
4536
- this.addLog('success', '✅ Workflow settings saved');
4537
- }
4538
- catch (error) {
4539
- this.addLog('error', '❌ Failed to save settings: ' + error?.message);
4540
- }
4541
- }
4542
- /**
4543
- * Export workflow به فرمت Elsa Workflow Definition v3.0.0
4544
- * https://elsaworkflows.io/schemas/workflow-definition/v3.0.0/schema.json
4545
- */
4546
- exportWorkflowDefinition() {
4547
- try {
4548
- const workflow = JSON.parse(this.workflowJson());
4549
- const settings = this.workflowSettings();
4550
- // Create Elsa Workflow Definition v3.0.0 structure
4551
- const definition = {
4552
- // VersionedEntity fields
4553
- id: workflow.id || this.generateId(),
4554
- version: settings.version,
4555
- isLatest: settings.isLatest,
4556
- isPublished: settings.isPublished,
4557
- // Identification fields
4558
- definitionId: settings.definitionId || workflow.id || this.generateId(),
4559
- name: settings.name || workflow.name || 'Untitled Workflow',
4560
- description: settings.description || this.resolveWorkflowDefinitionDescription(workflow),
4561
- toolVersion: settings.toolVersion || '3.0.0',
4562
- // Materialization fields
4563
- providerName: settings.providerName || 'ACoreX',
4564
- materializerContext: {
4565
- materializerName: 'Json',
4566
- // Store the root activity as JSON string
4567
- stringData: JSON.stringify(workflow.root),
4568
- },
4569
- // WorkflowCommon fields
4570
- options: {
4571
- usableAsActivity: settings.usableAsActivity || false,
4572
- autoUpdateConsumingWorkflows: settings.autoUpdateConsumingWorkflows || false,
4573
- },
4574
- // Variables array
4575
- variables: settings.variables.map((v) => ({
4576
- id: v.name,
4577
- name: v.name,
4578
- typeName: v.typeName,
4579
- value: v.value,
4580
- storageDriverType: 'Memory',
4581
- })),
4582
- // Inputs array (aligned with {@link AXPProperty})
4583
- inputs: settings.inputs.map((i) => ({
4584
- name: i.name,
4585
- title: i.title,
4586
- description: i.description,
4587
- dataType: i.schema.dataType,
4588
- interface: i.schema.interface ?? { type: 'text-editor', options: {} },
4589
- validations: i.validations || [],
4590
- })),
4591
- // Outputs array (aligned with {@link AXPWorkflowOutputProperty})
4592
- outputs: settings.outputs.map((o) => ({
4593
- name: o.name,
4594
- title: o.title,
4595
- description: o.description,
4596
- dataType: o.schema.dataType,
4597
- interface: o.schema.interface ?? { type: 'text-editor', options: {} },
4598
- path: o.path,
4599
- metadata: o.metadata,
4600
- })),
4601
- // Outcomes array
4602
- outcomes: settings.outcomes || ['Done'],
4603
- // Custom properties
4604
- customProperties: workflow.customProperties || {},
4605
- // Flags
4606
- isReadonly: false,
4607
- isSystem: false,
4608
- // Root activity (direct reference for Elsa compatibility)
4609
- root: workflow.root,
4610
- };
4611
- return definition;
4612
- }
4613
- catch (error) {
4614
- this.addLog('error', '❌ خطا در export: ' + error.message);
4615
- return null;
4616
- }
4617
- }
4618
- /**
4619
- * دانلود WorkflowDefinition به صورت JSON file
4620
- */
4621
- downloadWorkflowDefinition() {
4622
- const definition = this.exportWorkflowDefinition();
4623
- if (!definition)
4624
- return;
4625
- const blob = new Blob([JSON.stringify(definition, null, 2)], { type: 'application/json' });
4626
- const url = URL.createObjectURL(blob);
4627
- const link = document.createElement('a');
4628
- link.href = url;
4629
- link.download = `${definition.definitionId || 'workflow'}-v${definition.version}.json`;
4630
- link.click();
4631
- URL.revokeObjectURL(url);
4632
- this.addLog('success', `📥 Workflow Definition دانلود شد: ${link.download}`);
4633
- }
4634
- generateId() {
4635
- return `wf-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
4636
- }
4637
- // ============ Workflow Inputs Management ============
4638
- addWorkflowInput() {
4639
- const settings = this.workflowSettings();
4640
- settings.inputs.push({
4641
- name: `input${settings.inputs.length + 1}`,
4642
- title: `Input ${settings.inputs.length + 1}`,
4643
- description: '',
4644
- schema: {
4645
- dataType: 'string',
4646
- defaultValue: undefined,
4647
- interface: { type: 'text-editor', options: {} },
4648
- },
4649
- validations: undefined,
4650
- });
4651
- this.workflowSettings.set({ ...settings });
4652
- }
4653
- removeWorkflowInput(index) {
4654
- const settings = this.workflowSettings();
4655
- settings.inputs.splice(index, 1);
4656
- this.workflowSettings.set({ ...settings });
4657
- }
4658
- updateWorkflowInput(index, field, value) {
4659
- const settings = this.workflowSettings();
4660
- const input = settings.inputs[index];
4661
- if (field === 'schema') {
4662
- // For nested schema updates
4663
- input[field] = value;
4664
- }
4665
- else if (field.startsWith('schema.')) {
4666
- // For nested schema properties like 'schema.dataType'
4667
- const schemaField = field.replace('schema.', '');
4668
- if (!input.schema) {
4669
- input.schema = { dataType: 'string', interface: { type: 'text-editor', options: {} } };
4670
- }
4671
- input.schema[schemaField] = value;
4672
- }
4673
- else {
4674
- input[field] = value;
4675
- }
4676
- this.workflowSettings.set({ ...settings });
4677
- }
4678
- updateWorkflowInputSchema(index, schemaField, value) {
4679
- const settings = this.workflowSettings();
4680
- const input = settings.inputs[index];
4681
- if (!input.schema) {
4682
- input.schema = { dataType: 'string', interface: { type: 'text-editor', options: {} } };
4683
- }
4684
- input.schema[schemaField] = value;
4685
- this.workflowSettings.set({ ...settings });
4686
- }
4687
- updateWorkflowInputValidation(index, isRequired) {
4688
- const settings = this.workflowSettings();
4689
- const input = settings.inputs[index];
4690
- if (isRequired) {
4691
- if (!input.validations) {
4692
- input.validations = [];
4693
- }
4694
- if (!input.validations.some((v) => v.rule === 'required')) {
4695
- input.validations.push({ rule: 'required' });
4696
- }
4697
- }
4698
- else {
4699
- input.validations = input.validations?.filter((v) => v.rule !== 'required');
4700
- if (input.validations?.length === 0) {
4701
- input.validations = undefined;
4702
- }
4703
- }
4704
- this.workflowSettings.set({ ...settings });
4705
- }
4706
- getInputIsRequired(input) {
4707
- return input.validations?.some((v) => v.rule === 'required') ?? false;
4708
- }
4709
- // ============ Workflow Outputs Management ============
4710
- addWorkflowOutput() {
4711
- const settings = this.workflowSettings();
4712
- settings.outputs.push({
4713
- name: `output${settings.outputs.length + 1}`,
4714
- title: `Output ${settings.outputs.length + 1}`,
4715
- description: '',
4716
- schema: {
4717
- dataType: 'string',
4718
- },
4719
- });
4720
- this.workflowSettings.set({ ...settings });
4721
- }
4722
- removeWorkflowOutput(index) {
4723
- const settings = this.workflowSettings();
4724
- settings.outputs.splice(index, 1);
4725
- this.workflowSettings.set({ ...settings });
4726
- }
4727
- updateWorkflowOutput(index, field, value) {
4728
- const settings = this.workflowSettings();
4729
- const output = settings.outputs[index];
4730
- if (field.startsWith('schema.')) {
4731
- // For nested schema properties like 'schema.dataType'
4732
- const schemaField = field.replace('schema.', '');
4733
- if (!output.schema) {
4734
- output.schema = { dataType: 'string' };
4735
- }
4736
- output.schema[schemaField] = value;
4737
- }
4738
- else {
4739
- output[field] = value;
4740
- }
4741
- this.workflowSettings.set({ ...settings });
4742
- }
4743
- updateWorkflowOutputSchema(index, schemaField, value) {
4744
- const settings = this.workflowSettings();
4745
- const output = settings.outputs[index];
4746
- if (!output.schema) {
4747
- output.schema = { dataType: 'string' };
4748
- }
4749
- output.schema[schemaField] = value;
4750
- this.workflowSettings.set({ ...settings });
4751
- }
4752
- // ============ Workflow Variables Management ============
4753
- addWorkflowVariable() {
4754
- const settings = this.workflowSettings();
4755
- settings.variables.push({
4756
- name: `variable${settings.variables.length + 1}`,
4757
- typeName: 'string',
4758
- value: '',
4759
- description: '',
4760
- });
4761
- this.workflowSettings.set({ ...settings });
4762
- }
4763
- removeWorkflowVariable(index) {
4764
- const settings = this.workflowSettings();
4765
- settings.variables.splice(index, 1);
4766
- this.workflowSettings.set({ ...settings });
4767
- }
4768
- updateWorkflowVariable(index, field, value) {
4769
- const settings = this.workflowSettings();
4770
- settings.variables[index][field] = value;
4771
- this.workflowSettings.set({ ...settings });
4772
- }
4773
- /**
4774
- * به‌روزرسانی outcomes از string
4775
- */
4776
- updateOutcomes(outcomesString) {
4777
- const settings = this.workflowSettings();
4778
- settings.outcomes = outcomesString
4779
- .split(',')
4780
- .map((o) => o.trim())
4781
- .filter((o) => o.length > 0);
4782
- this.workflowSettings.set({ ...settings });
4783
- }
4784
- /**
4785
- * پاک کردن لاگ‌ها
4786
- */
4787
- clearLogs() {
4788
- this.executionLogs.set([]);
4789
- }
4790
- // ============ Visual Designer Methods ============
4791
- /**
4792
- * تغییر تب
4793
- */
4794
- switchTab(tab) {
4795
- if (tab === 'visual' && this.activeTab() === 'json') {
4796
- // تبدیل JSON به Visual
4797
- this.jsonToVisual();
4798
- }
4799
- else if (tab === 'json' && this.activeTab() === 'visual') {
4800
- // تبدیل Visual به JSON
4801
- this.visualToJson();
4802
- }
4803
- this.activeTab.set(tab);
4804
- }
4805
- /**
4806
- * انتخاب Node
4807
- */
4808
- selectNodeById(node) {
4809
- this.selectedNode.set(node);
4810
- }
4811
- /**
4812
- * Delete node from canvas (used from template to avoid event propagation).
4813
- */
4814
- deleteNodeFromCanvas(nodeId) {
4815
- this.deleteNode(nodeId);
4816
- }
4817
- /**
4818
- * حذف Node
4819
- */
4820
- deleteNode(nodeId) {
4821
- const nodes = this.visualNodes().filter((n) => n.id !== nodeId);
4822
- // حذف اتصالات به این نود
4823
- nodes.forEach((n) => {
4824
- n.connections = n.connections.filter((c) => c !== nodeId);
4825
- });
4826
- this.visualNodes.set(nodes);
4827
- if (this.selectedNode()?.id === nodeId) {
4828
- this.selectedNode.set(null);
4829
- }
4830
- this.addLog('info', `🗑️ Node حذف شد`);
4831
- }
4832
- /**
4833
- * اتصال دو Node با outcome مشخص
4834
- */
4835
- connectNodes(fromId, toId, outcome) {
4836
- const nodes = this.visualNodes();
4837
- const fromNodeIndex = nodes.findIndex((n) => n.id === fromId);
4838
- const toNode = nodes.find((n) => n.id === toId);
4839
- if (fromNodeIndex !== -1 && toNode) {
4840
- const fromNode = nodes[fromNodeIndex];
4841
- // Use outcome-based connections if available
4842
- if (outcome && fromNode.outcomes && fromNode.outcomes.length > 1) {
4843
- const outcomeConnections = fromNode.outcomeConnections || [];
4844
- // Check if this outcome already has a connection
4845
- const existingConnection = outcomeConnections.find((c) => c.outcome === outcome);
4846
- if (existingConnection) {
4847
- this.addLog('warning', `⚠️ Outcome "${outcome}" قبلاً متصل شده است`);
4848
- return;
4849
- }
4850
- // Add new outcome connection
4851
- const updatedNodes = [...nodes];
4852
- updatedNodes[fromNodeIndex] = {
4853
- ...fromNode,
4854
- outcomeConnections: [...outcomeConnections, { outcome, targetNodeId: toId }],
4855
- connections: [...fromNode.connections, toId], // Keep for backward compat
4856
- };
4857
- this.visualNodes.set(updatedNodes);
4858
- this.addLog('success', `🔗 ${fromNode.name} [${outcome}] → ${toNode.name}`);
4859
- }
4860
- else {
4861
- // Simple connection (no outcomes)
4862
- if (!fromNode.connections.includes(toId)) {
4863
- const updatedNodes = [...nodes];
4864
- updatedNodes[fromNodeIndex] = {
4865
- ...fromNode,
4866
- connections: [...fromNode.connections, toId],
4867
- };
4868
- this.visualNodes.set(updatedNodes);
4869
- this.addLog('success', `🔗 ${fromNode.name} متصل شد به ${toNode.name}`);
4870
- }
4871
- else {
4872
- this.addLog('warning', '⚠️ این اتصال از قبل وجود دارد');
4873
- }
4874
- }
4875
- }
4876
- else {
4877
- this.addLog('error', '❌ خطا در ایجاد اتصال');
4878
- }
4879
- }
4880
- /**
4881
- * قطع اتصال (با یا بدون outcome)
4882
- */
4883
- disconnectNodes(fromId, toId, outcome) {
4884
- const nodes = this.visualNodes();
4885
- const fromNodeIndex = nodes.findIndex((n) => n.id === fromId);
4886
- if (fromNodeIndex !== -1) {
4887
- const fromNode = nodes[fromNodeIndex];
4888
- const updatedNodes = [...nodes];
4889
- // Remove from outcome connections if specified
4890
- if (outcome && fromNode.outcomeConnections) {
4891
- updatedNodes[fromNodeIndex] = {
4892
- ...fromNode,
4893
- outcomeConnections: fromNode.outcomeConnections.filter((c) => !(c.outcome === outcome && c.targetNodeId === toId)),
4894
- connections: fromNode.connections.filter((c) => c !== toId),
4895
- };
4896
- }
4897
- else {
4898
- // Simple disconnect
4899
- updatedNodes[fromNodeIndex] = {
4900
- ...fromNode,
4901
- connections: fromNode.connections.filter((c) => c !== toId),
4902
- outcomeConnections: fromNode.outcomeConnections?.filter((c) => c.targetNodeId !== toId),
4903
- };
4904
- }
4905
- this.visualNodes.set(updatedNodes);
4906
- this.addLog('info', `✂️ اتصال قطع شد${outcome ? ` [${outcome}]` : ''}`);
4907
- }
4908
- }
4909
- /**
4910
- * تبدیل JSON به Visual
4911
- */
4912
- jsonToVisual() {
4913
- try {
4914
- const workflow = JSON.parse(this.workflowJson());
4915
- const nodes = [];
4916
- let yPos = 100;
4917
- // پردازش root activity
4918
- if (workflow.root) {
4919
- this.processActivityToNode(workflow.root, nodes, 100, yPos);
4920
- }
4921
- this.visualNodes.set(nodes);
4922
- this.addLog('success', '✅ JSON به Visual تبدیل شد');
4923
- }
4924
- catch (error) {
4925
- this.addLog('error', '❌ خطا در تبدیل: ' + error.message);
4926
- }
4927
- }
4928
- /**
4929
- * پردازش Activity به Node (recursive)
4930
- */
4931
- processActivityToNode(activity, nodes, x, y, parentId) {
4932
- const nodeId = activity.id || `${activity.type}-${Date.now()}-${Math.random()}`;
4933
- // Get outcomes for this activity type (use default for now, will be updated async if needed)
4934
- const outcomes = ['Done']; // Default outcome, will be updated when activity info is loaded
4935
- // Get outcomeConnections from activity definition
4936
- const outcomeConnections = activity.outcomeConnections || [];
4937
- // Build simple connections list from outcomeConnections for backward compatibility
4938
- const connections = outcomeConnections.map((conn) => conn.targetNodeId);
4939
- const node = {
4940
- id: nodeId,
4941
- type: activity.type,
4942
- name: activity.name || activity.type,
4943
- icon: this.getIconForActivityType(activity.type),
4944
- properties: activity.properties || {},
4945
- position: { x, y },
4946
- connections: connections,
4947
- outcomeConnections: outcomeConnections,
4948
- outcomes: outcomes,
4949
- };
4950
- nodes.push(node);
4951
- // اگر parent دارد، اتصال برقرار کن (برای Sequence)
4952
- if (parentId && !outcomeConnections.length) {
4953
- const parentNode = nodes.find((n) => n.id === parentId);
4954
- if (parentNode && !parentNode.connections.includes(nodeId)) {
4955
- parentNode.connections.push(nodeId);
4956
- }
4957
- }
4958
- // پردازش children (برای Sequence) - اما فقط اگر outcomeConnections نباشد
4959
- if (activity.children && Array.isArray(activity.children) && !outcomeConnections.length) {
4960
- let childY = y;
4961
- activity.children.forEach((child, index) => {
4962
- childY = y + index * 100;
4963
- this.processActivityToNode(child, nodes, x + 250, childY, nodeId);
4964
- });
4965
- }
4966
- return nodeId;
4967
- }
4968
- /**
4969
- * تبدیل Visual به JSON
4970
- */
4971
- visualToJson() {
4972
- try {
4973
- const nodes = this.visualNodes();
4974
- if (nodes.length === 0) {
4975
- this.addLog('warning', '⚠️ هیچ Node ای وجود ندارد');
4976
- return;
4977
- }
4978
- // پیدا کردن root node (node بدون parent)
4979
- const rootNode = this.findRootNode(nodes);
4980
- if (!rootNode) {
4981
- this.addLog('error', '❌ Root Node پیدا نشد');
4982
- return;
4983
- }
4984
- const workflow = {
4985
- id: 'visual-workflow-' + Date.now(),
4986
- name: 'Visual Workflow',
4987
- version: 1,
4988
- root: this.nodeToActivity(rootNode, nodes),
4989
- };
4990
- this.workflowJson.set(JSON.stringify(workflow, null, 2));
4991
- this.addLog('success', '✅ Visual به JSON تبدیل شد');
4992
- }
4993
- catch (error) {
4994
- this.addLog('error', '❌ خطا در تبدیل: ' + error.message);
4995
- }
4996
- }
4997
- /**
4998
- * پیدا کردن Root Node
4999
- */
5000
- findRootNode(nodes) {
5001
- // Node ای که به آن اشاره نشده
5002
- const connectedIds = new Set();
5003
- nodes.forEach((n) => n.connections.forEach((c) => connectedIds.add(c)));
5004
- const rootNodes = nodes.filter((n) => !connectedIds.has(n.id));
5005
- return rootNodes[0] || nodes[0];
5006
- }
5007
- /**
5008
- * تبدیل Node به Activity (recursive)
5009
- */
5010
- nodeToActivity(node, allNodes) {
5011
- const activity = {
5012
- id: node.id,
5013
- type: node.type,
5014
- name: node.name,
5015
- properties: node.properties,
5016
- };
5017
- // اگر children دارد (connections)
5018
- if (node.connections.length > 0) {
5019
- const children = node.connections
5020
- .map((connId) => allNodes.find((n) => n.id === connId))
5021
- .filter((n) => n !== undefined)
5022
- .map((childNode) => this.nodeToActivity(childNode, allNodes));
5023
- if (children.length > 0) {
5024
- activity.children = children;
5025
- }
5026
- }
5027
- return activity;
5028
- }
5029
- /**
5030
- * دریافت آیکون برای نوع Activity
5031
- */
5032
- getIconForActivityType(type) {
5033
- const iconMap = {
5034
- 'workflow-activity:sequence': 'fa-light fa-list-ol',
5035
- 'workflow-activity:show-confirm-dialog': 'fa-light fa-question-circle',
5036
- 'workflow-activity:show-alert-dialog': 'fa-light fa-circle-info',
5037
- 'workflow-activity:show-toast': 'fa-light fa-bell',
5038
- 'workflow-activity:set-variable': 'fa-light fa-variable',
5039
- 'workflow-activity:navigate': 'fa-light fa-route',
5040
- 'workflow-activity:dispatch-event': 'fa-light fa-paper-plane',
5041
- 'workflow-activity:entity-create': 'fa-light fa-plus',
5042
- 'workflow-activity:entity-read': 'fa-light fa-book-open',
5043
- 'workflow-activity:entity-update': 'fa-light fa-pen',
5044
- 'workflow-activity:entity-delete': 'fa-light fa-trash',
5045
- 'workflow-activity:human-task': 'fa-light fa-user-check',
5046
- 'workflow-activity:cartable': 'fa-light fa-inbox',
5047
- };
5048
- return iconMap[type] || 'fa-light fa-circle';
5049
- }
5050
- /**
5051
- * به‌روزرسانی property نود
5052
- */
5053
- updateNodeProperty(nodeId, propertyName, value) {
5054
- const nodes = this.visualNodes();
5055
- const nodeIndex = nodes.findIndex((n) => n.id === nodeId);
5056
- if (nodeIndex !== -1) {
5057
- const node = nodes[nodeIndex];
5058
- const updatedNodes = [...nodes];
5059
- if (propertyName === 'name') {
5060
- updatedNodes[nodeIndex] = {
5061
- ...node,
5062
- name: value,
5063
- };
5064
- }
5065
- else {
5066
- const newProperties = {
5067
- ...node.properties,
5068
- [propertyName]: value,
5069
- };
5070
- let newOutcomes = node.outcomes;
5071
- const shouldRecomputeOutcomes = (propertyName === 'expectedStatusCodes' && node.type === 'workflow-activity:http-request') ||
5072
- (propertyName === 'actions' &&
5073
- (node.type === 'workflow-activity:human-task' || node.type === 'workflow-activity:cartable'));
5074
- if (shouldRecomputeOutcomes) {
5075
- this.findActivityInfo(node.type)
5076
- .then((activityInfo) => {
5077
- if (activityInfo) {
5078
- const computedOutcomes = this.computeOutcomes(activityInfo, newProperties);
5079
- const updatedNodes = this.visualNodes();
5080
- const nodeIdx = updatedNodes.findIndex((n) => n.id === nodeId);
5081
- if (nodeIdx !== -1) {
5082
- updatedNodes[nodeIdx] = {
5083
- ...updatedNodes[nodeIdx],
5084
- outcomes: computedOutcomes,
5085
- };
5086
- this.visualNodes.set([...updatedNodes]);
5087
- this.addLog('info', `🔄 Outcomes updated: [${computedOutcomes.join(', ')}]`);
5088
- }
5089
- }
5090
- })
5091
- .catch(() => { });
5092
- }
5093
- updatedNodes[nodeIndex] = {
5094
- ...node,
5095
- properties: newProperties,
5096
- outcomes: newOutcomes,
5097
- };
5098
- }
5099
- this.visualNodes.set(updatedNodes);
5100
- if (this.selectedNode()?.id === nodeId) {
5101
- this.selectedNode.set(updatedNodes[nodeIndex]);
5102
- }
5103
- }
5104
- }
5105
- /**
5106
- * پیدا کردن activity info بر اساس type
5107
- */
5108
- async findActivityInfo(type) {
5109
- try {
5110
- const activity = await this.activityDefinitionService.getActivityByName(type);
5111
- if (activity) {
5112
- return this.convertActivityDefinitionToInfo(activity);
5113
- }
5114
- }
5115
- catch (error) {
5116
- console.warn(`Failed to find activity info for type: ${type}`, error);
5117
- }
5118
- return null;
5119
- }
5120
- /**
5121
- * پاک کردن همه نودها
5122
- */
5123
- clearCanvas() {
5124
- this.visualNodes.set([]);
5125
- this.selectedNode.set(null);
5126
- this.addLog('info', '🗑️ Canvas پاک شد');
5127
- }
5128
- /**
5129
- * Copy workflow Definition ID to clipboard (Elsa-style workflow info).
5130
- */
5131
- async copyDefinitionIdToClipboard() {
5132
- const id = this.workflowSettings().definitionId || 'new-workflow';
5133
- try {
5134
- if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {
5135
- await navigator.clipboard.writeText(id);
5136
- this.addLog('success', 'Definition ID copied to clipboard');
5137
- }
5138
- }
5139
- catch {
5140
- this.addLog('warning', 'Could not copy to clipboard');
5141
- }
5142
- }
5143
- /**
5144
- * Scroll canvas area so content is centered (Elsa-style "Center").
5145
- */
5146
- canvasCenter() {
5147
- const el = this.canvasAreaRef()?.nativeElement;
5148
- if (!el)
5149
- return;
5150
- const nodes = this.visualNodes();
5151
- if (nodes.length === 0)
5152
- return;
5153
- let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
5154
- for (const n of nodes) {
5155
- minX = Math.min(minX, n.position.x);
5156
- minY = Math.min(minY, n.position.y);
5157
- maxX = Math.max(maxX, n.position.x + 150);
5158
- maxY = Math.max(maxY, n.position.y + 120);
5159
- }
5160
- const cx = (minX + maxX) / 2;
5161
- const cy = (minY + maxY) / 2;
5162
- const parent = el.parentElement;
5163
- if (parent && parent.scrollWidth > parent.clientWidth) {
5164
- parent.scrollLeft = Math.max(0, cx - parent.clientWidth / 2);
5165
- }
5166
- if (parent && parent.scrollHeight > parent.clientHeight) {
5167
- parent.scrollTop = Math.max(0, cy - parent.clientHeight / 2);
5168
- }
5169
- }
5170
- /**
5171
- * Scroll canvas so all nodes are in view (Elsa-style "Zoom to fit" – fit by scroll).
5172
- */
5173
- canvasZoomToFit() {
5174
- const el = this.canvasAreaRef()?.nativeElement;
5175
- if (!el)
5176
- return;
5177
- const nodes = this.visualNodes();
5178
- if (nodes.length === 0)
5179
- return;
5180
- let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
5181
- for (const n of nodes) {
5182
- minX = Math.min(minX, n.position.x);
5183
- minY = Math.min(minY, n.position.y);
5184
- maxX = Math.max(maxX, n.position.x + 150);
5185
- maxY = Math.max(maxY, n.position.y + 120);
5186
- }
5187
- const parent = el.parentElement;
5188
- if (parent) {
5189
- parent.scrollLeft = Math.max(0, minX - 24);
5190
- parent.scrollTop = Math.max(0, minY - 24);
5191
- }
5192
- }
5193
- /**
5194
- * Auto-arrange nodes in a vertical flow (Elsa-style "Auto layout").
5195
- */
5196
- canvasAutoLayout() {
5197
- const nodes = this.visualNodes();
5198
- if (nodes.length === 0)
5199
- return;
5200
- const root = this.findRootNode(nodes);
5201
- const ordered = [];
5202
- const visited = new Set();
5203
- const add = (n) => {
5204
- if (visited.has(n.id))
5205
- return;
5206
- visited.add(n.id);
5207
- ordered.push(n);
5208
- const targets = (n.outcomeConnections ?? [])
5209
- .map((c) => this.findNodeById(c.targetNodeId))
5210
- .filter(Boolean);
5211
- for (const t of targets)
5212
- add(t);
5213
- const fallback = (n.connections ?? []).map((id) => this.findNodeById(id)).filter(Boolean);
5214
- for (const t of fallback)
5215
- add(t);
5216
- };
5217
- if (root)
5218
- add(root);
5219
- for (const n of nodes)
5220
- if (!visited.has(n.id))
5221
- ordered.push(n);
5222
- const startX = 50;
5223
- const startY = 50;
5224
- const stepY = 120;
5225
- this.visualNodes.update((list) => list.map((node) => {
5226
- const idx = ordered.findIndex((o) => o.id === node.id);
5227
- const y = idx >= 0 ? startY + idx * stepY : node.position.y;
5228
- return { ...node, position: { x: startX, y } };
5229
- }));
5230
- this.addLog('info', 'Layout applied');
5231
- }
5232
- // ============ Drag & Drop Methods ============
5233
- /**
5234
- * شروع drag از activity list
5235
- */
5236
- onActivityDragStart(event, activity) {
5237
- this.draggedActivity = activity;
5238
- if (event.dataTransfer) {
5239
- event.dataTransfer.effectAllowed = 'copy';
5240
- event.dataTransfer.setData('text/plain', activity.type);
5241
- }
5242
- this.addLog('info', `🎯 در حال Drag: ${activity.name}`);
5243
- }
5244
- /**
5245
- * پایان drag از activity list
5246
- */
5247
- onActivityDragEnd(event) {
5248
- this.draggedActivity = null;
5249
- }
5250
- /**
5251
- * drag over روی Canvas
5252
- */
5253
- onCanvasDragOver(event) {
5254
- event.preventDefault();
5255
- if (event.dataTransfer) {
5256
- event.dataTransfer.dropEffect = 'copy';
5257
- }
5258
- }
5259
- /**
5260
- * drag leave از Canvas
5261
- */
5262
- onCanvasDragLeave(event) {
5263
- // می‌توان از این برای visual feedback استفاده کرد
5264
- }
5265
- /**
5266
- * محاسبه outcomes برای یک activity
5267
- */
5268
- computeOutcomes(activityInfo, properties) {
5269
- // For HTTP Request with expected status codes
5270
- if (activityInfo.type === 'workflow-activity:http-request' && properties['expectedStatusCodes']) {
5271
- const codes = Array.isArray(properties['expectedStatusCodes'])
5272
- ? properties['expectedStatusCodes']
5273
- : [properties['expectedStatusCodes']];
5274
- const statusOutcomes = codes.map((code) => code.toString());
5275
- return [...statusOutcomes, 'Done', 'Failed', 'Timeout'];
5276
- }
5277
- // Human task / cartable: outcomes from actions (prefix/suffix) in workflow definition
5278
- if ((activityInfo.type === 'workflow-activity:human-task' ||
5279
- activityInfo.type === 'workflow-activity:cartable') &&
5280
- properties['actions']) {
5281
- const names = [];
5282
- try {
5283
- const actions = properties['actions'];
5284
- const parsed = typeof actions === 'string' ? JSON.parse(actions) : actions;
5285
- const prefix = parsed?.prefix ?? [];
5286
- const suffix = parsed?.suffix ?? [];
5287
- for (const item of [...prefix, ...suffix]) {
5288
- const name = item?.command?.name ?? item?.name;
5289
- if (name && typeof name === 'string' && !names.includes(name))
5290
- names.push(name);
5291
- }
5292
- }
5293
- catch {
5294
- // ignore parse error
5295
- }
5296
- if (names.length > 0)
5297
- return names;
5298
- }
5299
- // Default: check activity info for outcomes
5300
- const outcomeMap = {
5301
- 'workflow-activity:if': ['Then', 'Else'],
5302
- 'workflow-activity:show-confirm-dialog': ['Confirmed', 'Cancelled'],
5303
- 'workflow-activity:show-alert-dialog': ['Done'],
5304
- 'workflow-activity:show-form': ['Submitted', 'Cancelled'],
5305
- 'workflow-activity:human-task': ['submit', 'cancel'],
5306
- 'workflow-activity:cartable': ['submit', 'cancel'],
5307
- 'workflow-activity:http-request': ['Done', 'Failed', 'Timeout'],
5308
- 'workflow-activity:sequence': ['Done'],
5309
- 'workflow-activity:for-each': ['Done'],
5310
- 'workflow-activity:while': ['Done'],
5311
- 'workflow-activity:set-variable': ['Done'],
5312
- 'workflow-activity:navigate': ['Done'],
5313
- 'workflow-activity:show-toast': ['Done'],
5314
- 'workflow-activity:dispatch-event': ['Done'],
5315
- 'workflow-activity:entity-create': ['Done', 'Failed'],
5316
- 'workflow-activity:entity-read': ['Done', 'NotFound', 'Failed'],
5317
- 'workflow-activity:entity-update': ['Done', 'Failed'],
5318
- 'workflow-activity:entity-delete': ['Done', 'Failed'],
5319
- };
5320
- return outcomeMap[activityInfo.type] || ['Done'];
5321
- }
5322
- /**
5323
- * drop روی Canvas - اضافه کردن activity جدید
5324
- */
5325
- onCanvasDrop(event) {
5326
- event.preventDefault();
5327
- if (!this.draggedActivity) {
5328
- return;
5329
- }
5330
- const canvas = event.currentTarget;
5331
- const rect = canvas.getBoundingClientRect();
5332
- const x = event.clientX - rect.left - 75; // center node
5333
- const y = event.clientY - rect.top - 40;
5334
- const nodes = this.visualNodes();
5335
- const defaultProps = { ...(this.draggedActivity.defaultProperties || {}) };
5336
- const newNode = {
5337
- id: `${this.draggedActivity.type}-${Date.now()}`,
5338
- type: this.draggedActivity.type,
5339
- name: this.draggedActivity.name,
5340
- icon: this.draggedActivity.icon,
5341
- properties: defaultProps,
5342
- position: { x: Math.max(0, x), y: Math.max(0, y) },
5343
- connections: [],
5344
- outcomeConnections: [],
5345
- outcomes: this.computeOutcomes(this.draggedActivity, defaultProps),
5346
- };
5347
- this.visualNodes.set([...nodes, newNode]);
5348
- const outcomesInfo = newNode.outcomes && newNode.outcomes.length > 1
5349
- ? ` with ${newNode.outcomes.length} outcomes [${newNode.outcomes.join(', ')}]`
5350
- : '';
5351
- this.addLog('success', `✅ Activity ${this.draggedActivity.name} اضافه شد${outcomesInfo}`);
5352
- this.draggedActivity = null;
5353
- }
5354
- /**
5355
- * شروع drag نود
5356
- */
5357
- onNodeDragStart(event, node) {
5358
- this.draggedNode = node;
5359
- const target = event.target;
5360
- const rect = target.getBoundingClientRect();
5361
- this.nodeDragOffset = {
5362
- x: event.clientX - rect.left,
5363
- y: event.clientY - rect.top,
5364
- };
5365
- if (event.dataTransfer) {
5366
- event.dataTransfer.effectAllowed = 'move';
5367
- // Make drag image transparent
5368
- const img = new Image();
5369
- img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
5370
- event.dataTransfer.setDragImage(img, 0, 0);
5371
- }
5372
- }
5373
- /**
5374
- * در حال drag نود
5375
- */
5376
- onNodeDrag(event, node) {
5377
- if (!this.draggedNode || event.clientX === 0 || event.clientY === 0) {
5378
- return;
5379
- }
5380
- const canvas = document.querySelector('.canvas-area');
5381
- if (!canvas)
5382
- return;
5383
- const rect = canvas.getBoundingClientRect();
5384
- const x = event.clientX - rect.left - this.nodeDragOffset.x;
5385
- const y = event.clientY - rect.top - this.nodeDragOffset.y;
5386
- const nodes = this.visualNodes();
5387
- const nodeIndex = nodes.findIndex((n) => n.id === node.id);
5388
- if (nodeIndex !== -1) {
5389
- nodes[nodeIndex].position = {
5390
- x: Math.max(0, x),
5391
- y: Math.max(0, y),
5392
- };
5393
- this.visualNodes.set([...nodes]);
5394
- }
5395
- }
5396
- /**
5397
- * پایان drag نود
5398
- */
5399
- onNodeDragEnd(event, node) {
5400
- this.draggedNode = null;
5401
- }
5402
- /**
5403
- * کلیک روی کانکتور - برای ایجاد اتصال (برای activities با یک outcome)
5404
- */
5405
- onConnectorClick(event, node, type) {
5406
- event.stopPropagation();
5407
- if (!this.connectionSource) {
5408
- // اولین کلیک - ذخیره source
5409
- if (type === 'out') {
5410
- this.connectionSource = { node, type };
5411
- this.addLog('info', `🔗 منبع اتصال انتخاب شد: ${node.name}`);
5412
- }
5413
- }
5414
- else {
5415
- // دومین کلیک - ایجاد اتصال
5416
- if (type === 'in' && this.connectionSource.node.id !== node.id) {
5417
- this.connectNodes(this.connectionSource.node.id, node.id, this.connectionSource.outcome);
5418
- this.connectionSource = null;
5419
- }
5420
- else {
5421
- this.addLog('warning', '⚠️ اتصال نامعتبر - ابتدا روی connector خروجی و سپس ورودی کلیک کنید');
5422
- this.connectionSource = null;
5423
- }
5424
- }
5425
- }
5426
- /**
5427
- * کلیک روی outcome connector - برای activities با چند outcome
5428
- */
5429
- onOutcomeConnectorClick(event, node, outcome) {
5430
- event.stopPropagation();
5431
- if (!this.connectionSource) {
5432
- // اولین کلیک - ذخیره source با outcome
5433
- this.connectionSource = { node, type: 'out', outcome };
5434
- this.addLog('info', `🔗 منبع اتصال انتخاب شد: ${node.name} [${outcome}]`);
5435
- }
5436
- else {
5437
- this.addLog('warning', '⚠️ لطفاً روی input connector یک نود دیگر کلیک کنید');
5438
- this.connectionSource = null;
5439
- }
5440
- }
5441
- // ============ UI Methods ============
5442
- /**
5443
- * تغییر وضعیت نمایش Properties Panel
5444
- */
5445
- togglePropertiesPanel() {
5446
- this.showPropertiesPanel.set(!this.showPropertiesPanel());
5447
- }
5448
- /**
5449
- * Build property viewer tabs from activity definition (platform widget-based).
5450
- * Used so the properties panel renders via the same widget system as the form builder.
5451
- */
5452
- buildPropertyViewerTabs(def, node) {
5453
- const generalGroup = { name: 'identity', title: 'General', order: 0 };
5454
- const inputGroup = { name: 'input-properties', title: 'Input Properties', order: 1 };
5455
- const outputGroup = { name: 'output', title: 'Output & Variables', order: 2 };
5456
- const identityProps = [
5457
- this.createReadOnlyStringProp('id', 'ID', 'id', generalGroup),
5458
- this.createReadOnlyStringProp('type', 'Type', 'type', generalGroup),
5459
- this.createStringProp('name', 'Name', 'name', generalGroup),
5460
- ];
5461
- const inputProps = (def?.inputs ?? []).map((input, index) => this.activityInputToWidgetProperty(input, inputGroup, index));
5462
- const outputProps = [
5463
- this.createStringProp('outputVariable', 'Output Variable', 'properties.outputVariable', outputGroup),
5464
- ];
5465
- const groups = [
5466
- { name: generalGroup.name, title: generalGroup.title, isCollapsed: false, props: identityProps },
5467
- ...(inputProps.length
5468
- ? [{ name: inputGroup.name, title: inputGroup.title, isCollapsed: false, props: inputProps }]
5469
- : []),
5470
- { name: outputGroup.name, title: outputGroup.title, isCollapsed: false, props: outputProps },
5471
- ];
5472
- return [{ name: 'general', title: 'General', groups }];
5473
- }
5474
- createStringProp(name, title, path, group) {
5475
- return {
5476
- name,
5477
- title,
5478
- group,
5479
- order: 0,
5480
- schema: {
5481
- dataType: 'string',
5482
- interface: {
5483
- path,
5484
- name,
5485
- type: 'text-editor',
5486
- options: {},
5487
- },
5488
- },
5489
- visible: true,
5490
- };
5491
- }
5492
- createReadOnlyStringProp(name, title, path, group) {
5493
- return {
5494
- name,
5495
- title,
5496
- group,
5497
- order: 0,
5498
- schema: {
5499
- dataType: 'string',
5500
- interface: {
5501
- path,
5502
- name,
5503
- type: 'text-editor',
5504
- options: { readonly: true },
5505
- },
5506
- },
5507
- visible: true,
5508
- };
5509
- }
5510
- activityInputToWidgetProperty(input, group, order) {
5511
- return mapAXPPropertyToWidgetProperty(input, {
5512
- group,
5513
- order,
5514
- valuePathPrefix: 'properties',
5515
- resolveTitle: (prop) => typeof prop.title === 'string' ? prop.title : (this.translationService.resolve(prop.title) ?? prop.name),
5516
- resolveDescription: (prop) => prop.description === undefined
5517
- ? undefined
5518
- : typeof prop.description === 'string'
5519
- ? prop.description
5520
- : this.translationService.resolve(prop.description),
5521
- });
5522
- }
5523
- /**
5524
- * Apply property viewer context changes back to the selected node.
5525
- */
5526
- onPropertyViewerChanged(ev) {
5527
- const node = this.selectedNode();
5528
- if (!node || ev.mode !== 'update')
5529
- return;
5530
- const v = ev.values;
5531
- if (v.name !== undefined)
5532
- this.updateNodeProperty(node.id, 'name', v.name);
5533
- if (v.properties && typeof v.properties === 'object') {
5534
- for (const key of Object.keys(v.properties)) {
5535
- this.updateNodeProperty(node.id, key, v.properties[key]);
5536
- }
5537
- }
5538
- }
5539
- // ============ Template Helper Methods ============
5540
- /**
5541
- * پیدا کردن Node با ID
5542
- */
5543
- findNodeById(nodeId) {
5544
- return this.visualNodes().find((n) => n.id === nodeId);
5545
- }
5546
- /**
5547
- * بررسی اینکه آیا properties خالی است یا نه
5548
- */
5549
- hasProperties(properties) {
5550
- return properties && Object.keys(properties).length > 0;
5551
- }
5552
- /**
5553
- * Builds SVG path for a curved connection (quadratic Bezier) so the line is smooth like Elsa/n8n.
5554
- * Control point is offset so the curve bows naturally between source and target.
5555
- */
5556
- getConnectionPath(x1, y1, x2, y2) {
5557
- const midX = (x1 + x2) / 2;
5558
- const midY = (y1 + y2) / 2;
5559
- const dy = y2 - y1;
5560
- const offset = Math.min(80, Math.max(40, Math.abs(dy) * 0.3));
5561
- const cpy = midY - (dy >= 0 ? offset : -offset);
5562
- return `M ${x1} ${y1} Q ${midX} ${cpy} ${x2} ${y2}`;
5563
- }
5564
- /**
5565
- * Approximate midpoint on the curve for label placement (quadratic Bezier t=0.5).
5566
- */
5567
- getConnectionLabelPosition(x1, y1, x2, y2) {
5568
- const midX = (x1 + x2) / 2;
5569
- const midY = (y1 + y2) / 2;
5570
- const dy = y2 - y1;
5571
- const offset = Math.min(80, Math.max(40, Math.abs(dy) * 0.3));
5572
- const cpy = midY - (dy >= 0 ? offset : -offset);
5573
- const t = 0.5;
5574
- const x = (1 - t) * (1 - t) * x1 + 2 * (1 - t) * t * midX + t * t * x2;
5575
- const y = (1 - t) * (1 - t) * y1 + 2 * (1 - t) * t * cpy + t * t * y2;
5576
- return { x, y: y + 12 };
5577
- }
5578
- /**
5579
- * دریافت رنگ بر اساس outcome
5580
- */
5581
- getOutcomeColor(outcome) {
5582
- const colorMap = {
5583
- '200': '#10b981', // Green - Success
5584
- Done: '#10b981', // Green - Success
5585
- Success: '#10b981', // Green - Success
5586
- '404': '#ef4444', // Red - Error
5587
- '500': '#ef4444', // Red - Error
5588
- Failed: '#ef4444', // Red - Error
5589
- Error: '#ef4444', // Red - Error
5590
- Timeout: '#f59e0b', // Orange - Warning
5591
- Cancelled: '#f59e0b', // Orange - Warning
5592
- Then: '#3b82f6', // Blue - Info
5593
- Else: '#64748b', // Gray
5594
- };
5595
- return colorMap[outcome] || '#8b5cf6'; // Purple - Default
5596
- }
5597
- /**
5598
- * Returns marker name for arrowhead def (success, error, warning, info, primary, default).
5599
- */
5600
- getOutcomeColorName(outcome) {
5601
- if (['200', 'Done', 'Success'].includes(outcome)) {
5602
- return 'success';
5603
- }
5604
- if (['404', '500', 'Failed', 'Error'].includes(outcome)) {
5605
- return 'error';
5606
- }
5607
- if (['Timeout', 'Cancelled'].includes(outcome)) {
5608
- return 'warning';
5609
- }
5610
- if (['Then'].includes(outcome)) {
5611
- return 'info';
5612
- }
5613
- if (['Else'].includes(outcome)) {
5614
- return 'default';
5615
- }
5616
- return 'primary'; // purple for custom outcomes
5617
- }
5618
- /**
5619
- * به‌روزرسانی property با parse کردن JSON
5620
- */
5621
- updateNodePropertyJSON(nodeId, propertyName, jsonString) {
5622
- try {
5623
- const value = JSON.parse(jsonString);
5624
- this.updateNodeProperty(nodeId, propertyName, value);
5625
- }
5626
- catch (error) {
5627
- // اگر JSON نامعتبر بود، چیزی نکن
5628
- console.warn('Invalid JSON:', jsonString);
5629
- }
5630
- }
5631
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WorkflowStudioComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
5632
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: WorkflowStudioComponent, isStandalone: true, selector: "app-workflow-studio", providers: [
5633
- {
5634
- provide: AXPPageLayoutBase,
5635
- useExisting: WorkflowStudioComponent,
5636
- },
5637
- ], viewQueries: [{ propertyName: "propertyViewerRef", first: true, predicate: AXPPropertyViewerComponent, descendants: true, isSignal: true }, { propertyName: "canvasAreaRef", first: true, predicate: ["canvasAreaRef"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout>\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>{{ '@workflow-management:activities.menus.activity-categories.title' | translate | async }}</axp-layout-title>\n <axp-layout-toolbar>\n <ax-search-box\n [delayTime]=\"300\"\n [placeholder]=\"'@workflow-management:workflow-studio.components.activity-categories-tree.search-placeholder' | translate | async\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n </axp-layout-toolbar>\n </axp-layout-header>\n <axp-layout-content>\n <axp-activity-categories-tree\n (categoryClick)=\"onCategoryClick($event)\"\n (activityClick)=\"onActivityClick($event)\"\n (activityDragStart)=\"onActivityDragStartFromTree($event)\"\n ></axp-activity-categories-tree>\n </axp-layout-content>\n </axp-layout-start-side>\n\n <axp-page-toolbar>\n <axp-layout-prefix>\n <!-- JSON / Visual toggle (same pattern as report view mode) -->\n <div class=\"studio-editor-tabs\">\n <ax-button-group class=\"ax-sm\" [selection]=\"'single'\">\n <ax-button-group-item (onClick)=\"switchTab('json')\" text=\"{{ '@workflow-management:workflow-studio.terms.json-editor' | translate | async }}\" [selected]=\"activeTab() === 'json'\">\n <ax-prefix>\n <i class=\"fa-light fa-code\"></i>\n </ax-prefix>\n </ax-button-group-item>\n <ax-button-group-item (onClick)=\"switchTab('visual')\" text=\"{{ '@workflow-management:workflow-studio.terms.visual-designer' | translate | async }}\" [selected]=\"activeTab() === 'visual'\">\n <ax-prefix>\n <i class=\"fa-light fa-diagram-project\"></i>\n </ax-prefix>\n </ax-button-group-item>\n </ax-button-group>\n </div>\n </axp-layout-prefix>\n </axp-page-toolbar>\n\n <axp-page-content>\n <div class=\"workflow-studio\">\n <!-- Main Layout -->\n <div class=\"studio-body\" [class.properties-hidden]=\"!showPropertiesPanel()\">\n\n <!-- Editor -->\n <div class=\"studio-editor\">\n <!-- Tab Content -->\n <div class=\"editor-content\">\n <!-- JSON Tab -->\n @if (activeTab() === 'json') {\n <div class=\"json-tab\">\n <textarea class=\"json-editor\" [value]=\"workflowJson()\"\n (input)=\"onWorkflowJsonInput($event)\"\n [placeholder]=\"'@workflow-management:workflow-studio.components.json-editor.placeholder' | translate | async\"\n spellcheck=\"false\"></textarea>\n </div>\n }\n\n <!-- Visual Tab -->\n @if (activeTab() === 'visual') {\n <div class=\"visual-tab\">\n <!-- Canvas -->\n <div class=\"visual-canvas\">\n <div class=\"canvas-toolbar\">\n <ax-button look=\"blank\" class=\"ax-sm\" [attr.title]=\"'@workflow-management:workflow-studio.components.canvas-toolbar.zoom-to-fit.title' | translate | async\" (onClick)=\"canvasZoomToFit()\">\n <ax-prefix><i class=\"fa-light fa-expand\"></i></ax-prefix>\n </ax-button>\n <ax-button look=\"blank\" class=\"ax-sm\" [attr.title]=\"'@workflow-management:workflow-studio.components.canvas-toolbar.center.title' | translate | async\" (onClick)=\"canvasCenter()\">\n <ax-prefix><i class=\"fa-light fa-crosshairs\"></i></ax-prefix>\n </ax-button>\n <ax-button look=\"blank\" class=\"ax-sm\" [attr.title]=\"'@workflow-management:workflow-studio.components.canvas-toolbar.auto-layout.title' | translate | async\" (onClick)=\"canvasAutoLayout()\">\n <ax-prefix><i class=\"fa-light fa-sitemap\"></i></ax-prefix>\n </ax-button>\n <span class=\"toolbar-sep\"></span>\n <label class=\"toolbar-auto-save\">\n <ax-switch [value]=\"autoSaveEnabled()\" (valueChange)=\"autoSaveEnabled.set($event)\"></ax-switch>\n <span>{{ '@workflow-management:workflow-studio.components.canvas-toolbar.auto-save' | translate | async }}</span>\n </label>\n <span class=\"toolbar-sep\"></span>\n <ax-button look=\"blank\" class=\"ax-sm\" [attr.title]=\"'@workflow-management:workflow-studio.components.canvas-toolbar.clear-canvas.title' | translate | async\" (onClick)=\"clearCanvas()\">\n <ax-prefix><i class=\"fa-light fa-trash\"></i></ax-prefix>\n </ax-button>\n <ax-button look=\"blank\" class=\"ax-sm\" [attr.title]=\"'@workflow-management:workflow-studio.components.canvas-toolbar.convert-to-json.title' | translate | async\" (onClick)=\"visualToJson()\">\n <ax-prefix><i class=\"fa-light fa-code\"></i></ax-prefix>\n </ax-button>\n <span class=\"tool-info\">\n <i class=\"fa-light fa-lightbulb\"></i>\n <strong>{{ '@workflow-management:workflow-studio.components.canvas-toolbar.hint' | translate | async }}</strong>\n </span>\n </div>\n\n <div #canvasAreaRef class=\"canvas-area\" (drop)=\"onCanvasDrop($event)\" (dragover)=\"onCanvasDragOver($event)\"\n (dragleave)=\"onCanvasDragLeave($event)\">\n <!-- SVG for Connections -->\n <svg class=\"connections-layer\">\n <!-- Outcome-based Connections -->\n @for (node of visualNodes(); track node.id) {\n @if (node.outcomeConnections && node.outcomeConnections.length > 0) {\n @for (conn of node.outcomeConnections; track conn.targetNodeId + conn.outcome) {\n @let targetNode = findNodeById(conn.targetNodeId);\n @if (targetNode) {\n <g class=\"outcome-connection-group\">\n <line [attr.x1]=\"node.position.x + 75\" [attr.y1]=\"node.position.y + 80\"\n [attr.x2]=\"targetNode.position.x + 75\" [attr.y2]=\"targetNode.position.y - 50\"\n class=\"connection-line outcome-line\" [attr.stroke]=\"getOutcomeColor(conn.outcome)\"\n stroke-width=\"2.5\"\n [attr.marker-end]=\"'url(#arrowhead-' + getOutcomeColorName(conn.outcome) + ')'\"\n style=\"cursor: pointer\" (dblclick)=\"disconnectNodes(node.id, conn.targetNodeId, conn.outcome)\"\n [attr.title]=\"'Outcome: ' + conn.outcome + ' (Double-click to remove)'\">\n <title>{{ conn.outcome }} \u00E2\u2020\u2019 {{ targetNode.name }}</title>\n </line>\n <text [attr.x]=\"(node.position.x + targetNode.position.x) / 2 + 75\"\n [attr.y]=\"(node.position.y + targetNode.position.y) / 2 + 15\" class=\"connection-label\"\n text-anchor=\"middle\" dominant-baseline=\"middle\" [attr.fill]=\"getOutcomeColor(conn.outcome)\" font-size=\"11\"\n font-weight=\"600\" pointer-events=\"none\">\n {{ conn.outcome }}\n </text>\n </g>\n }\n }\n } @else {\n <!-- Simple Connections (backward compatibility) -->\n @for (targetId of node.connections; track targetId) {\n @let targetNode = findNodeById(targetId);\n @if (targetNode) {\n @let sx = node.position.x + 75;\n @let sy = node.position.y + 40;\n @let tx = targetNode.position.x + 75;\n @let ty = targetNode.position.y - 50;\n @let pathD = getConnectionPath(sx, sy, tx, ty);\n <g class=\"connection-group\">\n <path [attr.d]=\"pathD\" class=\"connection-line connection-hit\" fill=\"none\" stroke=\"transparent\"\n stroke-width=\"16\" pointer-events=\"stroke\" (dblclick)=\"disconnectNodes(node.id, targetId)\">\n </path>\n <path [attr.d]=\"pathD\" class=\"connection-line\" fill=\"none\" stroke=\"#64748b\" stroke-width=\"2\"\n stroke-linecap=\"round\" marker-end=\"url(#arrowhead-default)\" pointer-events=\"none\">\n </path>\n <title>{{ '@workflow-management:workflow-studio.components.canvas-toolbar.connection-remove-hint' | translate | async }}</title>\n </g>\n }\n }\n }\n }\n\n <defs>\n <!-- Arrow markers: larger, rounded tip on line end (refX so tip touches path end) -->\n <marker id=\"arrowhead-default\" markerWidth=\"12\" markerHeight=\"12\" refX=\"10\" refY=\"4\" orient=\"auto\">\n <polygon points=\"0 0, 12 4, 0 8\" fill=\"#64748b\" />\n </marker>\n <marker id=\"arrowhead-primary\" markerWidth=\"12\" markerHeight=\"12\" refX=\"10\" refY=\"4\" orient=\"auto\">\n <polygon points=\"0 0, 12 4, 0 8\" fill=\"#8b5cf6\" />\n </marker>\n <marker id=\"arrowhead-success\" markerWidth=\"12\" markerHeight=\"12\" refX=\"10\" refY=\"4\" orient=\"auto\">\n <polygon points=\"0 0, 12 4, 0 8\" fill=\"#10b981\" />\n </marker>\n <marker id=\"arrowhead-error\" markerWidth=\"12\" markerHeight=\"12\" refX=\"10\" refY=\"4\" orient=\"auto\">\n <polygon points=\"0 0, 12 4, 0 8\" fill=\"#ef4444\" />\n </marker>\n <marker id=\"arrowhead-warning\" markerWidth=\"12\" markerHeight=\"12\" refX=\"10\" refY=\"4\" orient=\"auto\">\n <polygon points=\"0 0, 12 4, 0 8\" fill=\"#f59e0b\" />\n </marker>\n <marker id=\"arrowhead-info\" markerWidth=\"12\" markerHeight=\"12\" refX=\"10\" refY=\"4\" orient=\"auto\">\n <polygon points=\"0 0, 12 4, 0 8\" fill=\"#3b82f6\" />\n </marker>\n </defs>\n </svg>\n\n <!-- Nodes -->\n @for (node of visualNodes(); track node.id) {\n <div class=\"visual-node\" [class.selected]=\"selectedNode()?.id === node.id\"\n [style.left.px]=\"node.position.x\" [style.top.px]=\"node.position.y\" [attr.data-node-id]=\"node.id\"\n draggable=\"true\" (dragstart)=\"onNodeDragStart($event, node)\" (drag)=\"onNodeDrag($event, node)\"\n (dragend)=\"onNodeDragEnd($event, node)\" (click)=\"selectNodeById(node)\">\n <div class=\"node-header\">\n <i [class]=\"node.icon\"></i>\n <span>{{ node.name }}</span>\n <span class=\"node-delete-wrap\" (click)=\"$event.stopPropagation()\">\n <ax-button look=\"blank\" size=\"sm\" class=\"node-delete\" (onClick)=\"deleteNodeFromCanvas(node.id)\">\n <ax-prefix><i class=\"fa-light fa-times\"></i></ax-prefix>\n </ax-button>\n </span>\n </div>\n\n <div class=\"node-body\">\n <small>{{ node.type }}</small>\n </div>\n\n <div class=\"node-connectors\">\n <!-- Input Connector -->\n <div class=\"connector connector-in\" title=\"Input\" (click)=\"onConnectorClick($event, node, 'in')\">\n </div>\n\n <!-- Output Connectors - Multiple outcomes support -->\n @if (node.outcomes && node.outcomes.length > 1) {\n <!-- Multiple outcomes: show separate port for each -->\n <div class=\"outcomes-container\">\n @for (outcome of node.outcomes; track outcome; let idx = $index) {\n <div class=\"outcome-connector\" [class.active]=\"\n connectionSource?.node?.id === node.id && connectionSource?.outcome === outcome\n \" [attr.data-outcome]=\"outcome\" [title]=\"'Output: ' + outcome\"\n (click)=\"onOutcomeConnectorClick($event, node, outcome)\">\n <span class=\"outcome-label\">{{ outcome }}</span>\n <div class=\"outcome-dot\"></div>\n </div>\n }\n </div>\n } @else {\n <!-- Single outcome: show simple output connector -->\n <div class=\"connector connector-out\" [class.active]=\"connectionSource?.node?.id === node.id\"\n title=\"Output\" (click)=\"onConnectorClick($event, node, 'out')\"></div>\n }\n </div>\n </div>\n }\n\n <!-- Empty State -->\n @if (visualNodes().length === 0) {\n <div class=\"canvas-empty-state\">\n <i class=\"fa-light fa-diagram-project\"></i>\n <p>{{ '@workflow-management:workflow-studio.components.canvas-empty-state.title' | translate | async }}</p>\n <small>{{ '@workflow-management:workflow-studio.components.canvas-empty-state.description' | translate | async }}</small>\n </div>\n }\n </div>\n </div>\n\n <!-- Workflow Panel (when no node selected, Elsa-style) -->\n @if (!selectedNode() && showPropertiesPanel()) {\n <div class=\"properties-panel workflow-panel\">\n <div class=\"properties-header\">\n <i class=\"fa-light fa-diagram-project\"></i>\n <h4>{{ '@workflow-management:workflow-studio.components.workflow-panel.title' | translate | async }}</h4>\n <div class=\"header-actions\">\n <ax-button look=\"blank\" size=\"sm\" [title]=\"'@workflow-management:workflow-studio.components.properties-panel.actions.close-panel' | translate | async\" (onClick)=\"togglePropertiesPanel()\">\n <ax-prefix><i class=\"fa-light fa-angle-right\"></i></ax-prefix>\n </ax-button>\n </div>\n </div>\n <div class=\"properties-body\">\n <section class=\"workflow-panel-section\">\n <h5>{{ '@workflow-management:workflow-studio.components.workflow-panel.metadata' | translate | async }}</h5>\n <div class=\"property-row\">\n <label>{{ '@workflow-management:workflow-studio.components.workflow-panel.name' | translate | async }}</label>\n <ax-text-box class=\"form-input\" [value]=\"workflowSettings().name\" [disabled]=\"true\" />\n </div>\n <div class=\"property-row\">\n <label>{{ '@workflow-management:workflow-studio.components.workflow-panel.description' | translate | async }}</label>\n <ax-text-box class=\"form-input\" [value]=\"workflowSettings().description\" [disabled]=\"true\" />\n </div>\n </section>\n <div class=\"properties-divider\"></div>\n <section class=\"workflow-panel-section\">\n <h5>{{ '@workflow-management:workflow-studio.components.workflow-panel.information' | translate | async }}</h5>\n <div class=\"workflow-info-table\">\n <div class=\"workflow-info-row\">\n <span class=\"info-label\">{{ '@workflow-management:workflow-studio.components.workflow-panel.definition-id' | translate | async }}</span>\n <span class=\"info-actions\">\n <ax-button look=\"blank\" size=\"sm\" [title]=\"'@workflow-management:workflow-studio.components.workflow-panel.copy' | translate | async\" (onClick)=\"copyDefinitionIdToClipboard()\">\n <ax-prefix><i class=\"fa-light fa-copy\"></i></ax-prefix>\n </ax-button>\n </span>\n <span class=\"info-value\">{{ workflowSettings().definitionId || 'new-workflow' }}</span>\n </div>\n <div class=\"workflow-info-row\">\n <span class=\"info-label\">{{ '@workflow-management:workflow-studio.components.workflow-panel.version' | translate | async }}</span>\n <span class=\"info-value\">{{ workflowSettings().version }}</span>\n </div>\n <div class=\"workflow-info-row\">\n <span class=\"info-label\">{{ '@workflow-management:workflow-studio.components.workflow-panel.status' | translate | async }}</span>\n <span class=\"info-value\">{{ workflowSettings().isPublished ? ('@workflow-management:workflow-studio.components.workflow-panel.published' | translate | async) : ('@workflow-management:workflow-studio.components.workflow-panel.draft' | translate | async) }}</span>\n </div>\n <div class=\"workflow-info-row\">\n <span class=\"info-label\">{{ '@workflow-management:workflow-studio.components.workflow-panel.usable-as-activity' | translate | async }}</span>\n <span class=\"info-value\">{{ workflowSettings().usableAsActivity ? ('@general:terms.common.yes-no.yes' | translate | async) : ('@general:terms.common.yes-no.no' | translate | async) }}</span>\n </div>\n </div>\n </section>\n <p class=\"properties-hint\">{{ '@workflow-management:workflow-studio.components.workflow-panel.settings-hint' | translate | async }}</p>\n </div>\n </div>\n }\n\n <!-- Properties Panel (when a node is selected) -->\n @if (selectedNode() && showPropertiesPanel()) {\n <div class=\"properties-panel\">\n <div class=\"properties-header\">\n <i class=\"fa-light fa-sliders\"></i>\n <h4>{{ '@workflow-management:workflow-studio.components.properties-panel.title' | translate | async }}</h4>\n <div class=\"header-actions\">\n <ax-button look=\"blank\" size=\"sm\" [title]=\"'@workflow-management:workflow-studio.components.properties-panel.actions.close-panel' | translate | async\" (onClick)=\"togglePropertiesPanel()\">\n <ax-prefix><i class=\"fa-light fa-angle-right\"></i></ax-prefix>\n </ax-button>\n <ax-button look=\"blank\" size=\"sm\" [title]=\"'@workflow-management:workflow-studio.components.properties-panel.actions.close' | translate | async\" (onClick)=\"selectedNode.set(null)\">\n <ax-prefix><i class=\"fa-light fa-times\"></i></ax-prefix>\n </ax-button>\n </div>\n </div>\n <div class=\"properties-body\">\n @if (propertyViewerTabs().length > 0) {\n <div class=\"properties-widget-section\">\n <axp-property-viewer\n #propertyViewerRef\n [tabsInput]=\"propertyViewerTabs()\"\n [mode]=\"'simple'\"\n (onChanged)=\"onPropertyViewerChanged($event)\">\n </axp-property-viewer>\n </div>\n } @else {\n <div class=\"property-row\">\n <label>{{ '@workflow-management:workflow-studio.components.properties-panel.fields.id' | translate | async }}:</label>\n <ax-text-box class=\"form-input\" [value]=\"selectedNode()!.id\" [disabled]=\"true\" />\n </div>\n <div class=\"property-row\">\n <label>{{ '@workflow-management:workflow-studio.components.properties-panel.fields.type' | translate | async }}:</label>\n <ax-text-box class=\"form-input\" [value]=\"selectedNode()!.type\" [disabled]=\"true\" />\n </div>\n <div class=\"property-row\">\n <label>{{ '@workflow-management:workflow-studio.components.properties-panel.fields.name' | translate | async }}:</label>\n <ax-text-box class=\"form-input\" [value]=\"selectedNode()!.name\"\n (valueChange)=\"updateNodeProperty(selectedNode()!.id, 'name', $event)\" />\n </div>\n <p class=\"no-properties\">\n {{ '@workflow-management:workflow-studio.components.properties-panel.empty-states.no-properties' | translate | async }}\n </p>\n }\n\n <div class=\"properties-divider\"></div>\n\n\n <h5>\u00F0\u0178\u201D\u2014 {{ '@workflow-management:workflow-studio.components.properties-panel.sections.connections' | translate | async }}</h5>\n <small class=\"properties-hint\">{{ '@workflow-management:workflow-studio.components.properties-panel.sections.connections-hint' | translate | async }}</small>\n\n <!-- Outcome-based Connections -->\n @if (selectedNode()!.outcomeConnections && selectedNode()!.outcomeConnections!.length > 0) {\n <div class=\"connections-list\">\n @for (conn of selectedNode()!.outcomeConnections!; track conn.targetNodeId + conn.outcome) {\n @let targetNode = findNodeById(conn.targetNodeId);\n @if (targetNode) {\n <div class=\"connection-item outcome-connection\">\n <span class=\"outcome-badge\" [style.background]=\"getOutcomeColor(conn.outcome)\">\n {{ conn.outcome }}\n </span>\n <i class=\"fa-light fa-arrow-right\"></i>\n <span>{{ targetNode.name }}</span>\n <ax-button look=\"blank\" size=\"sm\" class=\"remove-btn\"\n [title]=\"'@workflow-management:workflow-studio.components.properties-panel.actions.remove-connection' | translate | async\"\n (onClick)=\"disconnectNodes(selectedNode()!.id, conn.targetNodeId, conn.outcome)\">\n <ax-prefix><i class=\"fa-light fa-times\"></i></ax-prefix>\n </ax-button>\n </div>\n }\n }\n </div>\n } @else if (selectedNode()!.connections.length > 0) {\n <!-- Simple Connections (fallback) -->\n <div class=\"connections-list\">\n @for (targetId of selectedNode()!.connections; track targetId) {\n @let targetNode = findNodeById(targetId);\n @if (targetNode) {\n <div class=\"connection-item\">\n <i class=\"fa-light fa-arrow-right\"></i>\n <span>{{ targetNode.name }}</span>\n <ax-button look=\"blank\" size=\"sm\" class=\"remove-btn\"\n [title]=\"'@workflow-management:workflow-studio.components.properties-panel.actions.remove-connection' | translate | async\"\n (onClick)=\"disconnectNodes(selectedNode()!.id, targetId)\">\n <ax-prefix><i class=\"fa-light fa-times\"></i></ax-prefix>\n </ax-button>\n </div>\n }\n }\n </div>\n } @else {\n <p class=\"no-properties\">{{ '@workflow-management:workflow-studio.components.properties-panel.empty-states.no-connections' | translate | async }}</p>\n }\n\n <!-- Available Outcomes Info -->\n @if (selectedNode()!.outcomes && selectedNode()!.outcomes!.length > 1) {\n <div class=\"properties-divider\"></div>\n <h5>\u00F0\u0178\u201C\u00A4 {{ '@workflow-management:workflow-studio.components.properties-panel.sections.available-outcomes' | translate | async }}</h5>\n <small class=\"properties-hint\">{{ '@workflow-management:workflow-studio.components.properties-panel.sections.available-outcomes-hint' | translate | async }}</small>\n <div class=\"outcomes-info\">\n @for (outcome of selectedNode()!.outcomes!; track outcome) {\n <span class=\"outcome-tag\" [style.borderColor]=\"getOutcomeColor(outcome)\">\n <span class=\"outcome-dot\" [style.background]=\"getOutcomeColor(outcome)\"></span>\n {{ outcome }}\n </span>\n }\n </div>\n }\n\n <div class=\"properties-divider\"></div>\n\n <h5>\u00F0\u0178\u201C\u009D {{ '@workflow-management:workflow-studio.components.properties-panel.sections.raw-json' | translate | async }}</h5>\n <pre class=\"properties-json\">{{ selectedNode() | json }}</pre>\n </div>\n </div>\n }\n\n <!-- Toggle Button for Properties (when closed) -->\n @if (!showPropertiesPanel()) {\n <ax-button look=\"blank\" class=\"sidebar-toggle-btn right\" (onClick)=\"togglePropertiesPanel()\"\n [title]=\"selectedNode() ? ('@workflow-management:workflow-studio.components.properties-panel.actions.show-panel' | translate | async) : ('@workflow-management:workflow-studio.components.workflow-panel.show-panel' | translate | async)\">\n <ax-prefix><i class=\"fa-light fa-sliders\"></i></ax-prefix>\n </ax-button>\n }\n </div>\n }\n </div>\n </div>\n\n </div>\n\n <!-- Workflow Settings: opened via Layout Builder dialog in openWorkflowSettings() -->\n\n <!-- Workflow Execution Dialog -->\n @if (showExecutionDialog()) {\n <div class=\"execution-dialog-overlay\" (click)=\"closeExecutionDialog()\">\n <div class=\"execution-dialog\" (click)=\"$event.stopPropagation()\">\n <!-- Dialog Header -->\n <div class=\"execution-dialog-header\">\n <div class=\"header-content\">\n <i class=\"fa-light fa-play-circle\"></i>\n <div class=\"header-info\">\n <h2>{{ '@workflow-management:test-pages.workflow-studio.actions.execute-workflow.title' | translate |\n async }}</h2>\n <p>{{ '@workflow-management:test-pages.workflow-studio.actions.execute-workflow.description' | translate\n | async }}</p>\n </div>\n </div>\n <ax-button look=\"blank\" size=\"sm\" class=\"close-btn\" [disabled]=\"isExecuting()\" (onClick)=\"closeExecutionDialog()\">\n <ax-prefix><i class=\"fa-light fa-times\"></i></ax-prefix>\n </ax-button>\n </div>\n\n <!-- Dialog Body -->\n <div class=\"execution-dialog-body\">\n <!-- Workflow Info Panel (Before Execution) -->\n @if (!workflowInstanceState()) {\n <div class=\"workflow-info-panel\">\n <div class=\"start-section\">\n <div class=\"start-illustration\">\n <i class=\"fa-light fa-rocket\"></i>\n </div>\n <h3>{{ '@workflow-management:test-pages.workflow-studio.messages.info.ready-to-execute' | translate |\n async }}</h3>\n <p>{{ '@workflow-management:test-pages.workflow-studio.messages.info.click-to-start' | translate | async\n }}</p>\n <ax-button\n [text]=\"'@workflow-management:test-pages.workflow-studio.actions.start-execution.title' | translate | async\"\n color=\"success\" size=\"lg\" (onClick)=\"startWorkflowExecution()\">\n </ax-button>\n </div>\n </div>\n }\n\n\n <!-- Custom UI for Registration -->\n @if (false) {\n <div class=\"registration-ui\">\n <div class=\"registration-card\">\n <div class=\"registration-icon\">\n <i class=\"fa-light fa-user-circle\"></i>\n </div>\n <h3>\u00D9\u0081\u00D8\u00B1\u00D8\u00A2\u00DB\u0152\u00D9\u2020\u00D8\u00AF \u00D8\u00AB\u00D8\u00A8\u00D8\u00AA\u00E2\u20AC\u0152\u00D9\u2020\u00D8\u00A7\u00D9\u2026</h3>\n <p class=\"registration-desc\">\n \u00D8\u00A7\u00DB\u0152\u00D9\u2020 \u00D9\u0081\u00D9\u201E\u00D9\u02C6 \u00D8\u00B4\u00D8\u00A7\u00D9\u2026\u00D9\u201E \u00DA\u2020\u00D9\u2020\u00D8\u00AF \u00D9\u2026\u00D8\u00B1\u00D8\u00AD\u00D9\u201E\u00D9\u2021 \u00D8\u00A7\u00D8\u00B3\u00D8\u00AA \u00DA\u00A9\u00D9\u2021 \u00D8\u00AF\u00D8\u00A7\u00D8\u00AF\u00D9\u2021\u00E2\u20AC\u0152\u00D9\u2021\u00D8\u00A7\u00DB\u0152 \u00DA\u00A9\u00D8\u00A7\u00D8\u00B1\u00D8\u00A8\u00D8\u00B1 \u00D8\u00B1\u00D8\u00A7 \u00D8\u00AC\u00D9\u2026\u00D8\u00B9\u00E2\u20AC\u0152\u00D8\u00A2\u00D9\u02C6\u00D8\u00B1\u00DB\u0152 \u00DA\u00A9\u00D8\u00B1\u00D8\u00AF\u00D9\u2021 \u00D9\u02C6 \u00D8\u00AF\u00D8\u00B1 \u00D9\u2020\u00D9\u2021\u00D8\u00A7\u00DB\u0152\u00D8\u00AA \u00D8\u00AD\u00D8\u00B3\u00D8\u00A7\u00D8\u00A8 \u00DA\u00A9\u00D8\u00A7\u00D8\u00B1\u00D8\u00A8\u00D8\u00B1\u00DB\u0152 \u00D8\u00A7\u00DB\u0152\u00D8\u00AC\u00D8\u00A7\u00D8\u00AF \u00D9\u2026\u00DB\u0152\u00E2\u20AC\u0152\u00DA\u00A9\u00D9\u2020\u00D8\u00AF.\n </p>\n\n @if (workflowInstanceState()?.status === 'running') {\n <div class=\"registration-progress\">\n <div class=\"progress-spinner\">\n <i class=\"fa-light fa-spinner-third fa-spin\"></i>\n </div>\n <p>\u00D8\u00AF\u00D8\u00B1 \u00D8\u00AD\u00D8\u00A7\u00D9\u201E \u00D8\u00A7\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7\u00DB\u0152 \u00D9\u2026\u00D8\u00B1\u00D8\u00A7\u00D8\u00AD\u00D9\u201E \u00D8\u00AB\u00D8\u00A8\u00D8\u00AA\u00E2\u20AC\u0152\u00D9\u2020\u00D8\u00A7\u00D9\u2026...</p>\n </div>\n }\n\n @if (workflowInstanceState()?.status === 'finished') {\n <div class=\"registration-success\">\n <i class=\"fa-light fa-check-circle\"></i>\n <h4>\u00D8\u00AB\u00D8\u00A8\u00D8\u00AA\u00E2\u20AC\u0152\u00D9\u2020\u00D8\u00A7\u00D9\u2026 \u00D8\u00A8\u00D8\u00A7 \u00D9\u2026\u00D9\u02C6\u00D9\u0081\u00D9\u201A\u00DB\u0152\u00D8\u00AA \u00D8\u00A7\u00D9\u2020\u00D8\u00AC\u00D8\u00A7\u00D9\u2026 \u00D8\u00B4\u00D8\u00AF!</h4>\n <p>\u00D8\u00AD\u00D8\u00B3\u00D8\u00A7\u00D8\u00A8 \u00DA\u00A9\u00D8\u00A7\u00D8\u00B1\u00D8\u00A8\u00D8\u00B1\u00DB\u0152 \u00D8\u00B4\u00D9\u2026\u00D8\u00A7 \u00D8\u00A7\u00DB\u0152\u00D8\u00AC\u00D8\u00A7\u00D8\u00AF \u00D8\u00B4\u00D8\u00AF \u00D9\u02C6 \u00D8\u00A8\u00D9\u2021 \u00D8\u00B2\u00D9\u02C6\u00D8\u00AF\u00DB\u0152 \u00D8\u00A8\u00D9\u2021 \u00D8\u00AF\u00D8\u00A7\u00D8\u00B4\u00D8\u00A8\u00D9\u02C6\u00D8\u00B1\u00D8\u00AF \u00D9\u2026\u00D9\u2020\u00D8\u00AA\u00D9\u201A\u00D9\u201E \u00D8\u00AE\u00D9\u02C6\u00D8\u00A7\u00D9\u2021\u00DB\u0152\u00D8\u00AF \u00D8\u00B4\u00D8\u00AF.</p>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Default Execution View -->\n @if (workflowInstanceState()) {\n <div class=\"default-execution-view\">\n <div class=\"execution-status\">\n @if (workflowInstanceState()?.status === 'running') {\n <div class=\"status-running\">\n <i class=\"fa-light fa-spinner-third fa-spin\"></i>\n <h3>\u00D8\u00AF\u00D8\u00B1 \u00D8\u00AD\u00D8\u00A7\u00D9\u201E \u00D8\u00A7\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7...</h3>\n <p>Workflow \u00D8\u00AF\u00D8\u00B1 \u00D8\u00AD\u00D8\u00A7\u00D9\u201E \u00D8\u00A7\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7 \u00D8\u00A7\u00D8\u00B3\u00D8\u00AA. \u00D9\u201E\u00D8\u00B7\u00D9\u0081\u00D8\u00A7\u00D9\u2039 \u00D8\u00B5\u00D8\u00A8\u00D8\u00B1 \u00DA\u00A9\u00D9\u2020\u00DB\u0152\u00D8\u00AF.</p>\n </div>\n }\n\n @if (workflowInstanceState()?.status === 'finished') {\n <div class=\"status-finished\">\n <i class=\"fa-light fa-check-circle\"></i>\n <h3>\u00D8\u00A7\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7 \u00D8\u00A8\u00D8\u00A7 \u00D9\u2026\u00D9\u02C6\u00D9\u0081\u00D9\u201A\u00DB\u0152\u00D8\u00AA \u00D8\u00AA\u00DA\u00A9\u00D9\u2026\u00DB\u0152\u00D9\u201E \u00D8\u00B4\u00D8\u00AF</h3>\n <p>Workflow \u00D8\u00A8\u00D8\u00A7 \u00D9\u2026\u00D9\u02C6\u00D9\u0081\u00D9\u201A\u00DB\u0152\u00D8\u00AA \u00D8\u00A7\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7 \u00D8\u00B4\u00D8\u00AF \u00D9\u02C6 \u00D8\u00AA\u00D9\u2026\u00D8\u00A7\u00D9\u2026 Activities \u00D8\u00A7\u00D9\u2020\u00D8\u00AC\u00D8\u00A7\u00D9\u2026 \u00D8\u00B4\u00D8\u00AF\u00D9\u2020\u00D8\u00AF.</p>\n </div>\n }\n\n @if (workflowInstanceState()?.status === 'error') {\n <div class=\"status-error\">\n <i class=\"fa-light fa-times-circle\"></i>\n <h3>\u00D8\u00AE\u00D8\u00B7\u00D8\u00A7 \u00D8\u00AF\u00D8\u00B1 \u00D8\u00A7\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7</h3>\n <p>{{ workflowInstanceState()?.error }}</p>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Execution Logs Panel -->\n @if (workflowInstanceState() && executionLogs().length > 0) {\n <div class=\"execution-logs-panel\">\n <h3><i class=\"fa-light fa-terminal\"></i> \u00D9\u201E\u00D8\u00A7\u00DA\u00AF\u00E2\u20AC\u0152\u00D9\u2021\u00D8\u00A7\u00DB\u0152 \u00D8\u00A7\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7</h3>\n <div class=\"logs-container-compact\">\n @for (log of executionLogs(); track $index) {\n <div class=\"log-item-compact\" [class]=\"'log-' + log.level\">\n <span class=\"log-time\">{{ log.timestamp | date: 'HH:mm:ss' }}</span>\n <span class=\"log-icon\">\n @switch (log.level) {\n @case ('info') {\n <i class=\"fa-light fa-info-circle\"></i>\n }\n @case ('success') {\n <i class=\"fa-light fa-check-circle\"></i>\n }\n @case ('warning') {\n <i class=\"fa-light fa-exclamation-triangle\"></i>\n }\n @case ('error') {\n <i class=\"fa-light fa-times-circle\"></i>\n }\n }\n </span>\n <span class=\"log-message\">{{ log.message }}</span>\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Dialog Footer -->\n <div class=\"execution-dialog-footer\">\n <div class=\"footer-info\">\n @if (workflowInstanceState()?.startTime) {\n <span class=\"time-info\">\n <i class=\"fa-light fa-clock\"></i>\n \u00D8\u00B4\u00D8\u00B1\u00D9\u02C6\u00D8\u00B9: {{ workflowInstanceState()!.startTime | date: 'HH:mm:ss' }}\n </span>\n }\n @if (workflowInstanceState()?.endTime) {\n <span class=\"time-info\">\n <i class=\"fa-light fa-flag-checkered\"></i>\n \u00D9\u00BE\u00D8\u00A7\u00DB\u0152\u00D8\u00A7\u00D9\u2020: {{ workflowInstanceState()!.endTime | date: 'HH:mm:ss' }}\n </span>\n }\n </div>\n <div class=\"footer-actions\">\n <ax-button\n [text]=\"(workflowInstanceState() ? '@general:actions.close.title' : '@general:actions.cancel.title') | translate | async\"\n color=\"secondary\" size=\"md\" [disabled]=\"isExecuting()\" (onClick)=\"closeExecutionDialog()\">\n </ax-button>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n </axp-page-content>\n</axp-page-layout>\n", styles: [".sidebar-header .toggle-btn{padding:.5rem;margin-left:auto;background:transparent;border:1px solid #e2e8f0;border-radius:6px;color:#64748b;cursor:pointer;transition:all .2s}.sidebar-header .toggle-btn:hover{background:#f8fafc;border-color:#8b5cf6;color:#8b5cf6}.sidebar-header .toggle-btn i{font-size:.875rem}.sidebar-toggle-btn{position:absolute;top:50%;transform:translateY(-50%);z-index:100;padding:1rem .5rem;background:#fff;border:1px solid #e2e8f0;border-radius:8px;color:#8b5cf6;cursor:pointer;box-shadow:0 4px 12px #0000001a;transition:all .3s}.sidebar-toggle-btn:hover{background:#8b5cf6;color:#fff;box-shadow:0 8px 24px #8b5cf64d;transform:translateY(-50%) scale(1.1)}.sidebar-toggle-btn.left{left:0;border-left:none;border-radius:0 8px 8px 0}.sidebar-toggle-btn.right{right:0;border-right:none;border-radius:8px 0 0 8px}.sidebar-toggle-btn i{font-size:1.25rem;display:block}.properties-header .header-actions{display:flex;gap:.5rem;margin-left:auto}.properties-header .header-btn{padding:.375rem .5rem;background:transparent;border:1px solid #e2e8f0;border-radius:4px;color:#64748b;cursor:pointer;transition:all .2s}.properties-header .header-btn:hover{background:#f8fafc;border-color:#8b5cf6;color:#8b5cf6}.properties-header .header-btn i{font-size:.75rem}.connections-list{margin-top:.75rem}.connection-item{display:flex;align-items:center;gap:.5rem;padding:.5rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;margin-bottom:.5rem;font-size:.875rem}.connection-item i{color:#8b5cf6}.connection-item span{flex:1;color:#1e293b}.connection-item .remove-btn{padding:.25rem .375rem;background:transparent;border:1px solid #e2e8f0;border-radius:4px;color:#ef4444;cursor:pointer;transition:all .2s}.connection-item .remove-btn:hover{background:#fef2f2;border-color:#ef4444}.connection-item .remove-btn i{font-size:.75rem;color:inherit}.property-editor{margin-top:.75rem}.property-editor .property-row label{display:flex;align-items:center;gap:.5rem;justify-content:space-between}.property-editor .property-row label .property-type-badge{padding:.125rem .375rem;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;font-size:.625rem;font-weight:400;color:#64748b;text-transform:lowercase;font-family:JetBrains Mono,monospace}.property-editor .property-row select{width:100%;padding:.5rem;border:1px solid #e2e8f0;border-radius:6px;font-size:.875rem;color:#1e293b;background:#fff;cursor:pointer;transition:all .2s}.property-editor .property-row select:focus{outline:none;border-color:#8b5cf6;box-shadow:0 0 0 3px #8b5cf61a}.property-editor .property-row textarea{width:100%;padding:.5rem;border:1px solid #e2e8f0;border-radius:6px;font-size:.75rem;font-family:JetBrains Mono,monospace;color:#1e293b;resize:vertical;transition:all .2s}.property-editor .property-row textarea:focus{outline:none;border-color:#8b5cf6;box-shadow:0 0 0 3px #8b5cf61a}.workflow-studio{display:flex;flex-direction:column;height:100vh;background:#f8fafc;overflow:hidden}.studio-editor-tabs ax-button-group-item[selected],.studio-editor-tabs ax-button-group-item.ax-selected{font-weight:600;opacity:1}.workflow-popup .popup-header{text-align:center;margin-bottom:1.5rem;padding-bottom:1rem;border-bottom:2px solid #e2e8f0}.workflow-popup .popup-header h3{margin:0 0 .5rem;color:#1e293b;font-size:1.5rem;font-weight:700}.workflow-popup .popup-header p{margin:0;color:#64748b;font-size:.95rem}.workflow-popup .popup-body{max-height:60vh;overflow-y:auto;padding:0 .5rem}.workflow-popup .popup-body h4{margin:1.5rem 0 .75rem;color:#374151;font-size:1.1rem;font-weight:600;display:flex;align-items:center;gap:.5rem}.workflow-popup .popup-body ul{margin:0;padding-left:1.5rem}.workflow-popup .popup-body ul li{margin-bottom:.5rem;color:#4b5563}.workflow-popup .popup-body ul li strong{color:#1f2937}.workflow-popup .workflow-info{background:#f8fafc;padding:1rem;border-radius:8px;border:1px solid #e2e8f0}.workflow-popup .workflow-variables{background:#fef3c7;padding:1rem;border-radius:8px;border:1px solid #f59e0b}.workflow-popup .workflow-flow{background:#ecfdf5;padding:1rem;border-radius:8px;border:1px solid #10b981}.workflow-popup .workflow-flow .flow-steps{display:flex;flex-direction:column;gap:.75rem}.workflow-popup .workflow-flow .flow-steps .flow-step{display:flex;align-items:center;gap:.75rem;padding:.5rem;background:#fff;border-radius:6px;border:1px solid #d1d5db}.workflow-popup .workflow-flow .flow-steps .flow-step .step-number{display:flex;align-items:center;justify-content:center;width:24px;height:24px;background:#3b82f6;color:#fff;border-radius:50%;font-size:.8rem;font-weight:600}.workflow-popup .workflow-flow .flow-steps .flow-step .step-text{color:#374151;font-weight:500}.workflow-popup .workflow-json{background:#1f2937;padding:1rem;border-radius:8px;border:1px solid #374151}.workflow-popup .workflow-json .json-preview{background:transparent;color:#e5e7eb;font-family:Monaco,Menlo,Ubuntu Mono,monospace;font-size:.8rem;line-height:1.4;margin:0;white-space:pre-wrap;word-break:break-all;max-height:200px;overflow-y:auto}.workflow-popup .popup-footer{text-align:center;margin-top:1.5rem;padding-top:1rem;border-top:1px solid #e2e8f0}.workflow-popup .popup-footer .btn{padding:.75rem 1.5rem;background:#3b82f6;color:#fff;border:none;border-radius:6px;font-weight:600;cursor:pointer;display:inline-flex;align-items:center;gap:.5rem;transition:background-color .2s}.workflow-popup .popup-footer .btn:hover{background:#2563eb}.workflow-popup .popup-footer .btn i{font-size:.9rem}.view-workflow-link{color:#3b82f6;text-decoration:none;font-size:.85rem;margin-left:.5rem;transition:color .2s}.view-workflow-link:hover{color:#1d4ed8;text-decoration:underline}.studio-header{display:flex;justify-content:space-between;align-items:center;padding:1rem 1.5rem;background:#fff;border-bottom:1px solid #e2e8f0;box-shadow:0 1px 3px #0000000d}.studio-header .header-title{display:flex;align-items:center;gap:.75rem}.studio-header .header-title i{font-size:1.75rem;color:#8b5cf6}.studio-header .header-title h1{margin:0;font-size:1.5rem;font-weight:700;color:#1e293b}.studio-header .header-title .badge{padding:.25rem .75rem;background:#8b5cf6;color:#fff;border-radius:12px;font-size:.75rem;font-weight:600}.studio-header .header-actions{display:flex;gap:.75rem;align-items:center}.samples-dropdown{position:relative}.samples-dropdown .samples-menu{position:absolute;top:calc(100% + .5rem);left:0;min-width:320px;background:#fff;border:1px solid #e2e8f0;border-radius:8px;box-shadow:0 10px 25px #0000001a;z-index:1000;max-height:400px;overflow-y:auto}.samples-dropdown .samples-menu .sample-item{padding:.875rem 1rem;display:flex;align-items:flex-start;gap:.75rem;cursor:pointer;border-bottom:1px solid #f1f5f9;transition:all .2s}.samples-dropdown .samples-menu .sample-item:last-child{border-bottom:none}.samples-dropdown .samples-menu .sample-item:hover{background:#f8fafc;transform:translate(4px)}.samples-dropdown .samples-menu .sample-item i{font-size:1.25rem;margin-top:.125rem;color:#8b5cf6}.samples-dropdown .samples-menu .sample-item .sample-info{display:flex;flex-direction:column;gap:.25rem;flex:1}.samples-dropdown .samples-menu .sample-item .sample-info strong{color:#1e293b;font-size:.875rem;font-weight:600}.samples-dropdown .samples-menu .sample-item .sample-info span{color:#64748b;font-size:.75rem;line-height:1.4}.studio-body{display:grid;grid-template-columns:1fr;gap:0;flex:1;overflow:hidden;transition:grid-template-columns .3s ease}.studio-body.sidebar-hidden,.studio-body.properties-hidden,.studio-body.sidebar-hidden.properties-hidden{grid-template-columns:1fr}.studio-sidebar{background:#fff;border-right:1px solid #e2e8f0;display:flex;flex-direction:column;overflow:hidden}.studio-sidebar .sidebar-header{padding:1rem 1.25rem;border-bottom:1px solid #e2e8f0;display:flex;align-items:center;gap:.5rem}.studio-sidebar .sidebar-header i{font-size:1.25rem;color:#8b5cf6}.studio-sidebar .sidebar-header h3{flex:1;margin:0;font-size:1.125rem;font-weight:600;color:#1e293b}.activities-tree{flex:1;overflow-y:auto;padding:.5rem}.category-section{margin-bottom:.5rem}.category-section .category-header{display:flex;align-items:center;gap:.5rem;padding:.75rem;border-radius:8px;cursor:pointer;transition:all .2s;background:#f8fafc}.category-section .category-header:hover{background:#f1f5f9}.category-section .category-header.active{background:#ede9fe}.category-section .category-header.active>i:first-child{color:#8b5cf6}.category-section .category-header>i:first-child{font-size:.875rem;color:#94a3b8;transition:transform .2s,color .2s}.category-section .category-header>i:nth-child(2){font-size:1.125rem}.category-section .category-header span{flex:1;font-weight:600;font-size:.875rem;color:#334155}.category-section .category-header .count{flex:none;padding:.125rem .5rem;background:#fff;border-radius:10px;font-size:.75rem;font-weight:600;color:#64748b;border:1px solid #e2e8f0}.activities-list{padding:.5rem 0 .5rem 1.5rem;display:flex;flex-direction:column;gap:.5rem;animation:slideDown .3s ease}.activities-list .activities-header{padding:.5rem .75rem;margin-bottom:.5rem}.activities-list .activities-header h4{margin:0;font-size:.875rem;font-weight:600;color:#64748b;text-transform:uppercase;letter-spacing:.5px}.activity-card{background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:.875rem;margin-bottom:.75rem;transition:all .2s}.activity-card:hover{border-color:#8b5cf6;box-shadow:0 4px 12px #8b5cf61a;transform:translateY(-1px)}.activity-card .activity-info{display:flex;align-items:flex-start;gap:.75rem;margin-bottom:.5rem}.activity-card .activity-info>i{font-size:1.5rem;color:#8b5cf6;margin-top:.125rem}.activity-card .activity-info .activity-details{flex:1;display:flex;flex-direction:column;gap:.25rem}.activity-card .activity-info .activity-details strong{font-size:.875rem;color:#1e293b}.activity-card .activity-info .activity-details small{font-size:.75rem;color:#64748b;line-height:1.4}.activity-card .activity-info .activity-details code{font-size:.75rem;color:#8b5cf6;background:#f3f0ff;padding:.125rem .375rem;border-radius:4px;width:fit-content}.activity-card .copy-btn{float:right;padding:.375rem .75rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;cursor:pointer;transition:all .2s;color:#64748b}.activity-card .copy-btn:hover{background:#8b5cf6;border-color:#8b5cf6;color:#fff}.activity-card .copy-btn i{font-size:.875rem}.activity-card .activity-properties{margin-top:.75rem;padding-top:.75rem;border-top:1px solid #f1f5f9}.activity-card .activity-properties .properties-title{display:block;font-size:.75rem;font-weight:600;color:#64748b;margin-bottom:.5rem}.activity-card .activity-properties .property-item{display:flex;align-items:center;gap:.5rem;padding:.25rem 0;font-size:.75rem}.activity-card .activity-properties .property-item code{color:#1e293b;background:#f8fafc;padding:.125rem .375rem;border-radius:3px}.activity-card .activity-properties .property-item .property-type{color:#64748b;font-style:italic}.activity-card .activity-properties .property-item .required{color:#ef4444;font-weight:700}.studio-editor{display:flex;flex-direction:column;background:#1e293b;overflow:hidden}.studio-editor .editor-header{padding:1rem 1.25rem;background:#0f172a;display:flex;align-items:center;gap:.5rem}.studio-editor .editor-header i{font-size:1.125rem;color:#8b5cf6}.studio-editor .editor-header h3{margin:0;font-size:1rem;font-weight:600;color:#e2e8f0}.studio-editor axp-page-toolbar .editor-tabs{display:flex;gap:.5rem;background:transparent}.studio-editor axp-page-toolbar .editor-tabs .tab-btn{padding:.5rem 1rem;background:transparent;border:1px solid #e2e8f0;border-radius:6px;color:#64748b;font-size:.875rem;font-weight:500;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center;gap:.5rem}.studio-editor axp-page-toolbar .editor-tabs .tab-btn i{font-size:.875rem}.studio-editor axp-page-toolbar .editor-tabs .tab-btn:hover{background:#f8fafc;border-color:#cbd5e1;color:#475569}.studio-editor axp-page-toolbar .editor-tabs .tab-btn.active{background:#8b5cf6;border-color:#8b5cf6;color:#fff}.studio-editor .editor-content{flex:1;display:flex;overflow:hidden}.studio-editor .json-tab{flex:1;display:flex;flex-direction:column}.studio-editor .json-editor{flex:1;padding:1.5rem;background:#1e293b;color:#e2e8f0;border:none;outline:none;font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:.875rem;line-height:1.6;resize:none;overflow:auto}.studio-editor .json-editor::placeholder{color:#475569}.studio-editor .json-editor::-webkit-scrollbar{width:10px;height:10px}.studio-editor .json-editor::-webkit-scrollbar-track{background:#0f172a}.studio-editor .json-editor::-webkit-scrollbar-thumb{background:#475569;border-radius:5px}.studio-editor .json-editor::-webkit-scrollbar-thumb:hover{background:#64748b}.studio-editor .visual-tab{flex:1;display:flex;background:#f8fafc;position:relative}.studio-editor .visual-canvas{flex:1;display:flex;flex-direction:column;overflow:hidden}.studio-editor .visual-canvas .canvas-toolbar{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem;background:var(--ax-surface, white);border-bottom:1px solid var(--ax-border, #e2e8f0)}.studio-editor .visual-canvas .canvas-toolbar .tool-btn{padding:.5rem .75rem;background:var(--ax-surface-alt, #f8fafc);border:1px solid var(--ax-border, #e2e8f0);border-radius:6px;color:var(--ax-text-muted, #64748b);cursor:pointer;transition:all .2s}.studio-editor .visual-canvas .canvas-toolbar .tool-btn:hover{background:#8b5cf6;border-color:#8b5cf6;color:#fff}.studio-editor .visual-canvas .canvas-toolbar .tool-btn i{font-size:.875rem}.studio-editor .visual-canvas .canvas-toolbar .toolbar-sep{width:1px;height:1.25rem;background:var(--ax-border, #e2e8f0);flex-shrink:0}.studio-editor .visual-canvas .canvas-toolbar .toolbar-auto-save{display:flex;align-items:center;gap:.5rem;font-size:.8125rem;color:var(--ax-text-muted, #64748b);cursor:default}.studio-editor .visual-canvas .canvas-toolbar .toolbar-auto-save ax-switch{flex-shrink:0}.studio-editor .visual-canvas .canvas-toolbar .tool-info{flex:1;display:flex;align-items:center;gap:.5rem;min-height:1.75rem;font-size:.8125rem;color:var(--ax-text-muted, #64748b);line-height:1.4}.studio-editor .visual-canvas .canvas-toolbar .tool-info strong{font-weight:600}.studio-editor .visual-canvas .canvas-toolbar .tool-info i{font-size:1rem;color:#8b5cf6;flex-shrink:0}.studio-editor .visual-canvas .canvas-area{flex:1;position:relative;background:linear-gradient(90deg,#e5e7eb 1px,transparent 1px),linear-gradient(#e5e7eb 1px,transparent 1px);background-size:20px 20px;overflow:auto;min-height:600px}.studio-editor .visual-canvas .connections-layer{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:1}.studio-editor .visual-canvas .connection-line{fill:none;transition:stroke .2s}.studio-editor .visual-canvas .connection-line.connection-hit{stroke:transparent;stroke-width:16;cursor:pointer;pointer-events:stroke}.studio-editor .visual-canvas .connection-line.connection-hit:hover~.outcome-line,.studio-editor .visual-canvas .connection-line.connection-hit:hover~.connection-line:not(.connection-hit){filter:brightness(.9)}.studio-editor .visual-canvas .connection-line:not(.connection-hit){stroke-linecap:round;pointer-events:none}.studio-editor .visual-canvas .connection-line.outcome-line{stroke-width:2.5}.studio-editor .visual-canvas .visual-node{position:absolute;width:150px;background:#fff;border:2px solid #e2e8f0;border-radius:8px;box-shadow:0 2px 8px #0000001a;cursor:move;transition:all .2s;z-index:2}.studio-editor .visual-canvas .visual-node:hover{border-color:#8b5cf6;box-shadow:0 4px 16px #8b5cf633;transform:translateY(-2px)}.studio-editor .visual-canvas .visual-node.selected{border-color:#8b5cf6;border-width:3px;box-shadow:0 0 0 3px #8b5cf633}.studio-editor .visual-canvas .visual-node .node-header{display:flex;align-items:center;gap:.5rem;padding:.75rem;background:linear-gradient(135deg,#8b5cf6,#7c3aed);color:#fff;border-radius:6px 6px 0 0;font-size:.875rem;font-weight:600}.studio-editor .visual-canvas .visual-node .node-header i{font-size:1rem}.studio-editor .visual-canvas .visual-node .node-header span{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.studio-editor .visual-canvas .visual-node .node-header .node-delete{padding:.25rem;background:#fff3;border:none;border-radius:4px;color:#fff;cursor:pointer;transition:all .2s}.studio-editor .visual-canvas .visual-node .node-header .node-delete:hover{background:#ef4444cc}.studio-editor .visual-canvas .visual-node .node-header .node-delete i{font-size:.75rem}.studio-editor .visual-canvas .visual-node .node-body{padding:.75rem}.studio-editor .visual-canvas .visual-node .node-body small{display:block;font-size:.75rem;color:#64748b;text-align:center}.studio-editor .visual-canvas .visual-node .node-connectors{position:relative}.studio-editor .visual-canvas .visual-node .node-connectors .connector{position:absolute;width:12px;height:12px;background:#8b5cf6;border:2px solid white;border-radius:50%;cursor:pointer;transition:all .2s;z-index:10}.studio-editor .visual-canvas .visual-node .node-connectors .connector:hover{transform:scale(1.3);box-shadow:0 0 0 3px #8b5cf64d}.studio-editor .visual-canvas .visual-node .node-connectors .connector-in{top:-50px;left:50%;transform:translate(-50%);background:#3b82f6}.studio-editor .visual-canvas .visual-node .node-connectors .connector-out{bottom:-6px;left:50%;transform:translate(-50%);background:#8b5cf6}.studio-editor .visual-canvas .visual-node .node-connectors .connector-out.active{background:#ef4444}.studio-editor .visual-canvas .visual-node .node-connectors .outcomes-container{position:absolute;bottom:-60px;left:50%;transform:translate(-50%);display:flex;flex-direction:column;gap:8px;background:#fff;padding:8px;border:1px solid #e2e8f0;border-radius:8px;box-shadow:0 4px 12px #00000026;min-width:120px;z-index:100}.studio-editor .visual-canvas .visual-node .node-connectors .outcomes-container:before{content:\"\";position:absolute;top:-8px;left:50%;transform:translate(-50%);width:0;height:0;border-left:8px solid transparent;border-right:8px solid transparent;border-bottom:8px solid white;filter:drop-shadow(0 -2px 2px rgba(0,0,0,.05))}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector{display:flex;align-items:center;justify-content:space-between;padding:6px 10px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;cursor:pointer;transition:all .2s;position:relative}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector:hover{background:#f1f5f9;border-color:#8b5cf6;transform:translate(2px)}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector.active{background:#fef2f2;border-color:#ef4444}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector.active .outcome-dot{background:#ef4444;box-shadow:0 0 0 3px #ef444433}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector .outcome-label{font-size:.75rem;font-weight:600;color:#475569;-webkit-user-select:none;user-select:none;flex:1}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector .outcome-dot{width:10px;height:10px;background:#8b5cf6;border:2px solid white;border-radius:50%;transition:all .2s;flex-shrink:0}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=\"200\"] .outcome-dot,.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=Done] .outcome-dot{background:#10b981}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=\"404\"] .outcome-dot,.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=Failed] .outcome-dot{background:#ef4444}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=Timeout] .outcome-dot,.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=Cancelled] .outcome-dot{background:#f59e0b}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=Then] .outcome-dot{background:#3b82f6}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=Else] .outcome-dot{background:#64748b}.studio-editor .visual-canvas .canvas-empty-state{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center;color:#94a3b8;pointer-events:none}.studio-editor .visual-canvas .canvas-empty-state i{font-size:4rem;margin-bottom:1rem;opacity:.5}.studio-editor .visual-canvas .canvas-empty-state p{margin:0 0 .5rem;font-size:1rem;font-weight:500}.studio-editor .visual-canvas .canvas-empty-state small{font-size:.875rem;opacity:.8}.studio-editor .properties-panel{width:280px;background:#fff;border-left:1px solid #e2e8f0;display:flex;flex-direction:column}.studio-editor .properties-panel .properties-header{display:flex;align-items:center;gap:.5rem;padding:1rem;border-bottom:1px solid #e2e8f0}.studio-editor .properties-panel .properties-header i{font-size:1.125rem;color:#8b5cf6}.studio-editor .properties-panel .properties-header h4{flex:1;margin:0;font-size:.875rem;font-weight:600;color:#1e293b}.studio-editor .properties-panel .properties-header button{padding:.25rem .5rem;background:transparent;border:none;color:#64748b;cursor:pointer;transition:color .2s}.studio-editor .properties-panel .properties-header button:hover{color:#ef4444}.studio-editor .properties-panel .properties-body{flex:1;padding:1rem;overflow-y:auto}.studio-editor .properties-panel .properties-body .properties-widget-section{min-height:0}.studio-editor .properties-panel .properties-body .workflow-panel-section{margin-bottom:1.5rem}.studio-editor .properties-panel .properties-body .workflow-panel-section h5{margin:0 0 .75rem;font-size:.75rem;font-weight:600;color:#64748b;text-transform:uppercase;letter-spacing:.5px}.studio-editor .properties-panel .properties-body .workflow-panel-section .form-group{margin-bottom:.75rem}.studio-editor .properties-panel .properties-body .workflow-panel-section .form-group label{font-size:.75rem}.studio-editor .properties-panel .properties-body .workflow-panel-section .form-group input,.studio-editor .properties-panel .properties-body .workflow-panel-section .form-group textarea{font-size:.8125rem}.studio-editor .properties-panel .properties-body .workflow-info-table{display:flex;flex-direction:column;gap:.5rem}.studio-editor .properties-panel .properties-body .workflow-info-row{display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:.5rem 0;border-bottom:1px solid #f1f5f9}.studio-editor .properties-panel .properties-body .workflow-info-row:last-child{border-bottom:none}.studio-editor .properties-panel .properties-body .info-label{font-size:.8125rem;font-weight:500;color:#64748b;flex-shrink:0}.studio-editor .properties-panel .properties-body .info-value{font-size:.8125rem;color:#1e293b;text-align:right;word-break:break-all}.studio-editor .properties-panel .properties-body .info-actions{display:flex;align-items:center;gap:.5rem}.studio-editor .properties-panel .properties-body .property-row{margin-bottom:1rem}.studio-editor .properties-panel .properties-body .property-row label{display:block;font-size:.75rem;font-weight:600;color:#64748b;margin-bottom:.375rem;text-transform:uppercase;letter-spacing:.5px}.studio-editor .properties-panel .properties-body .property-row input{width:100%;padding:.5rem;border:1px solid #e2e8f0;border-radius:6px;font-size:.875rem;color:#1e293b;transition:all .2s}.studio-editor .properties-panel .properties-body .property-row input:focus{outline:none;border-color:#8b5cf6;box-shadow:0 0 0 3px #8b5cf61a}.studio-editor .properties-panel .properties-body .property-row input:disabled{background:#f8fafc;color:#94a3b8;cursor:not-allowed}.studio-editor .properties-panel .properties-body .properties-divider{height:1px;background:#e2e8f0;margin:1.5rem 0}.studio-editor .properties-panel .properties-body h5{margin:0 0 .5rem;font-size:.75rem;font-weight:600;color:#64748b;text-transform:uppercase;letter-spacing:.5px}.studio-editor .properties-panel .properties-body .properties-hint{display:block;font-size:.75rem;color:#94a3b8;margin-bottom:.75rem}.studio-editor .properties-panel .properties-body .properties-json{margin:.75rem 0 0;padding:.75rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;font-family:JetBrains Mono,monospace;font-size:.75rem;line-height:1.6;color:#1e293b;overflow-x:auto}.studio-editor .properties-panel .properties-body .no-properties{margin:.75rem 0 0;padding:1rem;background:#f8fafc;border:1px dashed #cbd5e1;border-radius:6px;text-align:center;font-size:.75rem;color:#94a3b8}.studio-editor .properties-panel .properties-body .connections-list{display:flex;flex-direction:column;gap:.5rem;margin-top:.75rem}.studio-editor .properties-panel .properties-body .connections-list .connection-item{display:flex;align-items:center;gap:.5rem;padding:.5rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;font-size:.75rem}.studio-editor .properties-panel .properties-body .connections-list .connection-item.outcome-connection{border-left-width:3px}.studio-editor .properties-panel .properties-body .connections-list .connection-item i{color:#64748b;font-size:.875rem}.studio-editor .properties-panel .properties-body .connections-list .connection-item span{flex:1;color:#1e293b;font-weight:500}.studio-editor .properties-panel .properties-body .connections-list .connection-item .outcome-badge{padding:.25rem .5rem;border-radius:4px;color:#fff;font-size:.65rem;font-weight:700;text-transform:uppercase;letter-spacing:.5px}.studio-editor .properties-panel .properties-body .connections-list .connection-item .remove-btn{padding:.25rem;background:transparent;border:none;color:#ef4444;cursor:pointer;border-radius:4px;transition:all .2s}.studio-editor .properties-panel .properties-body .connections-list .connection-item .remove-btn:hover{background:#fee2e2}.studio-editor .properties-panel .properties-body .connections-list .connection-item .remove-btn i{font-size:.75rem;color:inherit}.studio-editor .properties-panel .properties-body .outcomes-info{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.75rem}.studio-editor .properties-panel .properties-body .outcomes-info .outcome-tag{display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .625rem;background:#fff;border:2px solid;border-radius:6px;font-size:.75rem;font-weight:600;color:#1e293b;transition:all .2s}.studio-editor .properties-panel .properties-body .outcomes-info .outcome-tag:hover{transform:translateY(-1px);box-shadow:0 2px 8px #0000001a}.studio-editor .properties-panel .properties-body .outcomes-info .outcome-tag .outcome-dot{width:8px;height:8px;border-radius:50%}.studio-result{display:flex;flex-direction:column;background:#fff;border-left:1px solid #e2e8f0;overflow:hidden}.studio-result .result-header{padding:1rem 1.25rem;border-bottom:1px solid #e2e8f0;display:flex;align-items:center;gap:.5rem}.studio-result .result-header i{font-size:1.125rem;color:#10b981}.studio-result .result-header h3{flex:1;margin:0;font-size:1rem;font-weight:600;color:#1e293b}.studio-result .result-header .clear-btn{padding:.375rem .75rem;background:#fee2e2;color:#dc2626;border:none;border-radius:6px;cursor:pointer;font-size:.75rem;font-weight:500;transition:all .2s}.studio-result .result-header .clear-btn:hover{background:#fecaca}.studio-result .result-header .clear-btn i{font-size:.75rem;color:inherit}.studio-result .result-body{flex:1;overflow-y:auto;padding:1rem}.logs-container{display:flex;flex-direction:column;gap:.5rem}.log-item{display:flex;align-items:flex-start;gap:.5rem;padding:.75rem;background:#f8fafc;border-left:3px solid #cbd5e1;border-radius:6px;font-size:.875rem}.log-item.log-info{border-left-color:#3b82f6;background:#eff6ff}.log-item.log-info .log-icon{color:#3b82f6}.log-item.log-success{border-left-color:#10b981;background:#f0fdf4}.log-item.log-success .log-icon{color:#10b981}.log-item.log-warning{border-left-color:#f59e0b;background:#fffbeb}.log-item.log-warning .log-icon{color:#f59e0b}.log-item.log-error{border-left-color:#ef4444;background:#fef2f2}.log-item.log-error .log-icon{color:#ef4444}.log-item .log-time{font-family:JetBrains Mono,monospace;font-size:.75rem;color:#64748b;min-width:80px}.log-item .log-icon{font-size:1rem}.log-item .log-message{flex:1;color:#1e293b}.log-item .log-data-toggle{padding:.25rem .5rem;background:transparent;border:1px solid #cbd5e1;border-radius:4px;cursor:pointer;transition:all .2s}.log-item .log-data-toggle:hover{background:#fff}.log-item .log-data-toggle i{font-size:.75rem;color:#64748b}.log-data{margin:.5rem 0 0;padding:1rem;background:#0f172a;color:#e2e8f0;border-radius:6px;font-family:JetBrains Mono,monospace;font-size:.75rem;line-height:1.6;overflow-x:auto}.settings-modal-overlay{position:fixed;inset:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:9999;padding:2rem;animation:fadeIn .2s ease}.settings-modal{background:#fff;border-radius:12px;box-shadow:0 20px 60px #0000004d;width:100%;max-width:900px;max-height:90vh;display:flex;flex-direction:column;animation:slideUp .3s ease}@keyframes slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}.settings-modal-header{display:flex;align-items:center;justify-content:space-between;padding:1.5rem 2rem;border-bottom:1px solid #e2e8f0}.settings-modal-header .header-title{display:flex;align-items:center;gap:.75rem}.settings-modal-header .header-title i{font-size:1.5rem;color:#8b5cf6}.settings-modal-header .header-title h2{margin:0;font-size:1.25rem;font-weight:700;color:#1e293b}.settings-modal-header .close-btn{padding:.5rem;background:transparent;border:none;color:#64748b;cursor:pointer;border-radius:6px;transition:all .2s}.settings-modal-header .close-btn:hover{background:#f1f5f9;color:#ef4444}.settings-modal-header .close-btn i{font-size:1.25rem}.settings-modal-body{flex:1;display:flex;flex-direction:column;overflow:hidden}.settings-tabs{padding:0 1.5rem}.settings-content{flex:1;overflow-y:auto;padding:2rem}.settings-section h3{margin:0 0 1.5rem;font-size:1rem;font-weight:600;color:#1e293b}.settings-section .section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem}.settings-section .section-header h3{margin:0}.settings-section .section-header .add-btn{display:flex;align-items:center;gap:.5rem;padding:.5rem 1rem;background:#8b5cf6;color:#fff;border:none;border-radius:6px;font-size:.875rem;font-weight:500;cursor:pointer;transition:all .2s}.settings-section .section-header .add-btn:hover{background:#7c3aed;transform:translateY(-1px);box-shadow:0 4px 12px #8b5cf64d}.settings-section .section-header .add-btn i{font-size:.875rem}.form-group{margin-bottom:1.25rem}.form-group label{display:block;font-size:.875rem;font-weight:600;color:#475569;margin-bottom:.5rem}.form-group small{display:block;font-size:.75rem;color:#94a3b8;margin-top:.375rem}.form-group.checkbox-group{margin-bottom:0}.form-group.checkbox-group label{display:flex;align-items:center;gap:.5rem;cursor:pointer;margin-bottom:0}.form-group.checkbox-group label input[type=checkbox]{width:18px;height:18px;cursor:pointer}.form-group.checkbox-group label span{font-size:.875rem;font-weight:500}.form-group.flex-1{flex:1}.form-row{display:flex;gap:1rem;align-items:flex-start}.form-input,.form-select,.form-textarea{width:100%;padding:.625rem;border:1px solid #e2e8f0;border-radius:6px;font-size:.875rem;color:#1e293b;transition:all .2s}.form-input:focus,.form-select:focus,.form-textarea:focus{outline:none;border-color:#8b5cf6;box-shadow:0 0 0 3px #8b5cf61a}.form-input::placeholder,.form-select::placeholder,.form-textarea::placeholder{color:#cbd5e1}.form-textarea{resize:vertical;font-family:inherit}.items-list{display:flex;flex-direction:column;gap:1rem}.item-card{background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;overflow:hidden;transition:all .2s}.item-card:hover{border-color:#cbd5e1;box-shadow:0 2px 8px #0000000d}.item-card .item-header{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;background:#f1f5f9;border-bottom:1px solid #e2e8f0}.item-card .item-header .item-number{font-size:.75rem;font-weight:700;color:#8b5cf6;padding:.25rem .5rem;background:#fff;border-radius:4px}.item-card .item-header .remove-btn{padding:.375rem .625rem;background:transparent;border:none;color:#ef4444;cursor:pointer;border-radius:4px;transition:all .2s}.item-card .item-header .remove-btn:hover{background:#fee2e2}.item-card .item-header .remove-btn i{font-size:.875rem}.item-card .item-body{padding:1rem}.advanced-group{margin-bottom:2rem;padding-bottom:2rem;border-bottom:1px solid #e2e8f0}.advanced-group:last-child{border-bottom:none;margin-bottom:0;padding-bottom:0}.advanced-group h4{margin:0 0 1rem;font-size:.875rem;font-weight:600;color:#475569;text-transform:uppercase;letter-spacing:.5px}.outcomes-preview{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.75rem}.outcomes-preview .outcome-chip{display:inline-flex;align-items:center;padding:.375rem .75rem;background:#f1f5f9;border:1px solid #cbd5e1;border-radius:6px;font-size:.75rem;font-weight:600;color:#475569}.export-info{margin-top:1rem;padding:1rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px}.export-info .info-row{display:flex;align-items:center;gap:.75rem;padding:.5rem 0;border-bottom:1px solid #e2e8f0}.export-info .info-row:last-child{border-bottom:none;padding-bottom:0}.export-info .info-row .label{font-size:.75rem;font-weight:600;color:#64748b;min-width:120px}.export-info .info-row code{flex:1;padding:.25rem .5rem;background:#fff;border:1px solid #e2e8f0;border-radius:4px;font-size:.75rem;color:#1e293b;font-family:JetBrains Mono,monospace}.settings-modal-footer{display:flex;align-items:center;justify-content:flex-end;gap:1rem;padding:1.5rem 2rem;border-top:1px solid #e2e8f0;background:#f8fafc}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem 1rem;text-align:center;color:#94a3b8}.empty-state i{font-size:3rem;margin-bottom:1rem}.empty-state p{margin:0;font-size:.875rem}.final-result{margin-top:1.5rem;padding-top:1.5rem;border-top:2px solid #e2e8f0}.final-result .result-header{display:flex;align-items:center;justify-content:space-between;padding:.75rem;background:#f8fafc;border-radius:8px;margin-bottom:1rem;cursor:pointer;transition:all .2s}.final-result .result-header:hover{background:#f1f5f9;transform:translate(-2px)}.final-result .result-header h4{display:flex;align-items:center;gap:.5rem;margin:0;font-size:.875rem;font-weight:600;color:#475569;text-transform:uppercase}.final-result .result-header h4 i{font-size:.875rem;transition:transform .2s}.final-result .result-header .toggle-hint{font-size:.75rem;color:#94a3b8}.final-result .result-card{background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;padding:1rem}.final-result .result-card .result-row{display:flex;align-items:center;gap:.75rem;padding:.5rem 0}.final-result .result-card .result-row:not(:last-child){border-bottom:1px solid #e2e8f0}.final-result .result-card .result-row strong{font-size:.875rem;color:#475569;min-width:100px}.final-result .result-card .result-row .badge{padding:.25rem .75rem;border-radius:12px;font-size:.75rem;font-weight:600}.final-result .result-card .result-row .badge.badge-running{background:#dbeafe;color:#1e40af}.final-result .result-card .result-row .badge.badge-finished{background:#d1fae5;color:#065f46}.final-result .result-card .result-row .badge.badge-cancelled{background:#fed7aa;color:#92400e}.final-result .result-card .result-row .badge.badge-faulted{background:#fee2e2;color:#991b1b}.final-result .result-card .result-row pre{margin:.5rem 0 0;padding:.75rem;background:#0f172a;color:#e2e8f0;border-radius:6px;font-family:JetBrains Mono,monospace;font-size:.75rem;line-height:1.6;overflow-x:auto;width:100%}.activities-list::-webkit-scrollbar,.result-body::-webkit-scrollbar{width:8px}.activities-list::-webkit-scrollbar-track,.result-body::-webkit-scrollbar-track{background:#f1f5f9}.activities-list::-webkit-scrollbar-thumb,.result-body::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:4px}.activities-list::-webkit-scrollbar-thumb:hover,.result-body::-webkit-scrollbar-thumb:hover{background:#94a3b8}.activity-card{cursor:grab}.activity-card:active{cursor:grabbing}.activity-card[draggable=true]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.visual-node[draggable=true]{cursor:move;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.visual-node:active{cursor:grabbing}.canvas-area[data-drag-over=true]{background-color:#8b5cf60d}.connector:hover{transform:scale(1.3);box-shadow:0 0 0 3px #8b5cf64d}.connector-out.active{animation:pulse 1s infinite}@keyframes pulse{0%,to{box-shadow:0 0 0 3px #ef44444d}50%{box-shadow:0 0 0 6px #ef44441a}}@keyframes slideDown{0%{opacity:0;max-height:0}to{opacity:1;max-height:2000px}}.execution-dialog-overlay{position:fixed;inset:0;background:#000000b3;backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;z-index:10000;animation:fadeIn .2s ease}.execution-dialog{width:90vw;max-width:1200px;height:90vh;background:#fff;border-radius:16px;box-shadow:0 25px 50px #0000004d;display:flex;flex-direction:column;overflow:hidden;animation:slideUp .3s ease}.execution-dialog-header{padding:1.5rem 2rem;background:linear-gradient(135deg,#8b5cf6,#7c3aed);color:#fff;display:flex;justify-content:space-between;align-items:center;flex-shrink:0}.execution-dialog-header .header-content{display:flex;align-items:center;gap:1rem;flex:1}.execution-dialog-header .header-content>i{font-size:2.5rem;opacity:.9}.execution-dialog-header .header-content .header-info h2{margin:0;font-size:1.75rem;font-weight:700}.execution-dialog-header .header-content .header-info p{margin:.25rem 0 0;opacity:.9;font-size:.95rem}.execution-dialog-header .close-btn{background:#fff3;border:none;width:40px;height:40px;border-radius:8px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s;color:#fff;font-size:1.25rem}.execution-dialog-header .close-btn:hover:not(:disabled){background:#ffffff4d;transform:scale(1.05)}.execution-dialog-header .close-btn:disabled{opacity:.5;cursor:not-allowed}.execution-dialog-body{flex:1;overflow-y:auto;padding:2rem;background:#f8fafc}.execution-dialog-footer{padding:1rem 2rem;background:#fff;border-top:1px solid #e2e8f0;display:flex;justify-content:space-between;align-items:center;flex-shrink:0}.execution-dialog-footer .footer-info{display:flex;gap:1.5rem}.execution-dialog-footer .footer-info .time-info{display:flex;align-items:center;gap:.5rem;color:#64748b;font-size:.875rem}.execution-dialog-footer .footer-info .time-info i{color:#8b5cf6}.execution-dialog-footer .footer-actions{display:flex;gap:.75rem}.workflow-info-panel{background:#fff;border-radius:12px;padding:2rem;box-shadow:0 4px 6px #0000000d}.workflow-info-panel .info-section{margin-bottom:2rem}.workflow-info-panel .info-section h3{display:flex;align-items:center;gap:.5rem;margin:0 0 1rem;color:#1e293b;font-size:1.25rem}.workflow-info-panel .info-section h3 i{color:#8b5cf6}.workflow-info-panel .info-section .description{color:#475569;line-height:1.7;margin:0}.workflow-info-panel .info-section .features-list{list-style:none;padding:0;margin:0;display:grid;gap:.75rem}.workflow-info-panel .info-section .features-list li{display:flex;align-items:center;gap:.75rem;padding:.75rem;background:#f8fafc;border-radius:8px;color:#334155}.workflow-info-panel .info-section .features-list li i{color:#10b981;font-size:1.125rem}.workflow-info-panel .start-section{text-align:center;padding:2rem;background:linear-gradient(135deg,#f0fdf4,#dcfce7);border-radius:12px;border:2px dashed #10b981}.workflow-info-panel .start-section .start-illustration{margin-bottom:1rem}.workflow-info-panel .start-section .start-illustration i{font-size:4rem;color:#10b981;animation:float 3s ease-in-out infinite}.workflow-info-panel .start-section h3{margin:0 0 .5rem;color:#1e293b;font-size:1.5rem}.workflow-info-panel .start-section p{margin:0 0 1.5rem;color:#64748b}.state-machine-ui .issue-tracker{background:#fff;border-radius:8px;overflow:hidden;box-shadow:0 1px 2px #0000000d}.state-machine-ui .issue-tracker .issue-header-main{padding:1.5rem 2rem 1rem;border-bottom:1px solid #e2e8f0}.state-machine-ui .issue-tracker .issue-header-main .issue-breadcrumb{display:flex;align-items:center;gap:.5rem;font-size:.875rem;color:#64748b;margin-bottom:.75rem}.state-machine-ui .issue-tracker .issue-header-main .issue-breadcrumb .project-name{color:#3b82f6;font-weight:600}.state-machine-ui .issue-tracker .issue-header-main .issue-breadcrumb .separator{color:#94a3b8}.state-machine-ui .issue-tracker .issue-header-main .issue-breadcrumb .issue-key{color:#64748b}.state-machine-ui .issue-tracker .issue-header-main .issue-type-title{display:flex;align-items:center;gap:.75rem}.state-machine-ui .issue-tracker .issue-header-main .issue-type-title .type-badge{padding:.375rem .75rem;border-radius:4px;font-size:.8125rem;font-weight:600;display:flex;align-items:center;gap:.375rem;background:#eff6ff;color:#3b82f6}.state-machine-ui .issue-tracker .issue-header-main .issue-type-title .type-badge i{font-size:1rem}.state-machine-ui .issue-tracker .issue-header-main .issue-type-title .issue-main-title{margin:0;font-size:1.5rem;font-weight:600;color:#1e293b}.state-machine-ui .issue-tracker .issue-action-bar{padding:.75rem 2rem;background:#f8fafc;border-bottom:1px solid #e2e8f0;display:flex;justify-content:space-between;align-items:center}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left{display:flex;gap:.5rem}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn{padding:.5rem 1rem;border:1px solid #cbd5e1;border-radius:4px;background:#fff;font-weight:500;font-size:.875rem;cursor:pointer;transition:all .2s;color:#334155}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn:hover:not(:disabled){background:#f1f5f9;border-color:#94a3b8}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn:disabled{opacity:.5;cursor:not-allowed}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn.btn-primary{background:#3b82f6;color:#fff;border-color:#3b82f6}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn.btn-primary:hover:not(:disabled){background:#2563eb}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn.btn-success{background:#10b981;color:#fff;border-color:#10b981}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn.btn-success:hover:not(:disabled){background:#059669}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn.btn-warning{background:#f59e0b;color:#fff;border-color:#f59e0b}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn.btn-warning:hover:not(:disabled){background:#d97706}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-right .more-actions-btn{padding:.5rem 1rem;border:1px solid #cbd5e1;border-radius:4px;background:#fff;font-weight:500;font-size:.875rem;cursor:pointer;display:flex;align-items:center;gap:.5rem;color:#334155;transition:all .2s}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-right .more-actions-btn:hover{background:#f1f5f9}.state-machine-ui .issue-tracker .issue-main-content{display:grid;grid-template-columns:320px 1fr;gap:2rem;padding:2rem}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section{margin-bottom:2rem}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section h3{margin:0 0 1rem;font-size:1rem;font-weight:600;color:#1e293b}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row{display:flex;padding:.625rem 0;border-bottom:1px solid #f1f5f9}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row:last-child{border-bottom:none}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row label{min-width:100px;font-size:.8125rem;color:#64748b;font-weight:500}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row .detail-value{display:flex;align-items:center;gap:.5rem;font-size:.875rem;color:#1e293b}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row .detail-value i{font-size:1rem}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row .detail-value .status-badge{padding:.25rem .625rem;border-radius:4px;color:#fff;font-weight:600;font-size:.75rem;text-transform:uppercase}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row .detail-value .view-workflow-link{color:#3b82f6;font-size:.8125rem;text-decoration:none;margin-left:.5rem}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row .detail-value .view-workflow-link:hover{text-decoration:underline}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row .detail-value .user-avatar{width:24px;height:24px;border-radius:50%;background:#8b5cf6;color:#fff;display:flex;align-items:center;justify-content:center;font-size:.75rem}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz{background:#f8fafc;border-radius:8px;padding:1.5rem;border:1px solid #e2e8f0}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz h3{margin:0 0 1rem;font-size:.875rem;font-weight:600;color:#1e293b}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow .flow-state{display:flex;flex-direction:column;align-items:center;gap:.375rem;opacity:.4;transition:opacity .2s}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow .flow-state.active,.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow .flow-state.completed{opacity:1}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow .flow-state .state-circle{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;color:#fff;font-size:.875rem;box-shadow:0 2px 4px #0000001a}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow .flow-state .state-name{font-size:.6875rem;color:#64748b;font-weight:500}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow .flow-state.active .state-name{color:#1e293b;font-weight:600}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow .flow-arrow{color:#cbd5e1;font-size:.75rem;margin:0 .25rem}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .description-section,.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section{margin-bottom:2rem}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .description-section h3,.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section h3{margin:0 0 1rem;font-size:1rem;font-weight:600;color:#1e293b}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .description-section .description-content,.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .description-content{padding:1rem;background:#f8fafc;border-radius:6px;border:1px solid #e2e8f0}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .description-section .description-content p,.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .description-content p{margin:0;color:#475569;line-height:1.7;font-size:.875rem}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline{display:flex;flex-direction:column;gap:1rem}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item{display:flex;gap:.75rem}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item .activity-avatar{width:32px;height:32px;border-radius:50%;background:#8b5cf6;color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:.875rem}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item .activity-content{flex:1;padding-bottom:1rem;border-bottom:1px solid #f1f5f9}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item .activity-content .activity-header{font-size:.875rem;color:#334155;line-height:1.6;margin-bottom:.375rem}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item .activity-content .activity-header strong{color:#1e293b;font-weight:600}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item .activity-content .activity-header .activity-action{color:#64748b}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item .activity-content .activity-meta{display:flex;align-items:center;gap:.5rem;font-size:.8125rem;color:#94a3b8}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item .activity-content .activity-meta .activity-label{color:#8b5cf6;font-weight:500}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item:last-child .activity-content{border-bottom:none;padding-bottom:0}.registration-ui{display:flex;justify-content:center;align-items:center;min-height:400px}.registration-ui .registration-card{background:#fff;border-radius:12px;padding:3rem;box-shadow:0 4px 6px #0000000d;text-align:center;max-width:500px}.registration-ui .registration-card .registration-icon{margin-bottom:1.5rem}.registration-ui .registration-card .registration-icon i{font-size:5rem;color:#8b5cf6}.registration-ui .registration-card h3{margin:0 0 .75rem;color:#1e293b;font-size:1.75rem;font-weight:700}.registration-ui .registration-card .registration-desc{margin:0 0 2rem;color:#64748b;line-height:1.7}.registration-ui .registration-card .registration-progress{padding:2rem;background:#fef3c7;border-radius:8px}.registration-ui .registration-card .registration-progress .progress-spinner{margin-bottom:1rem}.registration-ui .registration-card .registration-progress .progress-spinner i{font-size:3rem;color:#f59e0b}.registration-ui .registration-card .registration-progress p{margin:0;color:#92400e;font-weight:500}.registration-ui .registration-card .registration-success{padding:2rem;background:#f0fdf4;border-radius:8px}.registration-ui .registration-card .registration-success i{font-size:4rem;color:#10b981;margin-bottom:1rem}.registration-ui .registration-card .registration-success h4{margin:0 0 .5rem;color:#064e3b;font-size:1.5rem;font-weight:700}.registration-ui .registration-card .registration-success p{margin:0;color:#065f46}.default-execution-view{display:flex;justify-content:center;align-items:center;min-height:400px}.default-execution-view .execution-status{text-align:center;padding:3rem;background:#fff;border-radius:12px;box-shadow:0 4px 6px #0000000d;min-width:400px}.default-execution-view .execution-status i{font-size:5rem;margin-bottom:1.5rem}.default-execution-view .execution-status h3{margin:0 0 .75rem;font-size:1.75rem;font-weight:700}.default-execution-view .execution-status p{margin:0;color:#64748b;line-height:1.7}.default-execution-view .execution-status .status-running i{color:#f59e0b}.default-execution-view .execution-status .status-finished i{color:#10b981}.default-execution-view .execution-status .status-error i{color:#ef4444}.execution-logs-panel{margin-top:2rem;background:#fff;border-radius:12px;padding:1.5rem;box-shadow:0 4px 6px #0000000d}.execution-logs-panel h3{display:flex;align-items:center;gap:.5rem;margin:0 0 1rem;color:#1e293b;font-size:1.125rem}.execution-logs-panel h3 i{color:#8b5cf6}.execution-logs-panel .logs-container-compact{max-height:300px;overflow-y:auto;background:#f8fafc;border-radius:8px;padding:.75rem}.execution-logs-panel .logs-container-compact .log-item-compact{display:flex;align-items:center;gap:.75rem;padding:.5rem .75rem;border-radius:6px;margin-bottom:.5rem;font-size:.875rem}.execution-logs-panel .logs-container-compact .log-item-compact:last-child{margin-bottom:0}.execution-logs-panel .logs-container-compact .log-item-compact .log-time{font-family:Courier New,monospace;color:#64748b;font-size:.8125rem;min-width:70px}.execution-logs-panel .logs-container-compact .log-item-compact .log-icon{display:flex;align-items:center;justify-content:center;width:20px}.execution-logs-panel .logs-container-compact .log-item-compact .log-icon i{font-size:1rem}.execution-logs-panel .logs-container-compact .log-item-compact .log-message{flex:1;color:#334155}.execution-logs-panel .logs-container-compact .log-item-compact.log-info{background:#eff6ff}.execution-logs-panel .logs-container-compact .log-item-compact.log-info .log-icon i{color:#3b82f6}.execution-logs-panel .logs-container-compact .log-item-compact.log-success{background:#f0fdf4}.execution-logs-panel .logs-container-compact .log-item-compact.log-success .log-icon i{color:#10b981}.execution-logs-panel .logs-container-compact .log-item-compact.log-warning{background:#fffbeb}.execution-logs-panel .logs-container-compact .log-item-compact.log-warning .log-icon i{color:#f59e0b}.execution-logs-panel .logs-container-compact .log-item-compact.log-error{background:#fef2f2}.execution-logs-panel .logs-container-compact .log-item-compact.log-error .log-icon i{color:#ef4444}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-10px)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXButtonGroupModule }, { kind: "component", type: i2$1.AXButtonGroupComponent, selector: "ax-button-group", inputs: ["disabled", "color", "look", "fitParent", "selection"], outputs: ["onBlur", "onFocus", "lookChange", "colorChange", "disabledChange", "onClick", "selectionChange", "selectedButtonChange"] }, { kind: "component", type: i2$1.AXButtonGroupItemComponent, selector: "ax-button-group-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "component", type: i4.AXTextBoxComponent, selector: "ax-text-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "maxLength", "allowNull", "type", "autoComplete", "look", "maskPattern", "customTokens", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress", "onMaskChanged"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i5.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXSwitchModule }, { kind: "component", type: i6.AXSwitchComponent, selector: "ax-switch", inputs: ["disabled", "readonly", "color", "tabIndex", "value", "name", "isLoading"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged", "readonlyChange", "disabledChange"] }, { kind: "ngmodule", type: AXTabsModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPPageLayoutComponent, selector: "axp-page-layout" }, { kind: "component", type: AXPPropertyViewerComponent, selector: "axp-property-viewer", inputs: ["tabsInput", "mode", "bindingExpressionEditorMode"], outputs: ["onChanged"] }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer-container, axp-page-footer, axp-page-header, axp-page-header-container, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "component", type: AXPThemeLayoutHeaderComponent, selector: "axp-layout-header" }, { kind: "component", type: AXPThemeLayoutToolbarComponent, selector: "axp-layout-toolbar" }, { kind: "component", type: AXPThemeLayoutStartSideComponent, selector: "axp-layout-page-start-side, axp-layout-start-side" }, { kind: "component", type: AXMActivityCategoriesTreeComponent, selector: "axp-activity-categories-tree", outputs: ["categoryClick", "activityClick", "activityDragStart"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i7.JsonPipe, name: "json" }, { kind: "pipe", type: i7.DatePipe, name: "date" }, { kind: "pipe", type: i5$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5638
- }
5639
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WorkflowStudioComponent, decorators: [{
5640
- type: Component,
5641
- args: [{ selector: 'app-workflow-studio', standalone: true, imports: [
5642
- CommonModule,
5643
- FormsModule,
5644
- AXButtonModule,
5645
- AXButtonGroupModule,
5646
- AXDecoratorModule,
5647
- AXTextBoxModule,
5648
- AXSelectBoxModule,
5649
- AXSearchBoxModule,
5650
- AXSwitchModule,
5651
- AXTabsModule,
5652
- AXTranslationModule,
5653
- AXPPageLayoutComponent,
5654
- AXPPropertyViewerComponent,
5655
- AXPThemeLayoutBlockComponent,
5656
- AXPThemeLayoutHeaderComponent,
5657
- AXPThemeLayoutToolbarComponent,
5658
- AXPThemeLayoutStartSideComponent,
5659
- AXMActivityCategoriesTreeComponent,
5660
- ], providers: [
5661
- {
5662
- provide: AXPPageLayoutBase,
5663
- useExisting: WorkflowStudioComponent,
5664
- },
5665
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<axp-page-layout>\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>{{ '@workflow-management:activities.menus.activity-categories.title' | translate | async }}</axp-layout-title>\n <axp-layout-toolbar>\n <ax-search-box\n [delayTime]=\"300\"\n [placeholder]=\"'@workflow-management:workflow-studio.components.activity-categories-tree.search-placeholder' | translate | async\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n </axp-layout-toolbar>\n </axp-layout-header>\n <axp-layout-content>\n <axp-activity-categories-tree\n (categoryClick)=\"onCategoryClick($event)\"\n (activityClick)=\"onActivityClick($event)\"\n (activityDragStart)=\"onActivityDragStartFromTree($event)\"\n ></axp-activity-categories-tree>\n </axp-layout-content>\n </axp-layout-start-side>\n\n <axp-page-toolbar>\n <axp-layout-prefix>\n <!-- JSON / Visual toggle (same pattern as report view mode) -->\n <div class=\"studio-editor-tabs\">\n <ax-button-group class=\"ax-sm\" [selection]=\"'single'\">\n <ax-button-group-item (onClick)=\"switchTab('json')\" text=\"{{ '@workflow-management:workflow-studio.terms.json-editor' | translate | async }}\" [selected]=\"activeTab() === 'json'\">\n <ax-prefix>\n <i class=\"fa-light fa-code\"></i>\n </ax-prefix>\n </ax-button-group-item>\n <ax-button-group-item (onClick)=\"switchTab('visual')\" text=\"{{ '@workflow-management:workflow-studio.terms.visual-designer' | translate | async }}\" [selected]=\"activeTab() === 'visual'\">\n <ax-prefix>\n <i class=\"fa-light fa-diagram-project\"></i>\n </ax-prefix>\n </ax-button-group-item>\n </ax-button-group>\n </div>\n </axp-layout-prefix>\n </axp-page-toolbar>\n\n <axp-page-content>\n <div class=\"workflow-studio\">\n <!-- Main Layout -->\n <div class=\"studio-body\" [class.properties-hidden]=\"!showPropertiesPanel()\">\n\n <!-- Editor -->\n <div class=\"studio-editor\">\n <!-- Tab Content -->\n <div class=\"editor-content\">\n <!-- JSON Tab -->\n @if (activeTab() === 'json') {\n <div class=\"json-tab\">\n <textarea class=\"json-editor\" [value]=\"workflowJson()\"\n (input)=\"onWorkflowJsonInput($event)\"\n [placeholder]=\"'@workflow-management:workflow-studio.components.json-editor.placeholder' | translate | async\"\n spellcheck=\"false\"></textarea>\n </div>\n }\n\n <!-- Visual Tab -->\n @if (activeTab() === 'visual') {\n <div class=\"visual-tab\">\n <!-- Canvas -->\n <div class=\"visual-canvas\">\n <div class=\"canvas-toolbar\">\n <ax-button look=\"blank\" class=\"ax-sm\" [attr.title]=\"'@workflow-management:workflow-studio.components.canvas-toolbar.zoom-to-fit.title' | translate | async\" (onClick)=\"canvasZoomToFit()\">\n <ax-prefix><i class=\"fa-light fa-expand\"></i></ax-prefix>\n </ax-button>\n <ax-button look=\"blank\" class=\"ax-sm\" [attr.title]=\"'@workflow-management:workflow-studio.components.canvas-toolbar.center.title' | translate | async\" (onClick)=\"canvasCenter()\">\n <ax-prefix><i class=\"fa-light fa-crosshairs\"></i></ax-prefix>\n </ax-button>\n <ax-button look=\"blank\" class=\"ax-sm\" [attr.title]=\"'@workflow-management:workflow-studio.components.canvas-toolbar.auto-layout.title' | translate | async\" (onClick)=\"canvasAutoLayout()\">\n <ax-prefix><i class=\"fa-light fa-sitemap\"></i></ax-prefix>\n </ax-button>\n <span class=\"toolbar-sep\"></span>\n <label class=\"toolbar-auto-save\">\n <ax-switch [value]=\"autoSaveEnabled()\" (valueChange)=\"autoSaveEnabled.set($event)\"></ax-switch>\n <span>{{ '@workflow-management:workflow-studio.components.canvas-toolbar.auto-save' | translate | async }}</span>\n </label>\n <span class=\"toolbar-sep\"></span>\n <ax-button look=\"blank\" class=\"ax-sm\" [attr.title]=\"'@workflow-management:workflow-studio.components.canvas-toolbar.clear-canvas.title' | translate | async\" (onClick)=\"clearCanvas()\">\n <ax-prefix><i class=\"fa-light fa-trash\"></i></ax-prefix>\n </ax-button>\n <ax-button look=\"blank\" class=\"ax-sm\" [attr.title]=\"'@workflow-management:workflow-studio.components.canvas-toolbar.convert-to-json.title' | translate | async\" (onClick)=\"visualToJson()\">\n <ax-prefix><i class=\"fa-light fa-code\"></i></ax-prefix>\n </ax-button>\n <span class=\"tool-info\">\n <i class=\"fa-light fa-lightbulb\"></i>\n <strong>{{ '@workflow-management:workflow-studio.components.canvas-toolbar.hint' | translate | async }}</strong>\n </span>\n </div>\n\n <div #canvasAreaRef class=\"canvas-area\" (drop)=\"onCanvasDrop($event)\" (dragover)=\"onCanvasDragOver($event)\"\n (dragleave)=\"onCanvasDragLeave($event)\">\n <!-- SVG for Connections -->\n <svg class=\"connections-layer\">\n <!-- Outcome-based Connections -->\n @for (node of visualNodes(); track node.id) {\n @if (node.outcomeConnections && node.outcomeConnections.length > 0) {\n @for (conn of node.outcomeConnections; track conn.targetNodeId + conn.outcome) {\n @let targetNode = findNodeById(conn.targetNodeId);\n @if (targetNode) {\n <g class=\"outcome-connection-group\">\n <line [attr.x1]=\"node.position.x + 75\" [attr.y1]=\"node.position.y + 80\"\n [attr.x2]=\"targetNode.position.x + 75\" [attr.y2]=\"targetNode.position.y - 50\"\n class=\"connection-line outcome-line\" [attr.stroke]=\"getOutcomeColor(conn.outcome)\"\n stroke-width=\"2.5\"\n [attr.marker-end]=\"'url(#arrowhead-' + getOutcomeColorName(conn.outcome) + ')'\"\n style=\"cursor: pointer\" (dblclick)=\"disconnectNodes(node.id, conn.targetNodeId, conn.outcome)\"\n [attr.title]=\"'Outcome: ' + conn.outcome + ' (Double-click to remove)'\">\n <title>{{ conn.outcome }} \u00E2\u2020\u2019 {{ targetNode.name }}</title>\n </line>\n <text [attr.x]=\"(node.position.x + targetNode.position.x) / 2 + 75\"\n [attr.y]=\"(node.position.y + targetNode.position.y) / 2 + 15\" class=\"connection-label\"\n text-anchor=\"middle\" dominant-baseline=\"middle\" [attr.fill]=\"getOutcomeColor(conn.outcome)\" font-size=\"11\"\n font-weight=\"600\" pointer-events=\"none\">\n {{ conn.outcome }}\n </text>\n </g>\n }\n }\n } @else {\n <!-- Simple Connections (backward compatibility) -->\n @for (targetId of node.connections; track targetId) {\n @let targetNode = findNodeById(targetId);\n @if (targetNode) {\n @let sx = node.position.x + 75;\n @let sy = node.position.y + 40;\n @let tx = targetNode.position.x + 75;\n @let ty = targetNode.position.y - 50;\n @let pathD = getConnectionPath(sx, sy, tx, ty);\n <g class=\"connection-group\">\n <path [attr.d]=\"pathD\" class=\"connection-line connection-hit\" fill=\"none\" stroke=\"transparent\"\n stroke-width=\"16\" pointer-events=\"stroke\" (dblclick)=\"disconnectNodes(node.id, targetId)\">\n </path>\n <path [attr.d]=\"pathD\" class=\"connection-line\" fill=\"none\" stroke=\"#64748b\" stroke-width=\"2\"\n stroke-linecap=\"round\" marker-end=\"url(#arrowhead-default)\" pointer-events=\"none\">\n </path>\n <title>{{ '@workflow-management:workflow-studio.components.canvas-toolbar.connection-remove-hint' | translate | async }}</title>\n </g>\n }\n }\n }\n }\n\n <defs>\n <!-- Arrow markers: larger, rounded tip on line end (refX so tip touches path end) -->\n <marker id=\"arrowhead-default\" markerWidth=\"12\" markerHeight=\"12\" refX=\"10\" refY=\"4\" orient=\"auto\">\n <polygon points=\"0 0, 12 4, 0 8\" fill=\"#64748b\" />\n </marker>\n <marker id=\"arrowhead-primary\" markerWidth=\"12\" markerHeight=\"12\" refX=\"10\" refY=\"4\" orient=\"auto\">\n <polygon points=\"0 0, 12 4, 0 8\" fill=\"#8b5cf6\" />\n </marker>\n <marker id=\"arrowhead-success\" markerWidth=\"12\" markerHeight=\"12\" refX=\"10\" refY=\"4\" orient=\"auto\">\n <polygon points=\"0 0, 12 4, 0 8\" fill=\"#10b981\" />\n </marker>\n <marker id=\"arrowhead-error\" markerWidth=\"12\" markerHeight=\"12\" refX=\"10\" refY=\"4\" orient=\"auto\">\n <polygon points=\"0 0, 12 4, 0 8\" fill=\"#ef4444\" />\n </marker>\n <marker id=\"arrowhead-warning\" markerWidth=\"12\" markerHeight=\"12\" refX=\"10\" refY=\"4\" orient=\"auto\">\n <polygon points=\"0 0, 12 4, 0 8\" fill=\"#f59e0b\" />\n </marker>\n <marker id=\"arrowhead-info\" markerWidth=\"12\" markerHeight=\"12\" refX=\"10\" refY=\"4\" orient=\"auto\">\n <polygon points=\"0 0, 12 4, 0 8\" fill=\"#3b82f6\" />\n </marker>\n </defs>\n </svg>\n\n <!-- Nodes -->\n @for (node of visualNodes(); track node.id) {\n <div class=\"visual-node\" [class.selected]=\"selectedNode()?.id === node.id\"\n [style.left.px]=\"node.position.x\" [style.top.px]=\"node.position.y\" [attr.data-node-id]=\"node.id\"\n draggable=\"true\" (dragstart)=\"onNodeDragStart($event, node)\" (drag)=\"onNodeDrag($event, node)\"\n (dragend)=\"onNodeDragEnd($event, node)\" (click)=\"selectNodeById(node)\">\n <div class=\"node-header\">\n <i [class]=\"node.icon\"></i>\n <span>{{ node.name }}</span>\n <span class=\"node-delete-wrap\" (click)=\"$event.stopPropagation()\">\n <ax-button look=\"blank\" size=\"sm\" class=\"node-delete\" (onClick)=\"deleteNodeFromCanvas(node.id)\">\n <ax-prefix><i class=\"fa-light fa-times\"></i></ax-prefix>\n </ax-button>\n </span>\n </div>\n\n <div class=\"node-body\">\n <small>{{ node.type }}</small>\n </div>\n\n <div class=\"node-connectors\">\n <!-- Input Connector -->\n <div class=\"connector connector-in\" title=\"Input\" (click)=\"onConnectorClick($event, node, 'in')\">\n </div>\n\n <!-- Output Connectors - Multiple outcomes support -->\n @if (node.outcomes && node.outcomes.length > 1) {\n <!-- Multiple outcomes: show separate port for each -->\n <div class=\"outcomes-container\">\n @for (outcome of node.outcomes; track outcome; let idx = $index) {\n <div class=\"outcome-connector\" [class.active]=\"\n connectionSource?.node?.id === node.id && connectionSource?.outcome === outcome\n \" [attr.data-outcome]=\"outcome\" [title]=\"'Output: ' + outcome\"\n (click)=\"onOutcomeConnectorClick($event, node, outcome)\">\n <span class=\"outcome-label\">{{ outcome }}</span>\n <div class=\"outcome-dot\"></div>\n </div>\n }\n </div>\n } @else {\n <!-- Single outcome: show simple output connector -->\n <div class=\"connector connector-out\" [class.active]=\"connectionSource?.node?.id === node.id\"\n title=\"Output\" (click)=\"onConnectorClick($event, node, 'out')\"></div>\n }\n </div>\n </div>\n }\n\n <!-- Empty State -->\n @if (visualNodes().length === 0) {\n <div class=\"canvas-empty-state\">\n <i class=\"fa-light fa-diagram-project\"></i>\n <p>{{ '@workflow-management:workflow-studio.components.canvas-empty-state.title' | translate | async }}</p>\n <small>{{ '@workflow-management:workflow-studio.components.canvas-empty-state.description' | translate | async }}</small>\n </div>\n }\n </div>\n </div>\n\n <!-- Workflow Panel (when no node selected, Elsa-style) -->\n @if (!selectedNode() && showPropertiesPanel()) {\n <div class=\"properties-panel workflow-panel\">\n <div class=\"properties-header\">\n <i class=\"fa-light fa-diagram-project\"></i>\n <h4>{{ '@workflow-management:workflow-studio.components.workflow-panel.title' | translate | async }}</h4>\n <div class=\"header-actions\">\n <ax-button look=\"blank\" size=\"sm\" [title]=\"'@workflow-management:workflow-studio.components.properties-panel.actions.close-panel' | translate | async\" (onClick)=\"togglePropertiesPanel()\">\n <ax-prefix><i class=\"fa-light fa-angle-right\"></i></ax-prefix>\n </ax-button>\n </div>\n </div>\n <div class=\"properties-body\">\n <section class=\"workflow-panel-section\">\n <h5>{{ '@workflow-management:workflow-studio.components.workflow-panel.metadata' | translate | async }}</h5>\n <div class=\"property-row\">\n <label>{{ '@workflow-management:workflow-studio.components.workflow-panel.name' | translate | async }}</label>\n <ax-text-box class=\"form-input\" [value]=\"workflowSettings().name\" [disabled]=\"true\" />\n </div>\n <div class=\"property-row\">\n <label>{{ '@workflow-management:workflow-studio.components.workflow-panel.description' | translate | async }}</label>\n <ax-text-box class=\"form-input\" [value]=\"workflowSettings().description\" [disabled]=\"true\" />\n </div>\n </section>\n <div class=\"properties-divider\"></div>\n <section class=\"workflow-panel-section\">\n <h5>{{ '@workflow-management:workflow-studio.components.workflow-panel.information' | translate | async }}</h5>\n <div class=\"workflow-info-table\">\n <div class=\"workflow-info-row\">\n <span class=\"info-label\">{{ '@workflow-management:workflow-studio.components.workflow-panel.definition-id' | translate | async }}</span>\n <span class=\"info-actions\">\n <ax-button look=\"blank\" size=\"sm\" [title]=\"'@workflow-management:workflow-studio.components.workflow-panel.copy' | translate | async\" (onClick)=\"copyDefinitionIdToClipboard()\">\n <ax-prefix><i class=\"fa-light fa-copy\"></i></ax-prefix>\n </ax-button>\n </span>\n <span class=\"info-value\">{{ workflowSettings().definitionId || 'new-workflow' }}</span>\n </div>\n <div class=\"workflow-info-row\">\n <span class=\"info-label\">{{ '@workflow-management:workflow-studio.components.workflow-panel.version' | translate | async }}</span>\n <span class=\"info-value\">{{ workflowSettings().version }}</span>\n </div>\n <div class=\"workflow-info-row\">\n <span class=\"info-label\">{{ '@workflow-management:workflow-studio.components.workflow-panel.status' | translate | async }}</span>\n <span class=\"info-value\">{{ workflowSettings().isPublished ? ('@workflow-management:workflow-studio.components.workflow-panel.published' | translate | async) : ('@workflow-management:workflow-studio.components.workflow-panel.draft' | translate | async) }}</span>\n </div>\n <div class=\"workflow-info-row\">\n <span class=\"info-label\">{{ '@workflow-management:workflow-studio.components.workflow-panel.usable-as-activity' | translate | async }}</span>\n <span class=\"info-value\">{{ workflowSettings().usableAsActivity ? ('@general:terms.common.yes-no.yes' | translate | async) : ('@general:terms.common.yes-no.no' | translate | async) }}</span>\n </div>\n </div>\n </section>\n <p class=\"properties-hint\">{{ '@workflow-management:workflow-studio.components.workflow-panel.settings-hint' | translate | async }}</p>\n </div>\n </div>\n }\n\n <!-- Properties Panel (when a node is selected) -->\n @if (selectedNode() && showPropertiesPanel()) {\n <div class=\"properties-panel\">\n <div class=\"properties-header\">\n <i class=\"fa-light fa-sliders\"></i>\n <h4>{{ '@workflow-management:workflow-studio.components.properties-panel.title' | translate | async }}</h4>\n <div class=\"header-actions\">\n <ax-button look=\"blank\" size=\"sm\" [title]=\"'@workflow-management:workflow-studio.components.properties-panel.actions.close-panel' | translate | async\" (onClick)=\"togglePropertiesPanel()\">\n <ax-prefix><i class=\"fa-light fa-angle-right\"></i></ax-prefix>\n </ax-button>\n <ax-button look=\"blank\" size=\"sm\" [title]=\"'@workflow-management:workflow-studio.components.properties-panel.actions.close' | translate | async\" (onClick)=\"selectedNode.set(null)\">\n <ax-prefix><i class=\"fa-light fa-times\"></i></ax-prefix>\n </ax-button>\n </div>\n </div>\n <div class=\"properties-body\">\n @if (propertyViewerTabs().length > 0) {\n <div class=\"properties-widget-section\">\n <axp-property-viewer\n #propertyViewerRef\n [tabsInput]=\"propertyViewerTabs()\"\n [mode]=\"'simple'\"\n (onChanged)=\"onPropertyViewerChanged($event)\">\n </axp-property-viewer>\n </div>\n } @else {\n <div class=\"property-row\">\n <label>{{ '@workflow-management:workflow-studio.components.properties-panel.fields.id' | translate | async }}:</label>\n <ax-text-box class=\"form-input\" [value]=\"selectedNode()!.id\" [disabled]=\"true\" />\n </div>\n <div class=\"property-row\">\n <label>{{ '@workflow-management:workflow-studio.components.properties-panel.fields.type' | translate | async }}:</label>\n <ax-text-box class=\"form-input\" [value]=\"selectedNode()!.type\" [disabled]=\"true\" />\n </div>\n <div class=\"property-row\">\n <label>{{ '@workflow-management:workflow-studio.components.properties-panel.fields.name' | translate | async }}:</label>\n <ax-text-box class=\"form-input\" [value]=\"selectedNode()!.name\"\n (valueChange)=\"updateNodeProperty(selectedNode()!.id, 'name', $event)\" />\n </div>\n <p class=\"no-properties\">\n {{ '@workflow-management:workflow-studio.components.properties-panel.empty-states.no-properties' | translate | async }}\n </p>\n }\n\n <div class=\"properties-divider\"></div>\n\n\n <h5>\u00F0\u0178\u201D\u2014 {{ '@workflow-management:workflow-studio.components.properties-panel.sections.connections' | translate | async }}</h5>\n <small class=\"properties-hint\">{{ '@workflow-management:workflow-studio.components.properties-panel.sections.connections-hint' | translate | async }}</small>\n\n <!-- Outcome-based Connections -->\n @if (selectedNode()!.outcomeConnections && selectedNode()!.outcomeConnections!.length > 0) {\n <div class=\"connections-list\">\n @for (conn of selectedNode()!.outcomeConnections!; track conn.targetNodeId + conn.outcome) {\n @let targetNode = findNodeById(conn.targetNodeId);\n @if (targetNode) {\n <div class=\"connection-item outcome-connection\">\n <span class=\"outcome-badge\" [style.background]=\"getOutcomeColor(conn.outcome)\">\n {{ conn.outcome }}\n </span>\n <i class=\"fa-light fa-arrow-right\"></i>\n <span>{{ targetNode.name }}</span>\n <ax-button look=\"blank\" size=\"sm\" class=\"remove-btn\"\n [title]=\"'@workflow-management:workflow-studio.components.properties-panel.actions.remove-connection' | translate | async\"\n (onClick)=\"disconnectNodes(selectedNode()!.id, conn.targetNodeId, conn.outcome)\">\n <ax-prefix><i class=\"fa-light fa-times\"></i></ax-prefix>\n </ax-button>\n </div>\n }\n }\n </div>\n } @else if (selectedNode()!.connections.length > 0) {\n <!-- Simple Connections (fallback) -->\n <div class=\"connections-list\">\n @for (targetId of selectedNode()!.connections; track targetId) {\n @let targetNode = findNodeById(targetId);\n @if (targetNode) {\n <div class=\"connection-item\">\n <i class=\"fa-light fa-arrow-right\"></i>\n <span>{{ targetNode.name }}</span>\n <ax-button look=\"blank\" size=\"sm\" class=\"remove-btn\"\n [title]=\"'@workflow-management:workflow-studio.components.properties-panel.actions.remove-connection' | translate | async\"\n (onClick)=\"disconnectNodes(selectedNode()!.id, targetId)\">\n <ax-prefix><i class=\"fa-light fa-times\"></i></ax-prefix>\n </ax-button>\n </div>\n }\n }\n </div>\n } @else {\n <p class=\"no-properties\">{{ '@workflow-management:workflow-studio.components.properties-panel.empty-states.no-connections' | translate | async }}</p>\n }\n\n <!-- Available Outcomes Info -->\n @if (selectedNode()!.outcomes && selectedNode()!.outcomes!.length > 1) {\n <div class=\"properties-divider\"></div>\n <h5>\u00F0\u0178\u201C\u00A4 {{ '@workflow-management:workflow-studio.components.properties-panel.sections.available-outcomes' | translate | async }}</h5>\n <small class=\"properties-hint\">{{ '@workflow-management:workflow-studio.components.properties-panel.sections.available-outcomes-hint' | translate | async }}</small>\n <div class=\"outcomes-info\">\n @for (outcome of selectedNode()!.outcomes!; track outcome) {\n <span class=\"outcome-tag\" [style.borderColor]=\"getOutcomeColor(outcome)\">\n <span class=\"outcome-dot\" [style.background]=\"getOutcomeColor(outcome)\"></span>\n {{ outcome }}\n </span>\n }\n </div>\n }\n\n <div class=\"properties-divider\"></div>\n\n <h5>\u00F0\u0178\u201C\u009D {{ '@workflow-management:workflow-studio.components.properties-panel.sections.raw-json' | translate | async }}</h5>\n <pre class=\"properties-json\">{{ selectedNode() | json }}</pre>\n </div>\n </div>\n }\n\n <!-- Toggle Button for Properties (when closed) -->\n @if (!showPropertiesPanel()) {\n <ax-button look=\"blank\" class=\"sidebar-toggle-btn right\" (onClick)=\"togglePropertiesPanel()\"\n [title]=\"selectedNode() ? ('@workflow-management:workflow-studio.components.properties-panel.actions.show-panel' | translate | async) : ('@workflow-management:workflow-studio.components.workflow-panel.show-panel' | translate | async)\">\n <ax-prefix><i class=\"fa-light fa-sliders\"></i></ax-prefix>\n </ax-button>\n }\n </div>\n }\n </div>\n </div>\n\n </div>\n\n <!-- Workflow Settings: opened via Layout Builder dialog in openWorkflowSettings() -->\n\n <!-- Workflow Execution Dialog -->\n @if (showExecutionDialog()) {\n <div class=\"execution-dialog-overlay\" (click)=\"closeExecutionDialog()\">\n <div class=\"execution-dialog\" (click)=\"$event.stopPropagation()\">\n <!-- Dialog Header -->\n <div class=\"execution-dialog-header\">\n <div class=\"header-content\">\n <i class=\"fa-light fa-play-circle\"></i>\n <div class=\"header-info\">\n <h2>{{ '@workflow-management:test-pages.workflow-studio.actions.execute-workflow.title' | translate |\n async }}</h2>\n <p>{{ '@workflow-management:test-pages.workflow-studio.actions.execute-workflow.description' | translate\n | async }}</p>\n </div>\n </div>\n <ax-button look=\"blank\" size=\"sm\" class=\"close-btn\" [disabled]=\"isExecuting()\" (onClick)=\"closeExecutionDialog()\">\n <ax-prefix><i class=\"fa-light fa-times\"></i></ax-prefix>\n </ax-button>\n </div>\n\n <!-- Dialog Body -->\n <div class=\"execution-dialog-body\">\n <!-- Workflow Info Panel (Before Execution) -->\n @if (!workflowInstanceState()) {\n <div class=\"workflow-info-panel\">\n <div class=\"start-section\">\n <div class=\"start-illustration\">\n <i class=\"fa-light fa-rocket\"></i>\n </div>\n <h3>{{ '@workflow-management:test-pages.workflow-studio.messages.info.ready-to-execute' | translate |\n async }}</h3>\n <p>{{ '@workflow-management:test-pages.workflow-studio.messages.info.click-to-start' | translate | async\n }}</p>\n <ax-button\n [text]=\"'@workflow-management:test-pages.workflow-studio.actions.start-execution.title' | translate | async\"\n color=\"success\" size=\"lg\" (onClick)=\"startWorkflowExecution()\">\n </ax-button>\n </div>\n </div>\n }\n\n\n <!-- Custom UI for Registration -->\n @if (false) {\n <div class=\"registration-ui\">\n <div class=\"registration-card\">\n <div class=\"registration-icon\">\n <i class=\"fa-light fa-user-circle\"></i>\n </div>\n <h3>\u00D9\u0081\u00D8\u00B1\u00D8\u00A2\u00DB\u0152\u00D9\u2020\u00D8\u00AF \u00D8\u00AB\u00D8\u00A8\u00D8\u00AA\u00E2\u20AC\u0152\u00D9\u2020\u00D8\u00A7\u00D9\u2026</h3>\n <p class=\"registration-desc\">\n \u00D8\u00A7\u00DB\u0152\u00D9\u2020 \u00D9\u0081\u00D9\u201E\u00D9\u02C6 \u00D8\u00B4\u00D8\u00A7\u00D9\u2026\u00D9\u201E \u00DA\u2020\u00D9\u2020\u00D8\u00AF \u00D9\u2026\u00D8\u00B1\u00D8\u00AD\u00D9\u201E\u00D9\u2021 \u00D8\u00A7\u00D8\u00B3\u00D8\u00AA \u00DA\u00A9\u00D9\u2021 \u00D8\u00AF\u00D8\u00A7\u00D8\u00AF\u00D9\u2021\u00E2\u20AC\u0152\u00D9\u2021\u00D8\u00A7\u00DB\u0152 \u00DA\u00A9\u00D8\u00A7\u00D8\u00B1\u00D8\u00A8\u00D8\u00B1 \u00D8\u00B1\u00D8\u00A7 \u00D8\u00AC\u00D9\u2026\u00D8\u00B9\u00E2\u20AC\u0152\u00D8\u00A2\u00D9\u02C6\u00D8\u00B1\u00DB\u0152 \u00DA\u00A9\u00D8\u00B1\u00D8\u00AF\u00D9\u2021 \u00D9\u02C6 \u00D8\u00AF\u00D8\u00B1 \u00D9\u2020\u00D9\u2021\u00D8\u00A7\u00DB\u0152\u00D8\u00AA \u00D8\u00AD\u00D8\u00B3\u00D8\u00A7\u00D8\u00A8 \u00DA\u00A9\u00D8\u00A7\u00D8\u00B1\u00D8\u00A8\u00D8\u00B1\u00DB\u0152 \u00D8\u00A7\u00DB\u0152\u00D8\u00AC\u00D8\u00A7\u00D8\u00AF \u00D9\u2026\u00DB\u0152\u00E2\u20AC\u0152\u00DA\u00A9\u00D9\u2020\u00D8\u00AF.\n </p>\n\n @if (workflowInstanceState()?.status === 'running') {\n <div class=\"registration-progress\">\n <div class=\"progress-spinner\">\n <i class=\"fa-light fa-spinner-third fa-spin\"></i>\n </div>\n <p>\u00D8\u00AF\u00D8\u00B1 \u00D8\u00AD\u00D8\u00A7\u00D9\u201E \u00D8\u00A7\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7\u00DB\u0152 \u00D9\u2026\u00D8\u00B1\u00D8\u00A7\u00D8\u00AD\u00D9\u201E \u00D8\u00AB\u00D8\u00A8\u00D8\u00AA\u00E2\u20AC\u0152\u00D9\u2020\u00D8\u00A7\u00D9\u2026...</p>\n </div>\n }\n\n @if (workflowInstanceState()?.status === 'finished') {\n <div class=\"registration-success\">\n <i class=\"fa-light fa-check-circle\"></i>\n <h4>\u00D8\u00AB\u00D8\u00A8\u00D8\u00AA\u00E2\u20AC\u0152\u00D9\u2020\u00D8\u00A7\u00D9\u2026 \u00D8\u00A8\u00D8\u00A7 \u00D9\u2026\u00D9\u02C6\u00D9\u0081\u00D9\u201A\u00DB\u0152\u00D8\u00AA \u00D8\u00A7\u00D9\u2020\u00D8\u00AC\u00D8\u00A7\u00D9\u2026 \u00D8\u00B4\u00D8\u00AF!</h4>\n <p>\u00D8\u00AD\u00D8\u00B3\u00D8\u00A7\u00D8\u00A8 \u00DA\u00A9\u00D8\u00A7\u00D8\u00B1\u00D8\u00A8\u00D8\u00B1\u00DB\u0152 \u00D8\u00B4\u00D9\u2026\u00D8\u00A7 \u00D8\u00A7\u00DB\u0152\u00D8\u00AC\u00D8\u00A7\u00D8\u00AF \u00D8\u00B4\u00D8\u00AF \u00D9\u02C6 \u00D8\u00A8\u00D9\u2021 \u00D8\u00B2\u00D9\u02C6\u00D8\u00AF\u00DB\u0152 \u00D8\u00A8\u00D9\u2021 \u00D8\u00AF\u00D8\u00A7\u00D8\u00B4\u00D8\u00A8\u00D9\u02C6\u00D8\u00B1\u00D8\u00AF \u00D9\u2026\u00D9\u2020\u00D8\u00AA\u00D9\u201A\u00D9\u201E \u00D8\u00AE\u00D9\u02C6\u00D8\u00A7\u00D9\u2021\u00DB\u0152\u00D8\u00AF \u00D8\u00B4\u00D8\u00AF.</p>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Default Execution View -->\n @if (workflowInstanceState()) {\n <div class=\"default-execution-view\">\n <div class=\"execution-status\">\n @if (workflowInstanceState()?.status === 'running') {\n <div class=\"status-running\">\n <i class=\"fa-light fa-spinner-third fa-spin\"></i>\n <h3>\u00D8\u00AF\u00D8\u00B1 \u00D8\u00AD\u00D8\u00A7\u00D9\u201E \u00D8\u00A7\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7...</h3>\n <p>Workflow \u00D8\u00AF\u00D8\u00B1 \u00D8\u00AD\u00D8\u00A7\u00D9\u201E \u00D8\u00A7\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7 \u00D8\u00A7\u00D8\u00B3\u00D8\u00AA. \u00D9\u201E\u00D8\u00B7\u00D9\u0081\u00D8\u00A7\u00D9\u2039 \u00D8\u00B5\u00D8\u00A8\u00D8\u00B1 \u00DA\u00A9\u00D9\u2020\u00DB\u0152\u00D8\u00AF.</p>\n </div>\n }\n\n @if (workflowInstanceState()?.status === 'finished') {\n <div class=\"status-finished\">\n <i class=\"fa-light fa-check-circle\"></i>\n <h3>\u00D8\u00A7\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7 \u00D8\u00A8\u00D8\u00A7 \u00D9\u2026\u00D9\u02C6\u00D9\u0081\u00D9\u201A\u00DB\u0152\u00D8\u00AA \u00D8\u00AA\u00DA\u00A9\u00D9\u2026\u00DB\u0152\u00D9\u201E \u00D8\u00B4\u00D8\u00AF</h3>\n <p>Workflow \u00D8\u00A8\u00D8\u00A7 \u00D9\u2026\u00D9\u02C6\u00D9\u0081\u00D9\u201A\u00DB\u0152\u00D8\u00AA \u00D8\u00A7\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7 \u00D8\u00B4\u00D8\u00AF \u00D9\u02C6 \u00D8\u00AA\u00D9\u2026\u00D8\u00A7\u00D9\u2026 Activities \u00D8\u00A7\u00D9\u2020\u00D8\u00AC\u00D8\u00A7\u00D9\u2026 \u00D8\u00B4\u00D8\u00AF\u00D9\u2020\u00D8\u00AF.</p>\n </div>\n }\n\n @if (workflowInstanceState()?.status === 'error') {\n <div class=\"status-error\">\n <i class=\"fa-light fa-times-circle\"></i>\n <h3>\u00D8\u00AE\u00D8\u00B7\u00D8\u00A7 \u00D8\u00AF\u00D8\u00B1 \u00D8\u00A7\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7</h3>\n <p>{{ workflowInstanceState()?.error }}</p>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Execution Logs Panel -->\n @if (workflowInstanceState() && executionLogs().length > 0) {\n <div class=\"execution-logs-panel\">\n <h3><i class=\"fa-light fa-terminal\"></i> \u00D9\u201E\u00D8\u00A7\u00DA\u00AF\u00E2\u20AC\u0152\u00D9\u2021\u00D8\u00A7\u00DB\u0152 \u00D8\u00A7\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7</h3>\n <div class=\"logs-container-compact\">\n @for (log of executionLogs(); track $index) {\n <div class=\"log-item-compact\" [class]=\"'log-' + log.level\">\n <span class=\"log-time\">{{ log.timestamp | date: 'HH:mm:ss' }}</span>\n <span class=\"log-icon\">\n @switch (log.level) {\n @case ('info') {\n <i class=\"fa-light fa-info-circle\"></i>\n }\n @case ('success') {\n <i class=\"fa-light fa-check-circle\"></i>\n }\n @case ('warning') {\n <i class=\"fa-light fa-exclamation-triangle\"></i>\n }\n @case ('error') {\n <i class=\"fa-light fa-times-circle\"></i>\n }\n }\n </span>\n <span class=\"log-message\">{{ log.message }}</span>\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Dialog Footer -->\n <div class=\"execution-dialog-footer\">\n <div class=\"footer-info\">\n @if (workflowInstanceState()?.startTime) {\n <span class=\"time-info\">\n <i class=\"fa-light fa-clock\"></i>\n \u00D8\u00B4\u00D8\u00B1\u00D9\u02C6\u00D8\u00B9: {{ workflowInstanceState()!.startTime | date: 'HH:mm:ss' }}\n </span>\n }\n @if (workflowInstanceState()?.endTime) {\n <span class=\"time-info\">\n <i class=\"fa-light fa-flag-checkered\"></i>\n \u00D9\u00BE\u00D8\u00A7\u00DB\u0152\u00D8\u00A7\u00D9\u2020: {{ workflowInstanceState()!.endTime | date: 'HH:mm:ss' }}\n </span>\n }\n </div>\n <div class=\"footer-actions\">\n <ax-button\n [text]=\"(workflowInstanceState() ? '@general:actions.close.title' : '@general:actions.cancel.title') | translate | async\"\n color=\"secondary\" size=\"md\" [disabled]=\"isExecuting()\" (onClick)=\"closeExecutionDialog()\">\n </ax-button>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n </axp-page-content>\n</axp-page-layout>\n", styles: [".sidebar-header .toggle-btn{padding:.5rem;margin-left:auto;background:transparent;border:1px solid #e2e8f0;border-radius:6px;color:#64748b;cursor:pointer;transition:all .2s}.sidebar-header .toggle-btn:hover{background:#f8fafc;border-color:#8b5cf6;color:#8b5cf6}.sidebar-header .toggle-btn i{font-size:.875rem}.sidebar-toggle-btn{position:absolute;top:50%;transform:translateY(-50%);z-index:100;padding:1rem .5rem;background:#fff;border:1px solid #e2e8f0;border-radius:8px;color:#8b5cf6;cursor:pointer;box-shadow:0 4px 12px #0000001a;transition:all .3s}.sidebar-toggle-btn:hover{background:#8b5cf6;color:#fff;box-shadow:0 8px 24px #8b5cf64d;transform:translateY(-50%) scale(1.1)}.sidebar-toggle-btn.left{left:0;border-left:none;border-radius:0 8px 8px 0}.sidebar-toggle-btn.right{right:0;border-right:none;border-radius:8px 0 0 8px}.sidebar-toggle-btn i{font-size:1.25rem;display:block}.properties-header .header-actions{display:flex;gap:.5rem;margin-left:auto}.properties-header .header-btn{padding:.375rem .5rem;background:transparent;border:1px solid #e2e8f0;border-radius:4px;color:#64748b;cursor:pointer;transition:all .2s}.properties-header .header-btn:hover{background:#f8fafc;border-color:#8b5cf6;color:#8b5cf6}.properties-header .header-btn i{font-size:.75rem}.connections-list{margin-top:.75rem}.connection-item{display:flex;align-items:center;gap:.5rem;padding:.5rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;margin-bottom:.5rem;font-size:.875rem}.connection-item i{color:#8b5cf6}.connection-item span{flex:1;color:#1e293b}.connection-item .remove-btn{padding:.25rem .375rem;background:transparent;border:1px solid #e2e8f0;border-radius:4px;color:#ef4444;cursor:pointer;transition:all .2s}.connection-item .remove-btn:hover{background:#fef2f2;border-color:#ef4444}.connection-item .remove-btn i{font-size:.75rem;color:inherit}.property-editor{margin-top:.75rem}.property-editor .property-row label{display:flex;align-items:center;gap:.5rem;justify-content:space-between}.property-editor .property-row label .property-type-badge{padding:.125rem .375rem;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;font-size:.625rem;font-weight:400;color:#64748b;text-transform:lowercase;font-family:JetBrains Mono,monospace}.property-editor .property-row select{width:100%;padding:.5rem;border:1px solid #e2e8f0;border-radius:6px;font-size:.875rem;color:#1e293b;background:#fff;cursor:pointer;transition:all .2s}.property-editor .property-row select:focus{outline:none;border-color:#8b5cf6;box-shadow:0 0 0 3px #8b5cf61a}.property-editor .property-row textarea{width:100%;padding:.5rem;border:1px solid #e2e8f0;border-radius:6px;font-size:.75rem;font-family:JetBrains Mono,monospace;color:#1e293b;resize:vertical;transition:all .2s}.property-editor .property-row textarea:focus{outline:none;border-color:#8b5cf6;box-shadow:0 0 0 3px #8b5cf61a}.workflow-studio{display:flex;flex-direction:column;height:100vh;background:#f8fafc;overflow:hidden}.studio-editor-tabs ax-button-group-item[selected],.studio-editor-tabs ax-button-group-item.ax-selected{font-weight:600;opacity:1}.workflow-popup .popup-header{text-align:center;margin-bottom:1.5rem;padding-bottom:1rem;border-bottom:2px solid #e2e8f0}.workflow-popup .popup-header h3{margin:0 0 .5rem;color:#1e293b;font-size:1.5rem;font-weight:700}.workflow-popup .popup-header p{margin:0;color:#64748b;font-size:.95rem}.workflow-popup .popup-body{max-height:60vh;overflow-y:auto;padding:0 .5rem}.workflow-popup .popup-body h4{margin:1.5rem 0 .75rem;color:#374151;font-size:1.1rem;font-weight:600;display:flex;align-items:center;gap:.5rem}.workflow-popup .popup-body ul{margin:0;padding-left:1.5rem}.workflow-popup .popup-body ul li{margin-bottom:.5rem;color:#4b5563}.workflow-popup .popup-body ul li strong{color:#1f2937}.workflow-popup .workflow-info{background:#f8fafc;padding:1rem;border-radius:8px;border:1px solid #e2e8f0}.workflow-popup .workflow-variables{background:#fef3c7;padding:1rem;border-radius:8px;border:1px solid #f59e0b}.workflow-popup .workflow-flow{background:#ecfdf5;padding:1rem;border-radius:8px;border:1px solid #10b981}.workflow-popup .workflow-flow .flow-steps{display:flex;flex-direction:column;gap:.75rem}.workflow-popup .workflow-flow .flow-steps .flow-step{display:flex;align-items:center;gap:.75rem;padding:.5rem;background:#fff;border-radius:6px;border:1px solid #d1d5db}.workflow-popup .workflow-flow .flow-steps .flow-step .step-number{display:flex;align-items:center;justify-content:center;width:24px;height:24px;background:#3b82f6;color:#fff;border-radius:50%;font-size:.8rem;font-weight:600}.workflow-popup .workflow-flow .flow-steps .flow-step .step-text{color:#374151;font-weight:500}.workflow-popup .workflow-json{background:#1f2937;padding:1rem;border-radius:8px;border:1px solid #374151}.workflow-popup .workflow-json .json-preview{background:transparent;color:#e5e7eb;font-family:Monaco,Menlo,Ubuntu Mono,monospace;font-size:.8rem;line-height:1.4;margin:0;white-space:pre-wrap;word-break:break-all;max-height:200px;overflow-y:auto}.workflow-popup .popup-footer{text-align:center;margin-top:1.5rem;padding-top:1rem;border-top:1px solid #e2e8f0}.workflow-popup .popup-footer .btn{padding:.75rem 1.5rem;background:#3b82f6;color:#fff;border:none;border-radius:6px;font-weight:600;cursor:pointer;display:inline-flex;align-items:center;gap:.5rem;transition:background-color .2s}.workflow-popup .popup-footer .btn:hover{background:#2563eb}.workflow-popup .popup-footer .btn i{font-size:.9rem}.view-workflow-link{color:#3b82f6;text-decoration:none;font-size:.85rem;margin-left:.5rem;transition:color .2s}.view-workflow-link:hover{color:#1d4ed8;text-decoration:underline}.studio-header{display:flex;justify-content:space-between;align-items:center;padding:1rem 1.5rem;background:#fff;border-bottom:1px solid #e2e8f0;box-shadow:0 1px 3px #0000000d}.studio-header .header-title{display:flex;align-items:center;gap:.75rem}.studio-header .header-title i{font-size:1.75rem;color:#8b5cf6}.studio-header .header-title h1{margin:0;font-size:1.5rem;font-weight:700;color:#1e293b}.studio-header .header-title .badge{padding:.25rem .75rem;background:#8b5cf6;color:#fff;border-radius:12px;font-size:.75rem;font-weight:600}.studio-header .header-actions{display:flex;gap:.75rem;align-items:center}.samples-dropdown{position:relative}.samples-dropdown .samples-menu{position:absolute;top:calc(100% + .5rem);left:0;min-width:320px;background:#fff;border:1px solid #e2e8f0;border-radius:8px;box-shadow:0 10px 25px #0000001a;z-index:1000;max-height:400px;overflow-y:auto}.samples-dropdown .samples-menu .sample-item{padding:.875rem 1rem;display:flex;align-items:flex-start;gap:.75rem;cursor:pointer;border-bottom:1px solid #f1f5f9;transition:all .2s}.samples-dropdown .samples-menu .sample-item:last-child{border-bottom:none}.samples-dropdown .samples-menu .sample-item:hover{background:#f8fafc;transform:translate(4px)}.samples-dropdown .samples-menu .sample-item i{font-size:1.25rem;margin-top:.125rem;color:#8b5cf6}.samples-dropdown .samples-menu .sample-item .sample-info{display:flex;flex-direction:column;gap:.25rem;flex:1}.samples-dropdown .samples-menu .sample-item .sample-info strong{color:#1e293b;font-size:.875rem;font-weight:600}.samples-dropdown .samples-menu .sample-item .sample-info span{color:#64748b;font-size:.75rem;line-height:1.4}.studio-body{display:grid;grid-template-columns:1fr;gap:0;flex:1;overflow:hidden;transition:grid-template-columns .3s ease}.studio-body.sidebar-hidden,.studio-body.properties-hidden,.studio-body.sidebar-hidden.properties-hidden{grid-template-columns:1fr}.studio-sidebar{background:#fff;border-right:1px solid #e2e8f0;display:flex;flex-direction:column;overflow:hidden}.studio-sidebar .sidebar-header{padding:1rem 1.25rem;border-bottom:1px solid #e2e8f0;display:flex;align-items:center;gap:.5rem}.studio-sidebar .sidebar-header i{font-size:1.25rem;color:#8b5cf6}.studio-sidebar .sidebar-header h3{flex:1;margin:0;font-size:1.125rem;font-weight:600;color:#1e293b}.activities-tree{flex:1;overflow-y:auto;padding:.5rem}.category-section{margin-bottom:.5rem}.category-section .category-header{display:flex;align-items:center;gap:.5rem;padding:.75rem;border-radius:8px;cursor:pointer;transition:all .2s;background:#f8fafc}.category-section .category-header:hover{background:#f1f5f9}.category-section .category-header.active{background:#ede9fe}.category-section .category-header.active>i:first-child{color:#8b5cf6}.category-section .category-header>i:first-child{font-size:.875rem;color:#94a3b8;transition:transform .2s,color .2s}.category-section .category-header>i:nth-child(2){font-size:1.125rem}.category-section .category-header span{flex:1;font-weight:600;font-size:.875rem;color:#334155}.category-section .category-header .count{flex:none;padding:.125rem .5rem;background:#fff;border-radius:10px;font-size:.75rem;font-weight:600;color:#64748b;border:1px solid #e2e8f0}.activities-list{padding:.5rem 0 .5rem 1.5rem;display:flex;flex-direction:column;gap:.5rem;animation:slideDown .3s ease}.activities-list .activities-header{padding:.5rem .75rem;margin-bottom:.5rem}.activities-list .activities-header h4{margin:0;font-size:.875rem;font-weight:600;color:#64748b;text-transform:uppercase;letter-spacing:.5px}.activity-card{background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:.875rem;margin-bottom:.75rem;transition:all .2s}.activity-card:hover{border-color:#8b5cf6;box-shadow:0 4px 12px #8b5cf61a;transform:translateY(-1px)}.activity-card .activity-info{display:flex;align-items:flex-start;gap:.75rem;margin-bottom:.5rem}.activity-card .activity-info>i{font-size:1.5rem;color:#8b5cf6;margin-top:.125rem}.activity-card .activity-info .activity-details{flex:1;display:flex;flex-direction:column;gap:.25rem}.activity-card .activity-info .activity-details strong{font-size:.875rem;color:#1e293b}.activity-card .activity-info .activity-details small{font-size:.75rem;color:#64748b;line-height:1.4}.activity-card .activity-info .activity-details code{font-size:.75rem;color:#8b5cf6;background:#f3f0ff;padding:.125rem .375rem;border-radius:4px;width:fit-content}.activity-card .copy-btn{float:right;padding:.375rem .75rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;cursor:pointer;transition:all .2s;color:#64748b}.activity-card .copy-btn:hover{background:#8b5cf6;border-color:#8b5cf6;color:#fff}.activity-card .copy-btn i{font-size:.875rem}.activity-card .activity-properties{margin-top:.75rem;padding-top:.75rem;border-top:1px solid #f1f5f9}.activity-card .activity-properties .properties-title{display:block;font-size:.75rem;font-weight:600;color:#64748b;margin-bottom:.5rem}.activity-card .activity-properties .property-item{display:flex;align-items:center;gap:.5rem;padding:.25rem 0;font-size:.75rem}.activity-card .activity-properties .property-item code{color:#1e293b;background:#f8fafc;padding:.125rem .375rem;border-radius:3px}.activity-card .activity-properties .property-item .property-type{color:#64748b;font-style:italic}.activity-card .activity-properties .property-item .required{color:#ef4444;font-weight:700}.studio-editor{display:flex;flex-direction:column;background:#1e293b;overflow:hidden}.studio-editor .editor-header{padding:1rem 1.25rem;background:#0f172a;display:flex;align-items:center;gap:.5rem}.studio-editor .editor-header i{font-size:1.125rem;color:#8b5cf6}.studio-editor .editor-header h3{margin:0;font-size:1rem;font-weight:600;color:#e2e8f0}.studio-editor axp-page-toolbar .editor-tabs{display:flex;gap:.5rem;background:transparent}.studio-editor axp-page-toolbar .editor-tabs .tab-btn{padding:.5rem 1rem;background:transparent;border:1px solid #e2e8f0;border-radius:6px;color:#64748b;font-size:.875rem;font-weight:500;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center;gap:.5rem}.studio-editor axp-page-toolbar .editor-tabs .tab-btn i{font-size:.875rem}.studio-editor axp-page-toolbar .editor-tabs .tab-btn:hover{background:#f8fafc;border-color:#cbd5e1;color:#475569}.studio-editor axp-page-toolbar .editor-tabs .tab-btn.active{background:#8b5cf6;border-color:#8b5cf6;color:#fff}.studio-editor .editor-content{flex:1;display:flex;overflow:hidden}.studio-editor .json-tab{flex:1;display:flex;flex-direction:column}.studio-editor .json-editor{flex:1;padding:1.5rem;background:#1e293b;color:#e2e8f0;border:none;outline:none;font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:.875rem;line-height:1.6;resize:none;overflow:auto}.studio-editor .json-editor::placeholder{color:#475569}.studio-editor .json-editor::-webkit-scrollbar{width:10px;height:10px}.studio-editor .json-editor::-webkit-scrollbar-track{background:#0f172a}.studio-editor .json-editor::-webkit-scrollbar-thumb{background:#475569;border-radius:5px}.studio-editor .json-editor::-webkit-scrollbar-thumb:hover{background:#64748b}.studio-editor .visual-tab{flex:1;display:flex;background:#f8fafc;position:relative}.studio-editor .visual-canvas{flex:1;display:flex;flex-direction:column;overflow:hidden}.studio-editor .visual-canvas .canvas-toolbar{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem;background:var(--ax-surface, white);border-bottom:1px solid var(--ax-border, #e2e8f0)}.studio-editor .visual-canvas .canvas-toolbar .tool-btn{padding:.5rem .75rem;background:var(--ax-surface-alt, #f8fafc);border:1px solid var(--ax-border, #e2e8f0);border-radius:6px;color:var(--ax-text-muted, #64748b);cursor:pointer;transition:all .2s}.studio-editor .visual-canvas .canvas-toolbar .tool-btn:hover{background:#8b5cf6;border-color:#8b5cf6;color:#fff}.studio-editor .visual-canvas .canvas-toolbar .tool-btn i{font-size:.875rem}.studio-editor .visual-canvas .canvas-toolbar .toolbar-sep{width:1px;height:1.25rem;background:var(--ax-border, #e2e8f0);flex-shrink:0}.studio-editor .visual-canvas .canvas-toolbar .toolbar-auto-save{display:flex;align-items:center;gap:.5rem;font-size:.8125rem;color:var(--ax-text-muted, #64748b);cursor:default}.studio-editor .visual-canvas .canvas-toolbar .toolbar-auto-save ax-switch{flex-shrink:0}.studio-editor .visual-canvas .canvas-toolbar .tool-info{flex:1;display:flex;align-items:center;gap:.5rem;min-height:1.75rem;font-size:.8125rem;color:var(--ax-text-muted, #64748b);line-height:1.4}.studio-editor .visual-canvas .canvas-toolbar .tool-info strong{font-weight:600}.studio-editor .visual-canvas .canvas-toolbar .tool-info i{font-size:1rem;color:#8b5cf6;flex-shrink:0}.studio-editor .visual-canvas .canvas-area{flex:1;position:relative;background:linear-gradient(90deg,#e5e7eb 1px,transparent 1px),linear-gradient(#e5e7eb 1px,transparent 1px);background-size:20px 20px;overflow:auto;min-height:600px}.studio-editor .visual-canvas .connections-layer{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:1}.studio-editor .visual-canvas .connection-line{fill:none;transition:stroke .2s}.studio-editor .visual-canvas .connection-line.connection-hit{stroke:transparent;stroke-width:16;cursor:pointer;pointer-events:stroke}.studio-editor .visual-canvas .connection-line.connection-hit:hover~.outcome-line,.studio-editor .visual-canvas .connection-line.connection-hit:hover~.connection-line:not(.connection-hit){filter:brightness(.9)}.studio-editor .visual-canvas .connection-line:not(.connection-hit){stroke-linecap:round;pointer-events:none}.studio-editor .visual-canvas .connection-line.outcome-line{stroke-width:2.5}.studio-editor .visual-canvas .visual-node{position:absolute;width:150px;background:#fff;border:2px solid #e2e8f0;border-radius:8px;box-shadow:0 2px 8px #0000001a;cursor:move;transition:all .2s;z-index:2}.studio-editor .visual-canvas .visual-node:hover{border-color:#8b5cf6;box-shadow:0 4px 16px #8b5cf633;transform:translateY(-2px)}.studio-editor .visual-canvas .visual-node.selected{border-color:#8b5cf6;border-width:3px;box-shadow:0 0 0 3px #8b5cf633}.studio-editor .visual-canvas .visual-node .node-header{display:flex;align-items:center;gap:.5rem;padding:.75rem;background:linear-gradient(135deg,#8b5cf6,#7c3aed);color:#fff;border-radius:6px 6px 0 0;font-size:.875rem;font-weight:600}.studio-editor .visual-canvas .visual-node .node-header i{font-size:1rem}.studio-editor .visual-canvas .visual-node .node-header span{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.studio-editor .visual-canvas .visual-node .node-header .node-delete{padding:.25rem;background:#fff3;border:none;border-radius:4px;color:#fff;cursor:pointer;transition:all .2s}.studio-editor .visual-canvas .visual-node .node-header .node-delete:hover{background:#ef4444cc}.studio-editor .visual-canvas .visual-node .node-header .node-delete i{font-size:.75rem}.studio-editor .visual-canvas .visual-node .node-body{padding:.75rem}.studio-editor .visual-canvas .visual-node .node-body small{display:block;font-size:.75rem;color:#64748b;text-align:center}.studio-editor .visual-canvas .visual-node .node-connectors{position:relative}.studio-editor .visual-canvas .visual-node .node-connectors .connector{position:absolute;width:12px;height:12px;background:#8b5cf6;border:2px solid white;border-radius:50%;cursor:pointer;transition:all .2s;z-index:10}.studio-editor .visual-canvas .visual-node .node-connectors .connector:hover{transform:scale(1.3);box-shadow:0 0 0 3px #8b5cf64d}.studio-editor .visual-canvas .visual-node .node-connectors .connector-in{top:-50px;left:50%;transform:translate(-50%);background:#3b82f6}.studio-editor .visual-canvas .visual-node .node-connectors .connector-out{bottom:-6px;left:50%;transform:translate(-50%);background:#8b5cf6}.studio-editor .visual-canvas .visual-node .node-connectors .connector-out.active{background:#ef4444}.studio-editor .visual-canvas .visual-node .node-connectors .outcomes-container{position:absolute;bottom:-60px;left:50%;transform:translate(-50%);display:flex;flex-direction:column;gap:8px;background:#fff;padding:8px;border:1px solid #e2e8f0;border-radius:8px;box-shadow:0 4px 12px #00000026;min-width:120px;z-index:100}.studio-editor .visual-canvas .visual-node .node-connectors .outcomes-container:before{content:\"\";position:absolute;top:-8px;left:50%;transform:translate(-50%);width:0;height:0;border-left:8px solid transparent;border-right:8px solid transparent;border-bottom:8px solid white;filter:drop-shadow(0 -2px 2px rgba(0,0,0,.05))}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector{display:flex;align-items:center;justify-content:space-between;padding:6px 10px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;cursor:pointer;transition:all .2s;position:relative}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector:hover{background:#f1f5f9;border-color:#8b5cf6;transform:translate(2px)}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector.active{background:#fef2f2;border-color:#ef4444}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector.active .outcome-dot{background:#ef4444;box-shadow:0 0 0 3px #ef444433}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector .outcome-label{font-size:.75rem;font-weight:600;color:#475569;-webkit-user-select:none;user-select:none;flex:1}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector .outcome-dot{width:10px;height:10px;background:#8b5cf6;border:2px solid white;border-radius:50%;transition:all .2s;flex-shrink:0}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=\"200\"] .outcome-dot,.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=Done] .outcome-dot{background:#10b981}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=\"404\"] .outcome-dot,.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=Failed] .outcome-dot{background:#ef4444}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=Timeout] .outcome-dot,.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=Cancelled] .outcome-dot{background:#f59e0b}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=Then] .outcome-dot{background:#3b82f6}.studio-editor .visual-canvas .visual-node .node-connectors .outcome-connector[data-outcome=Else] .outcome-dot{background:#64748b}.studio-editor .visual-canvas .canvas-empty-state{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center;color:#94a3b8;pointer-events:none}.studio-editor .visual-canvas .canvas-empty-state i{font-size:4rem;margin-bottom:1rem;opacity:.5}.studio-editor .visual-canvas .canvas-empty-state p{margin:0 0 .5rem;font-size:1rem;font-weight:500}.studio-editor .visual-canvas .canvas-empty-state small{font-size:.875rem;opacity:.8}.studio-editor .properties-panel{width:280px;background:#fff;border-left:1px solid #e2e8f0;display:flex;flex-direction:column}.studio-editor .properties-panel .properties-header{display:flex;align-items:center;gap:.5rem;padding:1rem;border-bottom:1px solid #e2e8f0}.studio-editor .properties-panel .properties-header i{font-size:1.125rem;color:#8b5cf6}.studio-editor .properties-panel .properties-header h4{flex:1;margin:0;font-size:.875rem;font-weight:600;color:#1e293b}.studio-editor .properties-panel .properties-header button{padding:.25rem .5rem;background:transparent;border:none;color:#64748b;cursor:pointer;transition:color .2s}.studio-editor .properties-panel .properties-header button:hover{color:#ef4444}.studio-editor .properties-panel .properties-body{flex:1;padding:1rem;overflow-y:auto}.studio-editor .properties-panel .properties-body .properties-widget-section{min-height:0}.studio-editor .properties-panel .properties-body .workflow-panel-section{margin-bottom:1.5rem}.studio-editor .properties-panel .properties-body .workflow-panel-section h5{margin:0 0 .75rem;font-size:.75rem;font-weight:600;color:#64748b;text-transform:uppercase;letter-spacing:.5px}.studio-editor .properties-panel .properties-body .workflow-panel-section .form-group{margin-bottom:.75rem}.studio-editor .properties-panel .properties-body .workflow-panel-section .form-group label{font-size:.75rem}.studio-editor .properties-panel .properties-body .workflow-panel-section .form-group input,.studio-editor .properties-panel .properties-body .workflow-panel-section .form-group textarea{font-size:.8125rem}.studio-editor .properties-panel .properties-body .workflow-info-table{display:flex;flex-direction:column;gap:.5rem}.studio-editor .properties-panel .properties-body .workflow-info-row{display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:.5rem 0;border-bottom:1px solid #f1f5f9}.studio-editor .properties-panel .properties-body .workflow-info-row:last-child{border-bottom:none}.studio-editor .properties-panel .properties-body .info-label{font-size:.8125rem;font-weight:500;color:#64748b;flex-shrink:0}.studio-editor .properties-panel .properties-body .info-value{font-size:.8125rem;color:#1e293b;text-align:right;word-break:break-all}.studio-editor .properties-panel .properties-body .info-actions{display:flex;align-items:center;gap:.5rem}.studio-editor .properties-panel .properties-body .property-row{margin-bottom:1rem}.studio-editor .properties-panel .properties-body .property-row label{display:block;font-size:.75rem;font-weight:600;color:#64748b;margin-bottom:.375rem;text-transform:uppercase;letter-spacing:.5px}.studio-editor .properties-panel .properties-body .property-row input{width:100%;padding:.5rem;border:1px solid #e2e8f0;border-radius:6px;font-size:.875rem;color:#1e293b;transition:all .2s}.studio-editor .properties-panel .properties-body .property-row input:focus{outline:none;border-color:#8b5cf6;box-shadow:0 0 0 3px #8b5cf61a}.studio-editor .properties-panel .properties-body .property-row input:disabled{background:#f8fafc;color:#94a3b8;cursor:not-allowed}.studio-editor .properties-panel .properties-body .properties-divider{height:1px;background:#e2e8f0;margin:1.5rem 0}.studio-editor .properties-panel .properties-body h5{margin:0 0 .5rem;font-size:.75rem;font-weight:600;color:#64748b;text-transform:uppercase;letter-spacing:.5px}.studio-editor .properties-panel .properties-body .properties-hint{display:block;font-size:.75rem;color:#94a3b8;margin-bottom:.75rem}.studio-editor .properties-panel .properties-body .properties-json{margin:.75rem 0 0;padding:.75rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;font-family:JetBrains Mono,monospace;font-size:.75rem;line-height:1.6;color:#1e293b;overflow-x:auto}.studio-editor .properties-panel .properties-body .no-properties{margin:.75rem 0 0;padding:1rem;background:#f8fafc;border:1px dashed #cbd5e1;border-radius:6px;text-align:center;font-size:.75rem;color:#94a3b8}.studio-editor .properties-panel .properties-body .connections-list{display:flex;flex-direction:column;gap:.5rem;margin-top:.75rem}.studio-editor .properties-panel .properties-body .connections-list .connection-item{display:flex;align-items:center;gap:.5rem;padding:.5rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;font-size:.75rem}.studio-editor .properties-panel .properties-body .connections-list .connection-item.outcome-connection{border-left-width:3px}.studio-editor .properties-panel .properties-body .connections-list .connection-item i{color:#64748b;font-size:.875rem}.studio-editor .properties-panel .properties-body .connections-list .connection-item span{flex:1;color:#1e293b;font-weight:500}.studio-editor .properties-panel .properties-body .connections-list .connection-item .outcome-badge{padding:.25rem .5rem;border-radius:4px;color:#fff;font-size:.65rem;font-weight:700;text-transform:uppercase;letter-spacing:.5px}.studio-editor .properties-panel .properties-body .connections-list .connection-item .remove-btn{padding:.25rem;background:transparent;border:none;color:#ef4444;cursor:pointer;border-radius:4px;transition:all .2s}.studio-editor .properties-panel .properties-body .connections-list .connection-item .remove-btn:hover{background:#fee2e2}.studio-editor .properties-panel .properties-body .connections-list .connection-item .remove-btn i{font-size:.75rem;color:inherit}.studio-editor .properties-panel .properties-body .outcomes-info{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.75rem}.studio-editor .properties-panel .properties-body .outcomes-info .outcome-tag{display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .625rem;background:#fff;border:2px solid;border-radius:6px;font-size:.75rem;font-weight:600;color:#1e293b;transition:all .2s}.studio-editor .properties-panel .properties-body .outcomes-info .outcome-tag:hover{transform:translateY(-1px);box-shadow:0 2px 8px #0000001a}.studio-editor .properties-panel .properties-body .outcomes-info .outcome-tag .outcome-dot{width:8px;height:8px;border-radius:50%}.studio-result{display:flex;flex-direction:column;background:#fff;border-left:1px solid #e2e8f0;overflow:hidden}.studio-result .result-header{padding:1rem 1.25rem;border-bottom:1px solid #e2e8f0;display:flex;align-items:center;gap:.5rem}.studio-result .result-header i{font-size:1.125rem;color:#10b981}.studio-result .result-header h3{flex:1;margin:0;font-size:1rem;font-weight:600;color:#1e293b}.studio-result .result-header .clear-btn{padding:.375rem .75rem;background:#fee2e2;color:#dc2626;border:none;border-radius:6px;cursor:pointer;font-size:.75rem;font-weight:500;transition:all .2s}.studio-result .result-header .clear-btn:hover{background:#fecaca}.studio-result .result-header .clear-btn i{font-size:.75rem;color:inherit}.studio-result .result-body{flex:1;overflow-y:auto;padding:1rem}.logs-container{display:flex;flex-direction:column;gap:.5rem}.log-item{display:flex;align-items:flex-start;gap:.5rem;padding:.75rem;background:#f8fafc;border-left:3px solid #cbd5e1;border-radius:6px;font-size:.875rem}.log-item.log-info{border-left-color:#3b82f6;background:#eff6ff}.log-item.log-info .log-icon{color:#3b82f6}.log-item.log-success{border-left-color:#10b981;background:#f0fdf4}.log-item.log-success .log-icon{color:#10b981}.log-item.log-warning{border-left-color:#f59e0b;background:#fffbeb}.log-item.log-warning .log-icon{color:#f59e0b}.log-item.log-error{border-left-color:#ef4444;background:#fef2f2}.log-item.log-error .log-icon{color:#ef4444}.log-item .log-time{font-family:JetBrains Mono,monospace;font-size:.75rem;color:#64748b;min-width:80px}.log-item .log-icon{font-size:1rem}.log-item .log-message{flex:1;color:#1e293b}.log-item .log-data-toggle{padding:.25rem .5rem;background:transparent;border:1px solid #cbd5e1;border-radius:4px;cursor:pointer;transition:all .2s}.log-item .log-data-toggle:hover{background:#fff}.log-item .log-data-toggle i{font-size:.75rem;color:#64748b}.log-data{margin:.5rem 0 0;padding:1rem;background:#0f172a;color:#e2e8f0;border-radius:6px;font-family:JetBrains Mono,monospace;font-size:.75rem;line-height:1.6;overflow-x:auto}.settings-modal-overlay{position:fixed;inset:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:9999;padding:2rem;animation:fadeIn .2s ease}.settings-modal{background:#fff;border-radius:12px;box-shadow:0 20px 60px #0000004d;width:100%;max-width:900px;max-height:90vh;display:flex;flex-direction:column;animation:slideUp .3s ease}@keyframes slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}.settings-modal-header{display:flex;align-items:center;justify-content:space-between;padding:1.5rem 2rem;border-bottom:1px solid #e2e8f0}.settings-modal-header .header-title{display:flex;align-items:center;gap:.75rem}.settings-modal-header .header-title i{font-size:1.5rem;color:#8b5cf6}.settings-modal-header .header-title h2{margin:0;font-size:1.25rem;font-weight:700;color:#1e293b}.settings-modal-header .close-btn{padding:.5rem;background:transparent;border:none;color:#64748b;cursor:pointer;border-radius:6px;transition:all .2s}.settings-modal-header .close-btn:hover{background:#f1f5f9;color:#ef4444}.settings-modal-header .close-btn i{font-size:1.25rem}.settings-modal-body{flex:1;display:flex;flex-direction:column;overflow:hidden}.settings-tabs{padding:0 1.5rem}.settings-content{flex:1;overflow-y:auto;padding:2rem}.settings-section h3{margin:0 0 1.5rem;font-size:1rem;font-weight:600;color:#1e293b}.settings-section .section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem}.settings-section .section-header h3{margin:0}.settings-section .section-header .add-btn{display:flex;align-items:center;gap:.5rem;padding:.5rem 1rem;background:#8b5cf6;color:#fff;border:none;border-radius:6px;font-size:.875rem;font-weight:500;cursor:pointer;transition:all .2s}.settings-section .section-header .add-btn:hover{background:#7c3aed;transform:translateY(-1px);box-shadow:0 4px 12px #8b5cf64d}.settings-section .section-header .add-btn i{font-size:.875rem}.form-group{margin-bottom:1.25rem}.form-group label{display:block;font-size:.875rem;font-weight:600;color:#475569;margin-bottom:.5rem}.form-group small{display:block;font-size:.75rem;color:#94a3b8;margin-top:.375rem}.form-group.checkbox-group{margin-bottom:0}.form-group.checkbox-group label{display:flex;align-items:center;gap:.5rem;cursor:pointer;margin-bottom:0}.form-group.checkbox-group label input[type=checkbox]{width:18px;height:18px;cursor:pointer}.form-group.checkbox-group label span{font-size:.875rem;font-weight:500}.form-group.flex-1{flex:1}.form-row{display:flex;gap:1rem;align-items:flex-start}.form-input,.form-select,.form-textarea{width:100%;padding:.625rem;border:1px solid #e2e8f0;border-radius:6px;font-size:.875rem;color:#1e293b;transition:all .2s}.form-input:focus,.form-select:focus,.form-textarea:focus{outline:none;border-color:#8b5cf6;box-shadow:0 0 0 3px #8b5cf61a}.form-input::placeholder,.form-select::placeholder,.form-textarea::placeholder{color:#cbd5e1}.form-textarea{resize:vertical;font-family:inherit}.items-list{display:flex;flex-direction:column;gap:1rem}.item-card{background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;overflow:hidden;transition:all .2s}.item-card:hover{border-color:#cbd5e1;box-shadow:0 2px 8px #0000000d}.item-card .item-header{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;background:#f1f5f9;border-bottom:1px solid #e2e8f0}.item-card .item-header .item-number{font-size:.75rem;font-weight:700;color:#8b5cf6;padding:.25rem .5rem;background:#fff;border-radius:4px}.item-card .item-header .remove-btn{padding:.375rem .625rem;background:transparent;border:none;color:#ef4444;cursor:pointer;border-radius:4px;transition:all .2s}.item-card .item-header .remove-btn:hover{background:#fee2e2}.item-card .item-header .remove-btn i{font-size:.875rem}.item-card .item-body{padding:1rem}.advanced-group{margin-bottom:2rem;padding-bottom:2rem;border-bottom:1px solid #e2e8f0}.advanced-group:last-child{border-bottom:none;margin-bottom:0;padding-bottom:0}.advanced-group h4{margin:0 0 1rem;font-size:.875rem;font-weight:600;color:#475569;text-transform:uppercase;letter-spacing:.5px}.outcomes-preview{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.75rem}.outcomes-preview .outcome-chip{display:inline-flex;align-items:center;padding:.375rem .75rem;background:#f1f5f9;border:1px solid #cbd5e1;border-radius:6px;font-size:.75rem;font-weight:600;color:#475569}.export-info{margin-top:1rem;padding:1rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px}.export-info .info-row{display:flex;align-items:center;gap:.75rem;padding:.5rem 0;border-bottom:1px solid #e2e8f0}.export-info .info-row:last-child{border-bottom:none;padding-bottom:0}.export-info .info-row .label{font-size:.75rem;font-weight:600;color:#64748b;min-width:120px}.export-info .info-row code{flex:1;padding:.25rem .5rem;background:#fff;border:1px solid #e2e8f0;border-radius:4px;font-size:.75rem;color:#1e293b;font-family:JetBrains Mono,monospace}.settings-modal-footer{display:flex;align-items:center;justify-content:flex-end;gap:1rem;padding:1.5rem 2rem;border-top:1px solid #e2e8f0;background:#f8fafc}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem 1rem;text-align:center;color:#94a3b8}.empty-state i{font-size:3rem;margin-bottom:1rem}.empty-state p{margin:0;font-size:.875rem}.final-result{margin-top:1.5rem;padding-top:1.5rem;border-top:2px solid #e2e8f0}.final-result .result-header{display:flex;align-items:center;justify-content:space-between;padding:.75rem;background:#f8fafc;border-radius:8px;margin-bottom:1rem;cursor:pointer;transition:all .2s}.final-result .result-header:hover{background:#f1f5f9;transform:translate(-2px)}.final-result .result-header h4{display:flex;align-items:center;gap:.5rem;margin:0;font-size:.875rem;font-weight:600;color:#475569;text-transform:uppercase}.final-result .result-header h4 i{font-size:.875rem;transition:transform .2s}.final-result .result-header .toggle-hint{font-size:.75rem;color:#94a3b8}.final-result .result-card{background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;padding:1rem}.final-result .result-card .result-row{display:flex;align-items:center;gap:.75rem;padding:.5rem 0}.final-result .result-card .result-row:not(:last-child){border-bottom:1px solid #e2e8f0}.final-result .result-card .result-row strong{font-size:.875rem;color:#475569;min-width:100px}.final-result .result-card .result-row .badge{padding:.25rem .75rem;border-radius:12px;font-size:.75rem;font-weight:600}.final-result .result-card .result-row .badge.badge-running{background:#dbeafe;color:#1e40af}.final-result .result-card .result-row .badge.badge-finished{background:#d1fae5;color:#065f46}.final-result .result-card .result-row .badge.badge-cancelled{background:#fed7aa;color:#92400e}.final-result .result-card .result-row .badge.badge-faulted{background:#fee2e2;color:#991b1b}.final-result .result-card .result-row pre{margin:.5rem 0 0;padding:.75rem;background:#0f172a;color:#e2e8f0;border-radius:6px;font-family:JetBrains Mono,monospace;font-size:.75rem;line-height:1.6;overflow-x:auto;width:100%}.activities-list::-webkit-scrollbar,.result-body::-webkit-scrollbar{width:8px}.activities-list::-webkit-scrollbar-track,.result-body::-webkit-scrollbar-track{background:#f1f5f9}.activities-list::-webkit-scrollbar-thumb,.result-body::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:4px}.activities-list::-webkit-scrollbar-thumb:hover,.result-body::-webkit-scrollbar-thumb:hover{background:#94a3b8}.activity-card{cursor:grab}.activity-card:active{cursor:grabbing}.activity-card[draggable=true]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.visual-node[draggable=true]{cursor:move;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.visual-node:active{cursor:grabbing}.canvas-area[data-drag-over=true]{background-color:#8b5cf60d}.connector:hover{transform:scale(1.3);box-shadow:0 0 0 3px #8b5cf64d}.connector-out.active{animation:pulse 1s infinite}@keyframes pulse{0%,to{box-shadow:0 0 0 3px #ef44444d}50%{box-shadow:0 0 0 6px #ef44441a}}@keyframes slideDown{0%{opacity:0;max-height:0}to{opacity:1;max-height:2000px}}.execution-dialog-overlay{position:fixed;inset:0;background:#000000b3;backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;z-index:10000;animation:fadeIn .2s ease}.execution-dialog{width:90vw;max-width:1200px;height:90vh;background:#fff;border-radius:16px;box-shadow:0 25px 50px #0000004d;display:flex;flex-direction:column;overflow:hidden;animation:slideUp .3s ease}.execution-dialog-header{padding:1.5rem 2rem;background:linear-gradient(135deg,#8b5cf6,#7c3aed);color:#fff;display:flex;justify-content:space-between;align-items:center;flex-shrink:0}.execution-dialog-header .header-content{display:flex;align-items:center;gap:1rem;flex:1}.execution-dialog-header .header-content>i{font-size:2.5rem;opacity:.9}.execution-dialog-header .header-content .header-info h2{margin:0;font-size:1.75rem;font-weight:700}.execution-dialog-header .header-content .header-info p{margin:.25rem 0 0;opacity:.9;font-size:.95rem}.execution-dialog-header .close-btn{background:#fff3;border:none;width:40px;height:40px;border-radius:8px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s;color:#fff;font-size:1.25rem}.execution-dialog-header .close-btn:hover:not(:disabled){background:#ffffff4d;transform:scale(1.05)}.execution-dialog-header .close-btn:disabled{opacity:.5;cursor:not-allowed}.execution-dialog-body{flex:1;overflow-y:auto;padding:2rem;background:#f8fafc}.execution-dialog-footer{padding:1rem 2rem;background:#fff;border-top:1px solid #e2e8f0;display:flex;justify-content:space-between;align-items:center;flex-shrink:0}.execution-dialog-footer .footer-info{display:flex;gap:1.5rem}.execution-dialog-footer .footer-info .time-info{display:flex;align-items:center;gap:.5rem;color:#64748b;font-size:.875rem}.execution-dialog-footer .footer-info .time-info i{color:#8b5cf6}.execution-dialog-footer .footer-actions{display:flex;gap:.75rem}.workflow-info-panel{background:#fff;border-radius:12px;padding:2rem;box-shadow:0 4px 6px #0000000d}.workflow-info-panel .info-section{margin-bottom:2rem}.workflow-info-panel .info-section h3{display:flex;align-items:center;gap:.5rem;margin:0 0 1rem;color:#1e293b;font-size:1.25rem}.workflow-info-panel .info-section h3 i{color:#8b5cf6}.workflow-info-panel .info-section .description{color:#475569;line-height:1.7;margin:0}.workflow-info-panel .info-section .features-list{list-style:none;padding:0;margin:0;display:grid;gap:.75rem}.workflow-info-panel .info-section .features-list li{display:flex;align-items:center;gap:.75rem;padding:.75rem;background:#f8fafc;border-radius:8px;color:#334155}.workflow-info-panel .info-section .features-list li i{color:#10b981;font-size:1.125rem}.workflow-info-panel .start-section{text-align:center;padding:2rem;background:linear-gradient(135deg,#f0fdf4,#dcfce7);border-radius:12px;border:2px dashed #10b981}.workflow-info-panel .start-section .start-illustration{margin-bottom:1rem}.workflow-info-panel .start-section .start-illustration i{font-size:4rem;color:#10b981;animation:float 3s ease-in-out infinite}.workflow-info-panel .start-section h3{margin:0 0 .5rem;color:#1e293b;font-size:1.5rem}.workflow-info-panel .start-section p{margin:0 0 1.5rem;color:#64748b}.state-machine-ui .issue-tracker{background:#fff;border-radius:8px;overflow:hidden;box-shadow:0 1px 2px #0000000d}.state-machine-ui .issue-tracker .issue-header-main{padding:1.5rem 2rem 1rem;border-bottom:1px solid #e2e8f0}.state-machine-ui .issue-tracker .issue-header-main .issue-breadcrumb{display:flex;align-items:center;gap:.5rem;font-size:.875rem;color:#64748b;margin-bottom:.75rem}.state-machine-ui .issue-tracker .issue-header-main .issue-breadcrumb .project-name{color:#3b82f6;font-weight:600}.state-machine-ui .issue-tracker .issue-header-main .issue-breadcrumb .separator{color:#94a3b8}.state-machine-ui .issue-tracker .issue-header-main .issue-breadcrumb .issue-key{color:#64748b}.state-machine-ui .issue-tracker .issue-header-main .issue-type-title{display:flex;align-items:center;gap:.75rem}.state-machine-ui .issue-tracker .issue-header-main .issue-type-title .type-badge{padding:.375rem .75rem;border-radius:4px;font-size:.8125rem;font-weight:600;display:flex;align-items:center;gap:.375rem;background:#eff6ff;color:#3b82f6}.state-machine-ui .issue-tracker .issue-header-main .issue-type-title .type-badge i{font-size:1rem}.state-machine-ui .issue-tracker .issue-header-main .issue-type-title .issue-main-title{margin:0;font-size:1.5rem;font-weight:600;color:#1e293b}.state-machine-ui .issue-tracker .issue-action-bar{padding:.75rem 2rem;background:#f8fafc;border-bottom:1px solid #e2e8f0;display:flex;justify-content:space-between;align-items:center}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left{display:flex;gap:.5rem}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn{padding:.5rem 1rem;border:1px solid #cbd5e1;border-radius:4px;background:#fff;font-weight:500;font-size:.875rem;cursor:pointer;transition:all .2s;color:#334155}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn:hover:not(:disabled){background:#f1f5f9;border-color:#94a3b8}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn:disabled{opacity:.5;cursor:not-allowed}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn.btn-primary{background:#3b82f6;color:#fff;border-color:#3b82f6}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn.btn-primary:hover:not(:disabled){background:#2563eb}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn.btn-success{background:#10b981;color:#fff;border-color:#10b981}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn.btn-success:hover:not(:disabled){background:#059669}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn.btn-warning{background:#f59e0b;color:#fff;border-color:#f59e0b}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-left .status-transition-btn.btn-warning:hover:not(:disabled){background:#d97706}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-right .more-actions-btn{padding:.5rem 1rem;border:1px solid #cbd5e1;border-radius:4px;background:#fff;font-weight:500;font-size:.875rem;cursor:pointer;display:flex;align-items:center;gap:.5rem;color:#334155;transition:all .2s}.state-machine-ui .issue-tracker .issue-action-bar .action-bar-right .more-actions-btn:hover{background:#f1f5f9}.state-machine-ui .issue-tracker .issue-main-content{display:grid;grid-template-columns:320px 1fr;gap:2rem;padding:2rem}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section{margin-bottom:2rem}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section h3{margin:0 0 1rem;font-size:1rem;font-weight:600;color:#1e293b}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row{display:flex;padding:.625rem 0;border-bottom:1px solid #f1f5f9}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row:last-child{border-bottom:none}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row label{min-width:100px;font-size:.8125rem;color:#64748b;font-weight:500}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row .detail-value{display:flex;align-items:center;gap:.5rem;font-size:.875rem;color:#1e293b}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row .detail-value i{font-size:1rem}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row .detail-value .status-badge{padding:.25rem .625rem;border-radius:4px;color:#fff;font-weight:600;font-size:.75rem;text-transform:uppercase}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row .detail-value .view-workflow-link{color:#3b82f6;font-size:.8125rem;text-decoration:none;margin-left:.5rem}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row .detail-value .view-workflow-link:hover{text-decoration:underline}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .details-section .detail-row .detail-value .user-avatar{width:24px;height:24px;border-radius:50%;background:#8b5cf6;color:#fff;display:flex;align-items:center;justify-content:center;font-size:.75rem}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz{background:#f8fafc;border-radius:8px;padding:1.5rem;border:1px solid #e2e8f0}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz h3{margin:0 0 1rem;font-size:.875rem;font-weight:600;color:#1e293b}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow .flow-state{display:flex;flex-direction:column;align-items:center;gap:.375rem;opacity:.4;transition:opacity .2s}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow .flow-state.active,.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow .flow-state.completed{opacity:1}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow .flow-state .state-circle{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;color:#fff;font-size:.875rem;box-shadow:0 2px 4px #0000001a}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow .flow-state .state-name{font-size:.6875rem;color:#64748b;font-weight:500}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow .flow-state.active .state-name{color:#1e293b;font-weight:600}.state-machine-ui .issue-tracker .issue-main-content .issue-details-panel .state-machine-viz .states-flow .flow-arrow{color:#cbd5e1;font-size:.75rem;margin:0 .25rem}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .description-section,.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section{margin-bottom:2rem}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .description-section h3,.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section h3{margin:0 0 1rem;font-size:1rem;font-weight:600;color:#1e293b}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .description-section .description-content,.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .description-content{padding:1rem;background:#f8fafc;border-radius:6px;border:1px solid #e2e8f0}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .description-section .description-content p,.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .description-content p{margin:0;color:#475569;line-height:1.7;font-size:.875rem}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline{display:flex;flex-direction:column;gap:1rem}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item{display:flex;gap:.75rem}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item .activity-avatar{width:32px;height:32px;border-radius:50%;background:#8b5cf6;color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:.875rem}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item .activity-content{flex:1;padding-bottom:1rem;border-bottom:1px solid #f1f5f9}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item .activity-content .activity-header{font-size:.875rem;color:#334155;line-height:1.6;margin-bottom:.375rem}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item .activity-content .activity-header strong{color:#1e293b;font-weight:600}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item .activity-content .activity-header .activity-action{color:#64748b}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item .activity-content .activity-meta{display:flex;align-items:center;gap:.5rem;font-size:.8125rem;color:#94a3b8}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item .activity-content .activity-meta .activity-label{color:#8b5cf6;font-weight:500}.state-machine-ui .issue-tracker .issue-main-content .issue-description-panel .activity-section .activity-timeline .activity-item:last-child .activity-content{border-bottom:none;padding-bottom:0}.registration-ui{display:flex;justify-content:center;align-items:center;min-height:400px}.registration-ui .registration-card{background:#fff;border-radius:12px;padding:3rem;box-shadow:0 4px 6px #0000000d;text-align:center;max-width:500px}.registration-ui .registration-card .registration-icon{margin-bottom:1.5rem}.registration-ui .registration-card .registration-icon i{font-size:5rem;color:#8b5cf6}.registration-ui .registration-card h3{margin:0 0 .75rem;color:#1e293b;font-size:1.75rem;font-weight:700}.registration-ui .registration-card .registration-desc{margin:0 0 2rem;color:#64748b;line-height:1.7}.registration-ui .registration-card .registration-progress{padding:2rem;background:#fef3c7;border-radius:8px}.registration-ui .registration-card .registration-progress .progress-spinner{margin-bottom:1rem}.registration-ui .registration-card .registration-progress .progress-spinner i{font-size:3rem;color:#f59e0b}.registration-ui .registration-card .registration-progress p{margin:0;color:#92400e;font-weight:500}.registration-ui .registration-card .registration-success{padding:2rem;background:#f0fdf4;border-radius:8px}.registration-ui .registration-card .registration-success i{font-size:4rem;color:#10b981;margin-bottom:1rem}.registration-ui .registration-card .registration-success h4{margin:0 0 .5rem;color:#064e3b;font-size:1.5rem;font-weight:700}.registration-ui .registration-card .registration-success p{margin:0;color:#065f46}.default-execution-view{display:flex;justify-content:center;align-items:center;min-height:400px}.default-execution-view .execution-status{text-align:center;padding:3rem;background:#fff;border-radius:12px;box-shadow:0 4px 6px #0000000d;min-width:400px}.default-execution-view .execution-status i{font-size:5rem;margin-bottom:1.5rem}.default-execution-view .execution-status h3{margin:0 0 .75rem;font-size:1.75rem;font-weight:700}.default-execution-view .execution-status p{margin:0;color:#64748b;line-height:1.7}.default-execution-view .execution-status .status-running i{color:#f59e0b}.default-execution-view .execution-status .status-finished i{color:#10b981}.default-execution-view .execution-status .status-error i{color:#ef4444}.execution-logs-panel{margin-top:2rem;background:#fff;border-radius:12px;padding:1.5rem;box-shadow:0 4px 6px #0000000d}.execution-logs-panel h3{display:flex;align-items:center;gap:.5rem;margin:0 0 1rem;color:#1e293b;font-size:1.125rem}.execution-logs-panel h3 i{color:#8b5cf6}.execution-logs-panel .logs-container-compact{max-height:300px;overflow-y:auto;background:#f8fafc;border-radius:8px;padding:.75rem}.execution-logs-panel .logs-container-compact .log-item-compact{display:flex;align-items:center;gap:.75rem;padding:.5rem .75rem;border-radius:6px;margin-bottom:.5rem;font-size:.875rem}.execution-logs-panel .logs-container-compact .log-item-compact:last-child{margin-bottom:0}.execution-logs-panel .logs-container-compact .log-item-compact .log-time{font-family:Courier New,monospace;color:#64748b;font-size:.8125rem;min-width:70px}.execution-logs-panel .logs-container-compact .log-item-compact .log-icon{display:flex;align-items:center;justify-content:center;width:20px}.execution-logs-panel .logs-container-compact .log-item-compact .log-icon i{font-size:1rem}.execution-logs-panel .logs-container-compact .log-item-compact .log-message{flex:1;color:#334155}.execution-logs-panel .logs-container-compact .log-item-compact.log-info{background:#eff6ff}.execution-logs-panel .logs-container-compact .log-item-compact.log-info .log-icon i{color:#3b82f6}.execution-logs-panel .logs-container-compact .log-item-compact.log-success{background:#f0fdf4}.execution-logs-panel .logs-container-compact .log-item-compact.log-success .log-icon i{color:#10b981}.execution-logs-panel .logs-container-compact .log-item-compact.log-warning{background:#fffbeb}.execution-logs-panel .logs-container-compact .log-item-compact.log-warning .log-icon i{color:#f59e0b}.execution-logs-panel .logs-container-compact .log-item-compact.log-error{background:#fef2f2}.execution-logs-panel .logs-container-compact .log-item-compact.log-error .log-icon i{color:#ef4444}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-10px)}}\n"] }]
5666
- }], propDecorators: { propertyViewerRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPPropertyViewerComponent), { isSignal: true }] }], canvasAreaRef: [{ type: i0.ViewChild, args: ['canvasAreaRef', { isSignal: true }] }] } });
5667
-
5668
- var workflowStudio_component = /*#__PURE__*/Object.freeze({
5669
- __proto__: null,
5670
- WorkflowStudioComponent: WorkflowStudioComponent
5671
- });
5672
-
5673
3314
  /**
5674
3315
  * Generated bundle index. Do not edit.
5675
3316
  */
5676
3317
 
5677
- export { AXCCategoryProvider, AXMActivityCategoriesTreeComponent, AXMMenuProvider, AXMWorkflowActivitiesDefinitionProvider, AXMWorkflowManagementModule, AXMWorkflowManagementModuleEntityProvider, AXPCreateEntityActivity, AXPGenericWorkflowTaskProvider, AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG, CartableTaskActivity, CollectSignatureActivity, CreateEntityFormActivity, HumanTaskActivity, RootConfig, ShowConfirmPopupActivity, ShowLayoutPopupActivity, ShowToastActivity, WorkflowStudioComponent };
3318
+ export { AXCCategoryProvider, AXMMenuProvider, AXMWorkflowActivitiesDefinitionProvider, AXMWorkflowManagementModule, AXMWorkflowManagementModuleEntityProvider, AXPCreateEntityActivity, AXPGenericWorkflowTaskProvider, AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG, CartableTaskActivity, CollectSignatureActivity, CreateEntityFormActivity, HumanTaskActivity, RootConfig, ShowConfirmPopupActivity, ShowLayoutPopupActivity, ShowToastActivity };
5678
3319
  //# sourceMappingURL=acorex-modules-workflow-management.mjs.map