@acorex/modules 21.0.0-next.57 → 21.0.0-next.59

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 (165) hide show
  1. package/fesm2022/{acorex-modules-assessment-management-acorex-modules-assessment-management-DcPnI9fZ.mjs → acorex-modules-assessment-management-acorex-modules-assessment-management-o8aFazwA.mjs} +72 -78
  2. package/fesm2022/acorex-modules-assessment-management-acorex-modules-assessment-management-o8aFazwA.mjs.map +1 -0
  3. package/fesm2022/{acorex-modules-assessment-management-assessment-case.entity-D880d_qz.mjs → acorex-modules-assessment-management-assessment-case.entity-yrc_Yybq.mjs} +67 -71
  4. package/fesm2022/acorex-modules-assessment-management-assessment-case.entity-yrc_Yybq.mjs.map +1 -0
  5. package/fesm2022/acorex-modules-assessment-management-assessment-session-answers-view.util-BUQa_TSY.mjs +47 -0
  6. package/fesm2022/acorex-modules-assessment-management-assessment-session-answers-view.util-BUQa_TSY.mjs.map +1 -0
  7. package/fesm2022/{acorex-modules-assessment-management-assessment-session.entity-DvbocIN1.mjs → acorex-modules-assessment-management-assessment-session.entity-Cwf30iuu.mjs} +5 -41
  8. package/fesm2022/acorex-modules-assessment-management-assessment-session.entity-Cwf30iuu.mjs.map +1 -0
  9. package/fesm2022/{acorex-modules-assessment-management-fill-assessment-session.command-BMJ54EPO.mjs → acorex-modules-assessment-management-fill-assessment-session.command-CJieLR5g.mjs} +32 -7
  10. package/fesm2022/acorex-modules-assessment-management-fill-assessment-session.command-CJieLR5g.mjs.map +1 -0
  11. package/fesm2022/{acorex-modules-assessment-management-index-XdJCIYG3.mjs → acorex-modules-assessment-management-index-D8KjfHAH.mjs} +4 -4
  12. package/fesm2022/{acorex-modules-assessment-management-index-XdJCIYG3.mjs.map → acorex-modules-assessment-management-index-D8KjfHAH.mjs.map} +1 -1
  13. package/fesm2022/{acorex-modules-assessment-management-preview-question.command-CO8NfjEb.mjs → acorex-modules-assessment-management-preview-question.command-D0-FB1HH.mjs} +2 -2
  14. package/fesm2022/{acorex-modules-assessment-management-preview-question.command-CO8NfjEb.mjs.map → acorex-modules-assessment-management-preview-question.command-D0-FB1HH.mjs.map} +1 -1
  15. package/fesm2022/{acorex-modules-assessment-management-preview-questionnaire.command-DSzbtU0e.mjs → acorex-modules-assessment-management-preview-questionnaire.command-wqPNgv7q.mjs} +2 -2
  16. package/fesm2022/{acorex-modules-assessment-management-preview-questionnaire.command-DSzbtU0e.mjs.map → acorex-modules-assessment-management-preview-questionnaire.command-wqPNgv7q.mjs.map} +1 -1
  17. package/fesm2022/{acorex-modules-assessment-management-question-bank-interface-editor-widget-edit.component-DbvxAUgb.mjs → acorex-modules-assessment-management-question-bank-interface-editor-widget-edit.component-DYyUhSWd.mjs} +2 -2
  18. package/fesm2022/{acorex-modules-assessment-management-question-bank-interface-editor-widget-edit.component-DbvxAUgb.mjs.map → acorex-modules-assessment-management-question-bank-interface-editor-widget-edit.component-DYyUhSWd.mjs.map} +1 -1
  19. package/fesm2022/{acorex-modules-assessment-management-question-bank-item.entity-DBfQhSKR.mjs → acorex-modules-assessment-management-question-bank-item.entity-DUf2ceKY.mjs} +2 -2
  20. package/fesm2022/{acorex-modules-assessment-management-question-bank-item.entity-DBfQhSKR.mjs.map → acorex-modules-assessment-management-question-bank-item.entity-DUf2ceKY.mjs.map} +1 -1
  21. package/fesm2022/{acorex-modules-assessment-management-questionnaire-calculation.entity-CL9s20qR.mjs → acorex-modules-assessment-management-questionnaire-calculation.entity-CYF0k42_.mjs} +2 -2
  22. package/fesm2022/{acorex-modules-assessment-management-questionnaire-calculation.entity-CL9s20qR.mjs.map → acorex-modules-assessment-management-questionnaire-calculation.entity-CYF0k42_.mjs.map} +1 -1
  23. package/fesm2022/{acorex-modules-assessment-management-questionnaire-viewer-popup.component-CH_cJlSf.mjs → acorex-modules-assessment-management-questionnaire-viewer-popup.component-Cy5ElBmU.mjs} +111 -28
  24. package/fesm2022/acorex-modules-assessment-management-questionnaire-viewer-popup.component-Cy5ElBmU.mjs.map +1 -0
  25. package/fesm2022/{acorex-modules-assessment-management-questionnaire.entity-CrryBMC2.mjs → acorex-modules-assessment-management-questionnaire.entity-RWSkzNbA.mjs} +3 -3
  26. package/fesm2022/{acorex-modules-assessment-management-questionnaire.entity-CrryBMC2.mjs.map → acorex-modules-assessment-management-questionnaire.entity-RWSkzNbA.mjs.map} +1 -1
  27. package/fesm2022/{acorex-modules-assessment-management-save-questionnaire-questions.command-Dq5VComh.mjs → acorex-modules-assessment-management-save-questionnaire-questions.command-koGmUbNE.mjs} +2 -2
  28. package/fesm2022/{acorex-modules-assessment-management-save-questionnaire-questions.command-Dq5VComh.mjs.map → acorex-modules-assessment-management-save-questionnaire-questions.command-koGmUbNE.mjs.map} +1 -1
  29. package/fesm2022/acorex-modules-assessment-management-view-case-last-session-answers.command-NTuDdoYk.mjs +157 -0
  30. package/fesm2022/acorex-modules-assessment-management-view-case-last-session-answers.command-NTuDdoYk.mjs.map +1 -0
  31. package/fesm2022/acorex-modules-assessment-management-view-session-answers.command-0btGV66_.mjs +172 -0
  32. package/fesm2022/acorex-modules-assessment-management-view-session-answers.command-0btGV66_.mjs.map +1 -0
  33. package/fesm2022/acorex-modules-assessment-management.mjs +1 -1
  34. package/fesm2022/{acorex-modules-auth-acorex-modules-auth-wfCSNwXC.mjs → acorex-modules-auth-acorex-modules-auth-D4IBi_VD.mjs} +39 -30
  35. package/fesm2022/acorex-modules-auth-acorex-modules-auth-D4IBi_VD.mjs.map +1 -0
  36. package/fesm2022/{acorex-modules-auth-app-chooser.component-BY281-Cl.mjs → acorex-modules-auth-app-chooser.component-BEktaBWD.mjs} +2 -2
  37. package/fesm2022/{acorex-modules-auth-app-chooser.component-BY281-Cl.mjs.map → acorex-modules-auth-app-chooser.component-BEktaBWD.mjs.map} +1 -1
  38. package/fesm2022/{acorex-modules-auth-login.module-CjgYlyOv.mjs → acorex-modules-auth-login.module-aAwHzXPj.mjs} +4 -4
  39. package/fesm2022/{acorex-modules-auth-login.module-CjgYlyOv.mjs.map → acorex-modules-auth-login.module-aAwHzXPj.mjs.map} +1 -1
  40. package/fesm2022/{acorex-modules-auth-master.layout-Clx8QDYW.mjs → acorex-modules-auth-master.layout-BapDYFZ_.mjs} +2 -2
  41. package/fesm2022/{acorex-modules-auth-master.layout-Clx8QDYW.mjs.map → acorex-modules-auth-master.layout-BapDYFZ_.mjs.map} +1 -1
  42. package/fesm2022/{acorex-modules-auth-oauth-callback.component-CGnGAPJ2.mjs → acorex-modules-auth-oauth-callback.component-Cyu2vqyK.mjs} +2 -2
  43. package/fesm2022/{acorex-modules-auth-oauth-callback.component-CGnGAPJ2.mjs.map → acorex-modules-auth-oauth-callback.component-Cyu2vqyK.mjs.map} +1 -1
  44. package/fesm2022/{acorex-modules-auth-password.component-8eEX0lRP.mjs → acorex-modules-auth-password.component-DB-ac0Rn.mjs} +2 -2
  45. package/fesm2022/{acorex-modules-auth-password.component-8eEX0lRP.mjs.map → acorex-modules-auth-password.component-DB-ac0Rn.mjs.map} +1 -1
  46. package/fesm2022/{acorex-modules-auth-password.component-CUxwThnN.mjs → acorex-modules-auth-password.component-cPmwNpuq.mjs} +2 -2
  47. package/fesm2022/{acorex-modules-auth-password.component-CUxwThnN.mjs.map → acorex-modules-auth-password.component-cPmwNpuq.mjs.map} +1 -1
  48. package/fesm2022/{acorex-modules-auth-routes-CYLKJm9g.mjs → acorex-modules-auth-routes-r72zIRTa.mjs} +2 -2
  49. package/fesm2022/{acorex-modules-auth-routes-CYLKJm9g.mjs.map → acorex-modules-auth-routes-r72zIRTa.mjs.map} +1 -1
  50. package/fesm2022/{acorex-modules-auth-tenant-chooser.component-DDK1KW-8.mjs → acorex-modules-auth-tenant-chooser.component-AQA2o6Ty.mjs} +2 -2
  51. package/fesm2022/{acorex-modules-auth-tenant-chooser.component-DDK1KW-8.mjs.map → acorex-modules-auth-tenant-chooser.component-AQA2o6Ty.mjs.map} +1 -1
  52. package/fesm2022/{acorex-modules-auth-two-factor.module-Iw2U7Cy5.mjs → acorex-modules-auth-two-factor.module-Dx0CC5ic.mjs} +2 -2
  53. package/fesm2022/{acorex-modules-auth-two-factor.module-Iw2U7Cy5.mjs.map → acorex-modules-auth-two-factor.module-Dx0CC5ic.mjs.map} +1 -1
  54. package/fesm2022/{acorex-modules-auth-user-sessions.component-sKDANprs.mjs → acorex-modules-auth-user-sessions.component-3Wr7DUDQ.mjs} +2 -2
  55. package/fesm2022/{acorex-modules-auth-user-sessions.component-sKDANprs.mjs.map → acorex-modules-auth-user-sessions.component-3Wr7DUDQ.mjs.map} +1 -1
  56. package/fesm2022/acorex-modules-auth.mjs +1 -1
  57. package/fesm2022/acorex-modules-common.mjs +7 -3
  58. package/fesm2022/acorex-modules-common.mjs.map +1 -1
  59. package/fesm2022/{acorex-modules-conversation-acorex-modules-conversation-DlteA_jC.mjs → acorex-modules-conversation-acorex-modules-conversation-DkdNLMKa.mjs} +8 -7
  60. package/fesm2022/acorex-modules-conversation-acorex-modules-conversation-DkdNLMKa.mjs.map +1 -0
  61. package/fesm2022/{acorex-modules-conversation-assist-delegated-agent-detail-popup.component-BAgBuxlz.mjs → acorex-modules-conversation-assist-delegated-agent-detail-popup.component-VKPbkRqI.mjs} +2 -2
  62. package/fesm2022/{acorex-modules-conversation-assist-delegated-agent-detail-popup.component-BAgBuxlz.mjs.map → acorex-modules-conversation-assist-delegated-agent-detail-popup.component-VKPbkRqI.mjs.map} +1 -1
  63. package/fesm2022/{acorex-modules-conversation-comments-page.component-BrwP9l7M.mjs → acorex-modules-conversation-comments-page.component-ehUCjoFD.mjs} +2 -2
  64. package/fesm2022/{acorex-modules-conversation-comments-page.component-BrwP9l7M.mjs.map → acorex-modules-conversation-comments-page.component-ehUCjoFD.mjs.map} +1 -1
  65. package/fesm2022/{acorex-modules-conversation-send-assist-chat-message.command-BzKawEoN.mjs → acorex-modules-conversation-send-assist-chat-message.command-ZNcVi54N.mjs} +2 -2
  66. package/fesm2022/{acorex-modules-conversation-send-assist-chat-message.command-BzKawEoN.mjs.map → acorex-modules-conversation-send-assist-chat-message.command-ZNcVi54N.mjs.map} +1 -1
  67. package/fesm2022/{acorex-modules-conversation-start-assist-chat.command-BUOGUMl0.mjs → acorex-modules-conversation-start-assist-chat.command-CX6lm1lG.mjs} +2 -2
  68. package/fesm2022/{acorex-modules-conversation-start-assist-chat.command-BUOGUMl0.mjs.map → acorex-modules-conversation-start-assist-chat.command-CX6lm1lG.mjs.map} +1 -1
  69. package/fesm2022/acorex-modules-conversation.mjs +1 -1
  70. package/fesm2022/acorex-modules-customer-management.mjs +2 -0
  71. package/fesm2022/acorex-modules-customer-management.mjs.map +1 -1
  72. package/fesm2022/acorex-modules-data-management.mjs +6 -5
  73. package/fesm2022/acorex-modules-data-management.mjs.map +1 -1
  74. package/fesm2022/{acorex-modules-help-desk-acorex-modules-help-desk-Bfjo-ENr.mjs → acorex-modules-help-desk-acorex-modules-help-desk-DVlO9JZw.mjs} +3 -2
  75. package/fesm2022/acorex-modules-help-desk-acorex-modules-help-desk-DVlO9JZw.mjs.map +1 -0
  76. package/fesm2022/{acorex-modules-help-desk-capture-screen.component-CsACFkPq.mjs → acorex-modules-help-desk-capture-screen.component-rNPehEf8.mjs} +2 -2
  77. package/fesm2022/{acorex-modules-help-desk-capture-screen.component-CsACFkPq.mjs.map → acorex-modules-help-desk-capture-screen.component-rNPehEf8.mjs.map} +1 -1
  78. package/fesm2022/acorex-modules-help-desk.mjs +1 -1
  79. package/fesm2022/{acorex-modules-human-capital-management-acorex-modules-human-capital-management-XhV2JQXs.mjs → acorex-modules-human-capital-management-acorex-modules-human-capital-management-BWezAea1.mjs} +131 -112
  80. package/fesm2022/acorex-modules-human-capital-management-acorex-modules-human-capital-management-BWezAea1.mjs.map +1 -0
  81. package/fesm2022/{acorex-modules-human-capital-management-approve-leave-request.command-Cre30Kp7.mjs → acorex-modules-human-capital-management-approve-leave-request.command-Bh_Bbq5-.mjs} +2 -2
  82. package/fesm2022/{acorex-modules-human-capital-management-approve-leave-request.command-Cre30Kp7.mjs.map → acorex-modules-human-capital-management-approve-leave-request.command-Bh_Bbq5-.mjs.map} +1 -1
  83. package/fesm2022/{acorex-modules-human-capital-management-assign-position-assignment.command-NYgddiaD.mjs → acorex-modules-human-capital-management-assign-position-assignment.command-BpDdDG9i.mjs} +2 -2
  84. package/fesm2022/{acorex-modules-human-capital-management-assign-position-assignment.command-NYgddiaD.mjs.map → acorex-modules-human-capital-management-assign-position-assignment.command-BpDdDG9i.mjs.map} +1 -1
  85. package/fesm2022/{acorex-modules-human-capital-management-cancel-leave-request.command-DPh-KQgN.mjs → acorex-modules-human-capital-management-cancel-leave-request.command-CjtKaKFw.mjs} +2 -2
  86. package/fesm2022/{acorex-modules-human-capital-management-cancel-leave-request.command-DPh-KQgN.mjs.map → acorex-modules-human-capital-management-cancel-leave-request.command-CjtKaKFw.mjs.map} +1 -1
  87. package/fesm2022/{acorex-modules-human-capital-management-employee.entity-znCbbQUd.mjs → acorex-modules-human-capital-management-employee.entity-Cx_oY2aK.mjs} +8 -8
  88. package/fesm2022/acorex-modules-human-capital-management-employee.entity-Cx_oY2aK.mjs.map +1 -0
  89. package/fesm2022/{acorex-modules-human-capital-management-employment-type.entity-DUNB3zAB.mjs → acorex-modules-human-capital-management-employment-type.entity-B20Taa5x.mjs} +2 -2
  90. package/fesm2022/{acorex-modules-human-capital-management-employment-type.entity-DUNB3zAB.mjs.map → acorex-modules-human-capital-management-employment-type.entity-B20Taa5x.mjs.map} +1 -1
  91. package/fesm2022/{acorex-modules-human-capital-management-leave-request.entity-JyFrrCGE.mjs → acorex-modules-human-capital-management-leave-request.entity-BO8QXpZE.mjs} +2 -2
  92. package/fesm2022/{acorex-modules-human-capital-management-leave-request.entity-JyFrrCGE.mjs.map → acorex-modules-human-capital-management-leave-request.entity-BO8QXpZE.mjs.map} +1 -1
  93. package/fesm2022/{acorex-modules-human-capital-management-leave-type.entity-B61MiEPu.mjs → acorex-modules-human-capital-management-leave-type.entity-CQwSWqSh.mjs} +2 -2
  94. package/fesm2022/{acorex-modules-human-capital-management-leave-type.entity-B61MiEPu.mjs.map → acorex-modules-human-capital-management-leave-type.entity-CQwSWqSh.mjs.map} +1 -1
  95. package/fesm2022/{acorex-modules-human-capital-management-lifecycle-process-type.entity-DJqo2kTG.mjs → acorex-modules-human-capital-management-lifecycle-event-type.entity-BPWJrvbN.mjs} +13 -13
  96. package/fesm2022/acorex-modules-human-capital-management-lifecycle-event-type.entity-BPWJrvbN.mjs.map +1 -0
  97. package/fesm2022/{acorex-modules-human-capital-management-employee-lifecycle-process.entity-LX68KORg.mjs → acorex-modules-human-capital-management-lifecycle-event.entity-ZZuPu9KQ.mjs} +45 -56
  98. package/fesm2022/acorex-modules-human-capital-management-lifecycle-event.entity-ZZuPu9KQ.mjs.map +1 -0
  99. package/fesm2022/{acorex-modules-human-capital-management-position-assignment.entity-CKCC6bKg.mjs → acorex-modules-human-capital-management-position-assignment.entity-BN1y0qhi.mjs} +2 -2
  100. package/fesm2022/{acorex-modules-human-capital-management-position-assignment.entity-CKCC6bKg.mjs.map → acorex-modules-human-capital-management-position-assignment.entity-BN1y0qhi.mjs.map} +1 -1
  101. package/fesm2022/{acorex-modules-human-capital-management-reject-leave-request.command-Blv08UQZ.mjs → acorex-modules-human-capital-management-reject-leave-request.command-LczqOHP-.mjs} +2 -2
  102. package/fesm2022/{acorex-modules-human-capital-management-reject-leave-request.command-Blv08UQZ.mjs.map → acorex-modules-human-capital-management-reject-leave-request.command-LczqOHP-.mjs.map} +1 -1
  103. package/fesm2022/{acorex-modules-human-capital-management-revoke-position-assignment.command-lgEAbxYH.mjs → acorex-modules-human-capital-management-revoke-position-assignment.command-Dm8YacDI.mjs} +2 -2
  104. package/fesm2022/{acorex-modules-human-capital-management-revoke-position-assignment.command-lgEAbxYH.mjs.map → acorex-modules-human-capital-management-revoke-position-assignment.command-Dm8YacDI.mjs.map} +1 -1
  105. package/fesm2022/acorex-modules-human-capital-management-start-lifecycle-event-flow.command-DPwuyFz2.mjs +237 -0
  106. package/fesm2022/acorex-modules-human-capital-management-start-lifecycle-event-flow.command-DPwuyFz2.mjs.map +1 -0
  107. package/fesm2022/acorex-modules-human-capital-management.mjs +1 -1
  108. package/fesm2022/{acorex-modules-learning-management-enrollment.entity-B53AQq_9.mjs → acorex-modules-learning-management-enrollment.entity-CdJafrUh.mjs} +4 -22
  109. package/fesm2022/acorex-modules-learning-management-enrollment.entity-CdJafrUh.mjs.map +1 -0
  110. package/fesm2022/acorex-modules-learning-management.mjs +1 -1
  111. package/fesm2022/acorex-modules-learning-management.mjs.map +1 -1
  112. package/fesm2022/acorex-modules-location-management.mjs +1 -0
  113. package/fesm2022/acorex-modules-location-management.mjs.map +1 -1
  114. package/fesm2022/{acorex-modules-platform-management-acorex-modules-platform-management-5DJoQkx2.mjs → acorex-modules-platform-management-acorex-modules-platform-management-Cbf1rlEK.mjs} +4 -4
  115. package/fesm2022/{acorex-modules-platform-management-acorex-modules-platform-management-5DJoQkx2.mjs.map → acorex-modules-platform-management-acorex-modules-platform-management-Cbf1rlEK.mjs.map} +1 -1
  116. package/fesm2022/{acorex-modules-platform-management-menu-list.component-C3WBYbOt.mjs → acorex-modules-platform-management-menu-list.component-DIf_-oaM.mjs} +2 -2
  117. package/fesm2022/{acorex-modules-platform-management-menu-list.component-C3WBYbOt.mjs.map → acorex-modules-platform-management-menu-list.component-DIf_-oaM.mjs.map} +1 -1
  118. package/fesm2022/acorex-modules-platform-management.mjs +1 -1
  119. package/fesm2022/acorex-modules-security-management.mjs +3 -0
  120. package/fesm2022/acorex-modules-security-management.mjs.map +1 -1
  121. package/fesm2022/acorex-modules-supplier-management.mjs +1 -0
  122. package/fesm2022/acorex-modules-supplier-management.mjs.map +1 -1
  123. package/fesm2022/{acorex-modules-task-management-acorex-modules-task-management-CrybKNgo.mjs → acorex-modules-task-management-acorex-modules-task-management--mdNdYIs.mjs} +32 -2
  124. package/fesm2022/acorex-modules-task-management-acorex-modules-task-management--mdNdYIs.mjs.map +1 -0
  125. package/fesm2022/{acorex-modules-task-management-task-board.page-B2xxXscG.mjs → acorex-modules-task-management-task-board.page-BIZ1qH7m.mjs} +33 -3
  126. package/fesm2022/acorex-modules-task-management-task-board.page-BIZ1qH7m.mjs.map +1 -0
  127. package/fesm2022/acorex-modules-task-management.mjs +1 -1
  128. package/fesm2022/{acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-OLbCD-7P.mjs → acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-B4DLmioy.mjs} +3 -3
  129. package/fesm2022/{acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-OLbCD-7P.mjs.map → acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-B4DLmioy.mjs.map} +1 -1
  130. package/fesm2022/{acorex-modules-workflow-management-index-RRzkvrNM.mjs → acorex-modules-workflow-management-index-BhVZ1Bcw.mjs} +3 -3
  131. package/fesm2022/{acorex-modules-workflow-management-index-RRzkvrNM.mjs.map → acorex-modules-workflow-management-index-BhVZ1Bcw.mjs.map} +1 -1
  132. package/fesm2022/{acorex-modules-workflow-management-index-Eh5DDK-V.mjs → acorex-modules-workflow-management-index-DC_9M9dk.mjs} +3 -3
  133. package/fesm2022/{acorex-modules-workflow-management-index-Eh5DDK-V.mjs.map → acorex-modules-workflow-management-index-DC_9M9dk.mjs.map} +1 -1
  134. package/fesm2022/{acorex-modules-workflow-management-workflow-instance.entity-B_V3uMSI.mjs → acorex-modules-workflow-management-workflow-instance.entity-BnKT3Wgh.mjs} +2 -2
  135. package/fesm2022/{acorex-modules-workflow-management-workflow-instance.entity-B_V3uMSI.mjs.map → acorex-modules-workflow-management-workflow-instance.entity-BnKT3Wgh.mjs.map} +1 -1
  136. package/fesm2022/acorex-modules-workflow-management-workflow-task-popover.component-DjYDwHWU.mjs +255 -0
  137. package/fesm2022/acorex-modules-workflow-management-workflow-task-popover.component-DjYDwHWU.mjs.map +1 -0
  138. package/fesm2022/acorex-modules-workflow-management.mjs +1819 -745
  139. package/fesm2022/acorex-modules-workflow-management.mjs.map +1 -1
  140. package/package.json +2 -2
  141. package/types/acorex-modules-assessment-management.d.ts +4 -7
  142. package/types/acorex-modules-common.d.ts +1 -0
  143. package/types/acorex-modules-human-capital-management.d.ts +31 -30
  144. package/types/acorex-modules-learning-management.d.ts +0 -1
  145. package/types/acorex-modules-task-management.d.ts +41 -2
  146. package/types/acorex-modules-workflow-management.d.ts +280 -34
  147. package/fesm2022/acorex-modules-assessment-management-acorex-modules-assessment-management-DcPnI9fZ.mjs.map +0 -1
  148. package/fesm2022/acorex-modules-assessment-management-assessment-case.entity-D880d_qz.mjs.map +0 -1
  149. package/fesm2022/acorex-modules-assessment-management-assessment-session.entity-DvbocIN1.mjs.map +0 -1
  150. package/fesm2022/acorex-modules-assessment-management-fill-assessment-session.command-BMJ54EPO.mjs.map +0 -1
  151. package/fesm2022/acorex-modules-assessment-management-questionnaire-viewer-popup.component-CH_cJlSf.mjs.map +0 -1
  152. package/fesm2022/acorex-modules-assessment-management-view-session-answers.command-DpppXekm.mjs +0 -112
  153. package/fesm2022/acorex-modules-assessment-management-view-session-answers.command-DpppXekm.mjs.map +0 -1
  154. package/fesm2022/acorex-modules-auth-acorex-modules-auth-wfCSNwXC.mjs.map +0 -1
  155. package/fesm2022/acorex-modules-conversation-acorex-modules-conversation-DlteA_jC.mjs.map +0 -1
  156. package/fesm2022/acorex-modules-help-desk-acorex-modules-help-desk-Bfjo-ENr.mjs.map +0 -1
  157. package/fesm2022/acorex-modules-human-capital-management-acorex-modules-human-capital-management-XhV2JQXs.mjs.map +0 -1
  158. package/fesm2022/acorex-modules-human-capital-management-employee-lifecycle-process.entity-LX68KORg.mjs.map +0 -1
  159. package/fesm2022/acorex-modules-human-capital-management-employee.entity-znCbbQUd.mjs.map +0 -1
  160. package/fesm2022/acorex-modules-human-capital-management-lifecycle-process-type.entity-DJqo2kTG.mjs.map +0 -1
  161. package/fesm2022/acorex-modules-learning-management-enrollment.entity-B53AQq_9.mjs.map +0 -1
  162. package/fesm2022/acorex-modules-task-management-acorex-modules-task-management-CrybKNgo.mjs.map +0 -1
  163. package/fesm2022/acorex-modules-task-management-task-board.page-B2xxXscG.mjs.map +0 -1
  164. package/fesm2022/acorex-modules-workflow-management-workflow-task-popover.component-DMszilef.mjs +0 -356
  165. package/fesm2022/acorex-modules-workflow-management-workflow-task-popover.component-DMszilef.mjs.map +0 -1
@@ -1,26 +1,27 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, inject, NgModule, InjectionToken, Inject, makeEnvironmentProviders, Injector, runInInjectionContext } from '@angular/core';
2
+ import { Injectable, inject, NgModule, Injector, runInInjectionContext, makeEnvironmentProviders, InjectionToken, Inject } from '@angular/core';
3
3
  import { AXPCommonMenuKeys, AXPWidgetsList } from '@acorex/modules/common';
4
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';
5
+ import { AXPEntityService, AXPEntityFormBuilderService, AXPEntityDefinitionRegistryService, entityDetailsCrudActions, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_DEFINITION_LOADER, AXP_RECORD_WORKFLOW_INFO_INSTANCE_ID_FIELD } from '@acorex/platform/layout/entity';
6
6
  import { firstValueFrom } from 'rxjs';
7
7
  import { AXMCalendarManagementModule } from '@acorex/modules/calendar-management';
8
- import { AXPEntityCommandScope, AXPStatusProvider, AXPSystemStatusType, systemStatusToDefinition, AXPSystemStatuses, AXP_STATUS_PROVIDERS, AXP_MENU_PROVIDER } from '@acorex/platform/common';
9
- import { AXPSystemActionType, AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, AXP_MODULE_MANIFEST_PROVIDER, provideLazyProvider } from '@acorex/platform/core';
8
+ import { AXPEntityCommandScope, AXPStatusProvider, AXPSystemStatusType, systemStatusToDefinition, AXP_STATUS_PROVIDERS, AXP_MENU_PROVIDER, AXPSettingsService, AXPStatusDefinitionProviderService, AXPRegionalSetting, AXPSystemStatuses } from '@acorex/platform/common';
9
+ import { AXPSystemActionType, AXPBroadcastEventService, AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, AXP_MODULE_MANIFEST_PROVIDER, provideLazyProvider } from '@acorex/platform/core';
10
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 } from '@acorex/platform/layout/widget-core';
12
+ import { AXPWidgetGroupEnum, AXP_WIDGETS_EDITOR_CATEGORY, AXPWidgetSerializationHelper, AXPWidgetCoreModule, AXP_WIDGET_DEFINITION_PROVIDER, AXPWidgetsCatalog } 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, AXP_WORKFLOW_ERROR_CODES, AXPWorkflowDefinitionService, AXP_WORKFLOW_PROVIDER, AXP_ACTIVITY_CATEGORY_PROVIDER, AXP_ACTIVITY_PROVIDER, AXP_WORKFLOW_CATEGORY_PROVIDER } from '@acorex/platform/workflow';
16
+ import { AXPWorkflowDefinitionService, AXP_WORKFLOW_ENGINE, AXPWorkflowManager, AXP_WORKFLOW_SUPPRESS_CONTINUATION_INPUT_KEY, AXP_WORKFLOW_ERROR_CODES, axpIsWorkflowTaskBoardActivityType, AXP_WORKFLOW_PROVIDER, AXP_ACTIVITY_CATEGORY_PROVIDER, AXP_ACTIVITY_PROVIDER, AXP_WORKFLOW_CATEGORY_PROVIDER, AXP_WORKFLOW_CONTINUATION_HOOK } from '@acorex/platform/workflow';
17
17
  import { AXDialogService } from '@acorex/components/dialog';
18
18
  import { AXTranslationService } from '@acorex/core/translation';
19
19
  import { AXPopupService } from '@acorex/components/popup';
20
20
  import { AXPDialogRendererComponent, AXPLayoutBuilderService } from '@acorex/platform/layout/builder';
21
21
  import { cloneDeep } from 'lodash-es';
22
22
  import { AXToastService } from '@acorex/components/toast';
23
- import { AXPWorkflowTaskProvider, matchesTaskBoardAssigneeUserIdsFilter, filterTasksOverlappingRange, AXP_WORKFLOW_TASK_PROVIDER } from '@acorex/modules/task-management';
23
+ import { AXP_WORKFLOW_TASK_PROVIDER, AXPWorkflowTaskProvider, matchesTaskBoardAssigneeUserIdsFilter, filterTasksOverlappingRange } from '@acorex/modules/task-management';
24
+ import { AXFormatService } from '@acorex/core/format';
24
25
 
25
26
  const config = {
26
27
  i18n: 'workflow-management',
@@ -167,7 +168,7 @@ class AXMWorkflowManagementModuleEntityProvider {
167
168
  case RootConfig.entities.workflowDefinition.name:
168
169
  return (await import('./acorex-modules-workflow-management-workflow-definition.entity-DISpkWE4.mjs')).factory();
169
170
  case RootConfig.entities.workflowInstance.name:
170
- return (await import('./acorex-modules-workflow-management-workflow-instance.entity-B_V3uMSI.mjs')).factory();
171
+ return (await import('./acorex-modules-workflow-management-workflow-instance.entity-BnKT3Wgh.mjs')).factory();
171
172
  case RootConfig.entities.activityDefinition.name:
172
173
  return (await import('./acorex-modules-workflow-management-activity-definition.entity-B3DkgDQb.mjs')).factory();
173
174
  case RootConfig.entities.automation.name:
@@ -996,10 +997,10 @@ const AXMActivityCommandConfiguratorWidget = {
996
997
  ],
997
998
  components: {
998
999
  edit: {
999
- component: () => import('./acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-OLbCD-7P.mjs').then((c) => c.AXMActivityCommandConfiguratorWidgetEditComponent),
1000
+ component: () => import('./acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-B4DLmioy.mjs').then((c) => c.AXMActivityCommandConfiguratorWidgetEditComponent),
1000
1001
  },
1001
1002
  designer: {
1002
- component: () => import('./acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-OLbCD-7P.mjs').then((c) => c.AXMActivityCommandConfiguratorWidgetEditComponent),
1003
+ component: () => import('./acorex-modules-workflow-management-activity-command-configurator-widget-edit.component-B4DLmioy.mjs').then((c) => c.AXMActivityCommandConfiguratorWidgetEditComponent),
1003
1004
  },
1004
1005
  column: {
1005
1006
  component: () => import('./acorex-modules-workflow-management-activity-command-configurator-widget-column.component-CDo0QVFy.mjs').then((c) => c.AXMActivityCommandConfiguratorWidgetColumnComponent),
@@ -2137,6 +2138,8 @@ const automationPlugin = {
2137
2138
  * This plugin:
2138
2139
  * - Adds workflow capability marker to entity extensions
2139
2140
  * - Enables workflow trigger middleware to detect workflow-capable entities
2141
+ * - Domain rows link runs via `workflowInfo` on the entity model (see `AXPRecordWorkflowInfo`),
2142
+ * not as entity definition properties
2140
2143
  * - Provides UI hooks for workflow-related features (future enhancement)
2141
2144
  *
2142
2145
  * Usage:
@@ -2550,6 +2553,68 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
2550
2553
  type: Injectable
2551
2554
  }] });
2552
2555
 
2556
+ //#region ---- Lazy loader ----
2557
+ /** Code-split chunk for the generic workflow task provider implementation. */
2558
+ function loadGenericWorkflowTaskProviderClass() {
2559
+ return Promise.resolve().then(function () { return genericWorkflowTask_provider; }).then((m) => m.AXPGenericWorkflowTaskProvider);
2560
+ }
2561
+ //#endregion
2562
+ //#region ---- Per-definition registration ----
2563
+ /**
2564
+ * Registers one workflow task provider for a single definition (lazy-loaded).
2565
+ * Use in feature modules that need a dedicated task-board entry per workflow.
2566
+ */
2567
+ function provideGenericWorkflowTaskProvider(config) {
2568
+ return {
2569
+ provide: AXP_WORKFLOW_TASK_PROVIDER,
2570
+ multi: true,
2571
+ useFactory: (injector) => loadGenericWorkflowTaskProviderClass().then((ProviderClass) => runInInjectionContext(injector, () => new ProviderClass(config))),
2572
+ deps: [Injector],
2573
+ };
2574
+ }
2575
+ //#endregion
2576
+ //#region ---- Auto-discovery registration ----
2577
+ /**
2578
+ * Registers one task provider per workflow definition (lazy-loaded).
2579
+ * Discovers definitions via {@link AXPWorkflowDefinitionService} at first resolve.
2580
+ */
2581
+ function provideTaskWorkflow() {
2582
+ return makeEnvironmentProviders([
2583
+ {
2584
+ provide: AXP_WORKFLOW_TASK_PROVIDER,
2585
+ multi: true,
2586
+ useFactory: (injector) => (async () => {
2587
+ const ProviderClass = await loadGenericWorkflowTaskProviderClass();
2588
+ const workflowDefinitionService = injector.get(AXPWorkflowDefinitionService);
2589
+ const multiLanguageResolver = injector.get(AXTranslationService);
2590
+ const categories = await workflowDefinitionService.getCategories();
2591
+ const providers = [];
2592
+ const seenDefinitionNames = new Set();
2593
+ for (const category of categories) {
2594
+ const workflows = await workflowDefinitionService.getWorkflowsByCategoryId(category.id);
2595
+ for (const workflow of workflows) {
2596
+ const key = workflow.name;
2597
+ if (!key || seenDefinitionNames.has(key)) {
2598
+ continue;
2599
+ }
2600
+ seenDefinitionNames.add(key);
2601
+ const provider = runInInjectionContext(injector, () => new ProviderClass({
2602
+ name: workflow.name,
2603
+ title: multiLanguageResolver.resolve(workflow.title) ?? workflow.name,
2604
+ icon: 'fa-light fa-diagram-project',
2605
+ definitionId: workflow.name,
2606
+ }));
2607
+ providers.push(provider);
2608
+ }
2609
+ }
2610
+ return providers;
2611
+ })(),
2612
+ deps: [Injector],
2613
+ },
2614
+ ]);
2615
+ }
2616
+ //#endregion
2617
+
2553
2618
  //#region ---- Imports ----
2554
2619
  //#endregion
2555
2620
  //#region ---- Permission Helpers ----
@@ -2563,133 +2628,336 @@ function canReassignWorkflowTaskToSelf(sessionService) {
2563
2628
  }
2564
2629
  //#endregion
2565
2630
 
2566
- //#region ---- Workflow task context (reserved keys) ----
2631
+ //#region ---- Imports ----
2632
+ //#endregion
2633
+ //#region ---- User id helpers ----
2634
+ /** Normalizes platform user id lists on bookmark payloads. */
2635
+ function normalizeWorkflowTaskUserIds(value) {
2636
+ if (!value || value.length === 0) {
2637
+ return [];
2638
+ }
2639
+ return value.map((id) => String(id)).filter((s) => s.length > 0);
2640
+ }
2641
+ /** Workflow instance creator (task-board "started by"). */
2642
+ function getWorkflowInstanceInitiatorUserId(instance) {
2643
+ const id = instance.auditInfo?.created?.by?.id;
2644
+ return id != null && String(id).length > 0 ? String(id) : null;
2645
+ }
2646
+ /** Demo/platform operator accounts that bypass permission checks in mock auth. */
2647
+ function isWorkflowPlatformRootUser(sessionService) {
2648
+ const username = sessionService.user?.name?.trim();
2649
+ return username === 'root' || username === 'root2' || username === 'super-root';
2650
+ }
2651
+ //#endregion
2652
+ //#region ---- Bookmark payload helpers ----
2653
+ /** Bookmark types rendered on the workflow task board. */
2654
+ function isWorkflowTaskBoardBookmarkPayload(payload) {
2655
+ const t = payload.activityType;
2656
+ return t === 'workflow-activity:human-task' || t === 'workflow-activity:cartable';
2657
+ }
2658
+ /** Pooled task that must be claimed before acting (no direct continuation offer). */
2659
+ function isWorkflowPooledClaimablePayload(payload) {
2660
+ const assigned = normalizeWorkflowTaskUserIds(payload.assignedUserIds);
2661
+ const candidates = normalizeWorkflowTaskUserIds(payload.candidateUserIds);
2662
+ if (payload.activityType === 'workflow-activity:cartable') {
2663
+ return assigned.length === 0 && candidates.length > 0;
2664
+ }
2665
+ return payload.activityType === 'workflow-activity:human-task' && assigned.length === 0 && candidates.length > 0;
2666
+ }
2667
+ /** Human-task assigned to another user; may be taken over when permitted. */
2668
+ function isWorkflowReassignableHumanTaskPayload(payload) {
2669
+ if (payload.activityType !== 'workflow-activity:human-task') {
2670
+ return false;
2671
+ }
2672
+ const assigned = normalizeWorkflowTaskUserIds(payload.assignedUserIds);
2673
+ if (assigned.length === 0) {
2674
+ return false;
2675
+ }
2676
+ return true;
2677
+ }
2678
+ /** Parses bookmark payload from entity storage. */
2679
+ function parseWorkflowTaskContinuationPayload(bookmark) {
2680
+ try {
2681
+ const raw = bookmark.payload ?? (bookmark.payloadJson ? JSON.parse(bookmark.payloadJson) : null);
2682
+ if (typeof raw !== 'object' || raw === null) {
2683
+ return null;
2684
+ }
2685
+ return raw;
2686
+ }
2687
+ catch {
2688
+ return null;
2689
+ }
2690
+ }
2691
+ //#endregion
2692
+ //#region ---- Step advancement gate ----
2693
+ /** Resume outcomes that do not advance the workflow graph (draft save, cancel, loop back). */
2694
+ const NON_ADVANCING_RESUME_OUTCOMES = new Set(['saved', 'cancelled', 'cancel', 'save', 'draft']);
2567
2695
  /**
2568
- * Human-task / cartable `context` payload: technical ids at the root; display metadata under reserved keys.
2696
+ * Whether the workflow moved forward enough to prompt "continue to next step".
2697
+ * Skips draft save / cancel on questionnaire (same human-task bookmark remains).
2698
+ */
2699
+ function shouldOfferWorkflowContinuationAfterStep(context, activeBookmarkActivityIds) {
2700
+ const outcome = context.resumeOutcome?.trim().toLowerCase();
2701
+ if (outcome && NON_ADVANCING_RESUME_OUTCOMES.has(outcome)) {
2702
+ return false;
2703
+ }
2704
+ const pendingActivityId = context.pendingNextTask?.activityId;
2705
+ const completedActivityId = context.completedActivityId;
2706
+ if (pendingActivityId && completedActivityId && pendingActivityId === completedActivityId) {
2707
+ return false;
2708
+ }
2709
+ if (activeBookmarkActivityIds.length === 0) {
2710
+ return false;
2711
+ }
2712
+ if (!completedActivityId) {
2713
+ return true;
2714
+ }
2715
+ return activeBookmarkActivityIds.some((id) => id !== completedActivityId);
2716
+ }
2717
+ //#endregion
2718
+ //#region ---- Continuation eligibility ----
2719
+ /**
2720
+ * Whether the UI should offer "continue to next step" after a successful resume.
2569
2721
  *
2570
- * @example
2571
- * ```json
2572
- * {
2573
- * "leaveRequestId": "{{ variables.leaveRequestId }}",
2574
- * "_taskI18n": {
2575
- * "employeeDisplayName": "{{ variables.employeeDisplayName }}",
2576
- * "leaveTypeTitle": "{{ variables.leaveTypeTitle }}"
2577
- * },
2578
- * "_taskTitleParts": [
2579
- * "{{ variables.employeeDisplayName }}",
2580
- * "{{ variables.leaveTypeTitle }}"
2581
- * ]
2582
- * }
2583
- * ```
2722
+ * - Current user is the assignee (sequential tasks for the same person, e.g. line manager).
2723
+ * - Workflow initiator and assignee are the same person and that person is the current user.
2724
+ * - Current user may take over a human-task assigned to someone else.
2584
2725
  */
2585
- /** Interpolation map for `@scope:key` task title and description strings. */
2586
- const AXP_WORKFLOW_TASK_CONTEXT_I18N_KEY = '_taskI18n';
2587
- /** Ordered segments joined with " — " when bookmark title is still a generic activity label. */
2588
- const AXP_WORKFLOW_TASK_CONTEXT_TITLE_PARTS_KEY = '_taskTitleParts';
2726
+ function shouldOfferWorkflowTaskContinuation(ctx) {
2727
+ const currentUserId = ctx.sessionService.user?.id;
2728
+ if (currentUserId == null) {
2729
+ return false;
2730
+ }
2731
+ const current = String(currentUserId);
2732
+ if (!isWorkflowTaskBoardBookmarkPayload(ctx.payload)) {
2733
+ return false;
2734
+ }
2735
+ if (isWorkflowPooledClaimablePayload(ctx.payload)) {
2736
+ return false;
2737
+ }
2738
+ const assigned = normalizeWorkflowTaskUserIds(ctx.payload.assignedUserIds);
2739
+ const assigneeId = assigned[0] ?? null;
2740
+ const initiatorId = getWorkflowInstanceInitiatorUserId(ctx.instance);
2741
+ const isPlatformRoot = isWorkflowPlatformRootUser(ctx.sessionService);
2742
+ const isInitiator = initiatorId != null && current === initiatorId;
2743
+ if (assigneeId && current === assigneeId) {
2744
+ return true;
2745
+ }
2746
+ if (initiatorId && assigneeId && initiatorId === assigneeId && current === initiatorId) {
2747
+ return true;
2748
+ }
2749
+ /** User who started the workflow may continue (take over when not assignee). */
2750
+ if (isInitiator && assigneeId) {
2751
+ return true;
2752
+ }
2753
+ /** Platform operators (e.g. super-root) may continue any pending human task. */
2754
+ if (isPlatformRoot) {
2755
+ return true;
2756
+ }
2757
+ if (!canReassignWorkflowTaskToSelf(ctx.sessionService) && !isPlatformRoot) {
2758
+ return false;
2759
+ }
2760
+ if (!isWorkflowReassignableHumanTaskPayload(ctx.payload)) {
2761
+ return false;
2762
+ }
2763
+ if (!assigneeId || current === assigneeId) {
2764
+ return false;
2765
+ }
2766
+ return true;
2767
+ }
2768
+ /** True when the user must take over the next bookmark before acting on it. */
2769
+ function needsTakeOverForWorkflowTaskContinuation(ctx) {
2770
+ const currentUserId = ctx.sessionService.user?.id;
2771
+ if (currentUserId == null) {
2772
+ return false;
2773
+ }
2774
+ const current = String(currentUserId);
2775
+ const assigned = normalizeWorkflowTaskUserIds(ctx.payload.assignedUserIds);
2776
+ const assigneeId = assigned[0] ?? null;
2777
+ if (!assigneeId || current === assigneeId) {
2778
+ return false;
2779
+ }
2780
+ const canTakeOver = canReassignWorkflowTaskToSelf(ctx.sessionService) || isWorkflowPlatformRootUser(ctx.sessionService);
2781
+ return canTakeOver && isWorkflowReassignableHumanTaskPayload(ctx.payload);
2782
+ }
2589
2783
  //#endregion
2590
2784
 
2785
+ //#region ---- Imports ----
2786
+ //#endregion
2787
+ //#region ---- Access factory ----
2788
+ function getActiveBookmarks(instance) {
2789
+ const wi = instance.workflowInstance;
2790
+ const bookmarks = wi?.bookmarks ?? [];
2791
+ return bookmarks.filter((b) => !b.isConsumed && !b.consumed);
2792
+ }
2591
2793
  /**
2592
- * Injection token for provider config. Use when registering via DI (provide token + useFactory with deps).
2593
- * When creating via useFactory: () => new AXPGenericWorkflowTaskProvider({ ... }), config is passed in the closure.
2794
+ * Loads workflow instance entity rows (including embedded bookmarks).
2594
2795
  */
2595
- const AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG = new InjectionToken('AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG');
2796
+ function createWorkflowInstanceBookmarkAccess(entityService = inject(AXPEntityService)) {
2797
+ const workflowInstanceData = entityService
2798
+ .withEntity('WorkflowManagement', 'WorkflowInstance')
2799
+ .data();
2800
+ return {
2801
+ async loadInstance(instanceId) {
2802
+ let instance = await workflowInstanceData.byKey(instanceId);
2803
+ if (instance && getActiveBookmarks(instance).length > 0) {
2804
+ return instance;
2805
+ }
2806
+ await new Promise((resolve) => setTimeout(resolve, 50));
2807
+ instance = await workflowInstanceData.byKey(instanceId);
2808
+ return instance ?? null;
2809
+ },
2810
+ getActiveBookmarks,
2811
+ async findActiveBookmark(instanceId, activityId) {
2812
+ const instance = await this.loadInstance(instanceId);
2813
+ if (!instance) {
2814
+ return null;
2815
+ }
2816
+ const bookmark = getActiveBookmarks(instance).find((b) => b.activityId === activityId);
2817
+ if (!bookmark) {
2818
+ return null;
2819
+ }
2820
+ return { instance, bookmark };
2821
+ },
2822
+ parseHumanTaskPayload(bookmark) {
2823
+ const parsed = parseWorkflowTaskContinuationPayload(bookmark);
2824
+ if (!parsed) {
2825
+ return null;
2826
+ }
2827
+ return parsed;
2828
+ },
2829
+ };
2830
+ }
2831
+ //#endregion
2832
+
2596
2833
  //#endregion
2834
+ //#region ---- Service ----
2597
2835
  /**
2598
- * Generic Workflow Task Provider
2599
- *
2600
- * Provides tasks from Workflow Instances directly (no Work Items).
2601
- * Queries suspended workflow instances and extracts tasks from bookmarks.
2602
- *
2603
- * Create one provider per workflow definition by passing a config (name, title, definitionId).
2604
- * E.g. leave request: { name: 'leave-request-workflow-tasks', title: 'Leave Request', definitionId: 'LeaveRequestWorkflow' }
2605
- *
2606
- * Architecture:
2607
- * - Queries Workflow Instances with subStatus = 'Suspended'
2608
- * - Filters by config.definitionId when set (one provider = one definition)
2609
- * - Extracts active bookmarks for each instance
2610
- * - Parses bookmark payload for assignment/actions
2611
- * - Maps to task board format
2836
+ * Workflow-instance human-task operations (resume, take-over, primary action).
2837
+ * Independent of task board / popover — task board delegates here for the same behavior.
2612
2838
  */
2613
- class AXPGenericWorkflowTaskProvider extends AXPWorkflowTaskProvider {
2614
- //#endregion
2615
- //#region ---- Constructor ----
2616
- constructor(config) {
2617
- super();
2618
- //#endregion
2839
+ class AXPWorkflowInstanceHumanTaskService {
2840
+ constructor() {
2619
2841
  //#region ---- Services & Dependencies ----
2620
- this.entityService = inject(AXPEntityService);
2621
- this.workflowInstanceData = this.entityService
2622
- .withEntity('WorkflowManagement', 'WorkflowInstance')
2623
- .data();
2624
- this.userEntityData = this.entityService.withEntity('SecurityManagement', 'User').data();
2625
- this.translationService = inject(AXTranslationService);
2626
- this.workflowManager = inject(AXPWorkflowManager);
2842
+ this.injector = inject(Injector);
2627
2843
  this.sessionService = inject(AXPSessionService);
2628
- this.toastService = inject(AXToastService);
2844
+ this.translationService = inject(AXTranslationService);
2629
2845
  this.dialogService = inject(AXDialogService);
2630
- this.config = config;
2631
- }
2632
- //#endregion
2633
- //#region ---- Provider Metadata ----
2634
- get name() {
2635
- return this.config.name;
2636
- }
2637
- get title() {
2638
- return this.config.title;
2846
+ this.toastService = inject(AXToastService);
2847
+ this.eventService = inject(AXPBroadcastEventService);
2848
+ this.workflowEngine = inject(AXP_WORKFLOW_ENGINE);
2849
+ this.bookmarkAccess = createWorkflowInstanceBookmarkAccess();
2639
2850
  }
2640
- get icon() {
2641
- return this.config.icon ?? 'fa-light fa-diagram-project';
2851
+ /** Resolved lazily to avoid DI cycle with {@link AXPWorkflowManager} continuation hook. */
2852
+ get workflowManager() {
2853
+ return this.injector.get(AXPWorkflowManager);
2642
2854
  }
2643
2855
  //#endregion
2644
- //#region ---- Task Retrieval ----
2856
+ //#region ---- Resume & take-over ----
2645
2857
  /**
2646
- * Bookmark types shown on the workflow task board.
2858
+ * Resumes a suspended human-task bookmark (runs interactive activities via the workflow manager).
2647
2859
  */
2648
- isTaskBoardBookmarkPayload(payload) {
2649
- const t = payload.activityType;
2650
- return t === 'workflow-activity:human-task' || t === 'workflow-activity:cartable';
2860
+ async resumeSuspendedHumanTask(request) {
2861
+ const userInput = {
2862
+ ...(request.userInput ?? {}),
2863
+ bookmarkId: request.bookmarkId,
2864
+ };
2865
+ if (request.suppressContinuation) {
2866
+ userInput[AXP_WORKFLOW_SUPPRESS_CONTINUATION_INPUT_KEY] = true;
2867
+ }
2868
+ let result = await this.workflowManager.resume(request.instanceId, request.activityId, request.outcome, userInput, request.taskToken);
2869
+ if (result.success || result.errorCode !== AXP_WORKFLOW_ERROR_CODES.TASK_NOT_ASSIGNEE || !this.canTakeOver()) {
2870
+ if (!result.success) {
2871
+ await this.showResumeError(result);
2872
+ }
2873
+ return result;
2874
+ }
2875
+ const confirmed = await this.confirmReassignToSelf();
2876
+ if (!confirmed) {
2877
+ return { success: false, instanceId: request.instanceId, error: result.error, errorCode: result.errorCode };
2878
+ }
2879
+ const reassigned = await this.reassignBookmarkToCurrentUser(request.instanceId, request.bookmarkId, request.activityId);
2880
+ if (!reassigned) {
2881
+ return { success: false, instanceId: request.instanceId, error: result.error, errorCode: result.errorCode };
2882
+ }
2883
+ result = await this.workflowManager.resume(request.instanceId, request.activityId, request.outcome, userInput, request.taskToken);
2884
+ if (!result.success) {
2885
+ await this.showResumeError(result);
2886
+ }
2887
+ return result;
2651
2888
  }
2652
2889
  /**
2653
- * Pooled task: must be claimed before submit/cancel (cartable, or human-task with candidates only).
2890
+ * Runs the first configured action on a suspended human-task bookmark (e.g. start-fill → questionnaire).
2654
2891
  */
2655
- isPooledClaimablePayload(payload) {
2656
- const assigned = this.normalizeUserIdList(payload.assignedUserIds);
2657
- const candidates = this.normalizeUserIdList(payload.candidateUserIds);
2658
- if (payload.activityType === 'workflow-activity:cartable') {
2659
- return assigned.length === 0 && candidates.length > 0;
2892
+ async executePrimaryHumanTaskAction(instanceId, activityId, options) {
2893
+ const found = await this.bookmarkAccess.findActiveBookmark(instanceId, activityId);
2894
+ if (!found) {
2895
+ return null;
2660
2896
  }
2661
- return payload.activityType === 'workflow-activity:human-task' && assigned.length === 0 && candidates.length > 0;
2662
- }
2663
- normalizeUserIdList(value) {
2664
- if (!value || value.length === 0)
2665
- return [];
2666
- return value.map((id) => String(id)).filter((s) => s.length > 0);
2897
+ const payload = this.bookmarkAccess.parseHumanTaskPayload(found.bookmark);
2898
+ if (!payload?.taskToken) {
2899
+ return null;
2900
+ }
2901
+ const outcome = this.resolvePrimaryTaskOutcome(payload);
2902
+ const result = await this.resumeSuspendedHumanTask({
2903
+ instanceId,
2904
+ bookmarkId: found.bookmark.id,
2905
+ activityId,
2906
+ taskToken: payload.taskToken,
2907
+ outcome,
2908
+ suppressContinuation: options?.suppressContinuation ?? true,
2909
+ });
2910
+ if (options?.notifyViews !== false) {
2911
+ this.notifyWorkflowTaskViewsChanged();
2912
+ }
2913
+ return result;
2667
2914
  }
2668
2915
  /**
2669
- * Human-task assigned to another user; current user may take over when permitted.
2916
+ * Reassigns a human-task bookmark to the current user (take over) without advancing the workflow.
2670
2917
  */
2671
- isReassignableHumanTaskPayload(payload) {
2672
- if (payload.activityType !== 'workflow-activity:human-task') {
2918
+ async reassignBookmarkToCurrentUser(instanceId, bookmarkId, activityId) {
2919
+ const reassign = this.workflowEngine.reassignTaskToSelf?.bind(this.workflowEngine);
2920
+ if (!reassign) {
2673
2921
  return false;
2674
2922
  }
2675
- const assigned = this.normalizeUserIdList(payload.assignedUserIds);
2676
- if (assigned.length === 0) {
2923
+ const result = await reassign({ instanceId, bookmarkId, stepId: activityId });
2924
+ if (!result.success) {
2925
+ await this.showToast('@workflow-management:tasks.errors.reassign-failed');
2677
2926
  return false;
2678
2927
  }
2679
- const currentUserId = this.sessionService.user?.id;
2680
- if (currentUserId == null) {
2928
+ return true;
2929
+ }
2930
+ /**
2931
+ * Take over with confirmation dialog (task board "Take Over" action).
2932
+ */
2933
+ async reassignBookmarkToCurrentUserWithConfirm(instanceId, bookmarkId, activityId) {
2934
+ if (!this.canTakeOver()) {
2935
+ await this.showToast('@workflow-management:tasks.errors.not-assignee');
2681
2936
  return false;
2682
2937
  }
2683
- return !assigned.includes(String(currentUserId));
2938
+ const confirmed = await this.confirmReassignToSelf();
2939
+ if (!confirmed) {
2940
+ return true;
2941
+ }
2942
+ return this.reassignBookmarkToCurrentUser(instanceId, bookmarkId, activityId);
2684
2943
  }
2685
- canTakeOverTask() {
2686
- return canReassignWorkflowTaskToSelf(this.sessionService);
2944
+ //#endregion
2945
+ //#region ---- Outcome resolution ----
2946
+ /** First action command name on the human-task bookmark (e.g. start-fill, approve). */
2947
+ resolvePrimaryTaskOutcome(payload) {
2948
+ const actions = [...(payload.actions?.prefix ?? []), ...(payload.actions?.suffix ?? [])];
2949
+ for (const action of actions) {
2950
+ const outcome = action.command?.name ?? action.name;
2951
+ if (outcome && outcome !== 'unknown') {
2952
+ return outcome;
2953
+ }
2954
+ }
2955
+ return 'submit';
2687
2956
  }
2688
- //#region ---- Task Command UX ----
2689
- async showWorkflowTaskToast(contentKey, color = 'danger') {
2690
- const title = await this.translationService.translateAsync('@general:messages.generic.error.title');
2691
- const content = await this.translationService.translateAsync(contentKey);
2692
- this.toastService.show({ color, title, content });
2957
+ //#endregion
2958
+ //#region ---- UI helpers ----
2959
+ canTakeOver() {
2960
+ return canReassignWorkflowTaskToSelf(this.sessionService);
2693
2961
  }
2694
2962
  async confirmReassignToSelf() {
2695
2963
  const title = await this.translationService.translateAsync('@workflow-management:tasks.dialogs.reassign-to-self.title');
@@ -2697,626 +2965,199 @@ class AXPGenericWorkflowTaskProvider extends AXPWorkflowTaskProvider {
2697
2965
  const dialogResult = await this.dialogService.confirm(title, message, 'warning', 'horizontal', false, 'cancel');
2698
2966
  return dialogResult.result === true;
2699
2967
  }
2700
- async reassignTaskToSelf(instanceId, bookmarkId, activityId) {
2701
- const result = await this.workflowManager.reassignTaskToSelf(instanceId, bookmarkId, activityId);
2702
- if (result.success) {
2703
- return true;
2704
- }
2705
- await this.showWorkflowTaskToast('@workflow-management:tasks.errors.reassign-failed');
2706
- return false;
2707
- }
2708
- async resumeWorkflowTask(instanceId, bookmarkId, activityId, outcome, userInput, taskToken) {
2709
- let result = await this.workflowManager.resume(instanceId, activityId, outcome, userInput, taskToken);
2710
- if (result.success || result.errorCode !== AXP_WORKFLOW_ERROR_CODES.TASK_NOT_ASSIGNEE || !this.canTakeOverTask()) {
2711
- if (!result.success) {
2712
- const toastKey = result.errorCode === AXP_WORKFLOW_ERROR_CODES.TASK_NOT_ASSIGNEE
2713
- ? '@workflow-management:tasks.errors.not-assignee'
2714
- : undefined;
2715
- if (toastKey) {
2716
- await this.showWorkflowTaskToast(toastKey);
2717
- }
2718
- else if (result.error) {
2719
- this.toastService.show({
2720
- color: 'danger',
2721
- title: await this.translationService.translateAsync('@general:messages.generic.error.title'),
2722
- content: result.error,
2723
- });
2724
- }
2725
- }
2726
- return result;
2727
- }
2728
- const confirmed = await this.confirmReassignToSelf();
2729
- if (!confirmed) {
2730
- return { success: false, instanceId, error: result.error, errorCode: result.errorCode };
2731
- }
2732
- const reassigned = await this.reassignTaskToSelf(instanceId, bookmarkId, activityId);
2733
- if (!reassigned) {
2734
- return { success: false, instanceId, error: result.error, errorCode: result.errorCode };
2968
+ async showResumeError(result) {
2969
+ const toastKey = result.errorCode === AXP_WORKFLOW_ERROR_CODES.TASK_NOT_ASSIGNEE
2970
+ ? '@workflow-management:tasks.errors.not-assignee'
2971
+ : undefined;
2972
+ if (toastKey) {
2973
+ await this.showToast(toastKey);
2974
+ return;
2735
2975
  }
2736
- result = await this.workflowManager.resume(instanceId, activityId, outcome, userInput, taskToken);
2737
- if (!result.success) {
2976
+ if (result.error) {
2738
2977
  this.toastService.show({
2739
2978
  color: 'danger',
2740
2979
  title: await this.translationService.translateAsync('@general:messages.generic.error.title'),
2741
- content: result.error ?? 'Failed to resume workflow',
2980
+ content: result.error,
2742
2981
  });
2743
2982
  }
2744
- return result;
2983
+ }
2984
+ async showToast(contentKey, color = 'danger') {
2985
+ const title = await this.translationService.translateAsync('@general:messages.generic.error.title');
2986
+ const content = await this.translationService.translateAsync(contentKey);
2987
+ this.toastService.show({ color, title, content });
2988
+ }
2989
+ /** Optional broadcast so open task-board views refresh; does not require task-board module at runtime. */
2990
+ notifyWorkflowTaskViewsChanged(provider) {
2991
+ this.eventService.publish('task-board.refresh', { provider });
2992
+ }
2993
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowInstanceHumanTaskService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2994
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowInstanceHumanTaskService, providedIn: 'root' }); }
2995
+ }
2996
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowInstanceHumanTaskService, decorators: [{
2997
+ type: Injectable,
2998
+ args: [{ providedIn: 'root' }]
2999
+ }] });
3000
+
3001
+ //#region ---- Imports ----
3002
+ //#endregion
3003
+ //#region ---- Service ----
3004
+ /**
3005
+ * Offers "continue to next step" / take-over after workflow start, resume, and interactive chains.
3006
+ * Uses {@link AXPWorkflowInstanceHumanTaskService} only — not task board or popover.
3007
+ */
3008
+ class AXPWorkflowTaskContinuationService {
3009
+ constructor() {
3010
+ //#region ---- Services & Dependencies ----
3011
+ this.sessionService = inject(AXPSessionService);
3012
+ this.translationService = inject(AXTranslationService);
3013
+ this.dialogService = inject(AXDialogService);
3014
+ this.humanTaskService = inject(AXPWorkflowInstanceHumanTaskService);
3015
+ this.bookmarkAccess = createWorkflowInstanceBookmarkAccess();
2745
3016
  }
2746
3017
  //#endregion
2747
- /**
2748
- * Get tasks from suspended workflow instances.
2749
- *
2750
- * Queries workflow instances filtered by:
2751
- * - subStatus = 'Suspended'
2752
- * - entityRefType (if provided in filter)
2753
- * - definitionId (if provided in filter)
2754
- * - assignee/claimant (if filter provided)
2755
- *
2756
- * Then extracts active bookmarks and maps to task board format.
2757
- */
2758
- async getTasks(options) {
2759
- // Build filter for workflow instances
2760
- const baseFilter = { logic: 'and', filters: [] };
2761
- // Filter by subStatus = 'Suspended' (only suspended workflows have pending tasks)
2762
- baseFilter.filters?.push({
2763
- field: 'subStatus',
2764
- operator: { type: 'equal' },
2765
- value: 'Suspended',
2766
- });
2767
- // Scope this provider to one workflow definition
2768
- if (this.config.definitionId) {
2769
- baseFilter.filters?.push({
2770
- field: 'definitionId',
2771
- operator: { type: 'equal' },
2772
- value: this.config.definitionId,
2773
- });
2774
- }
2775
- // Date range is applied after mapping bookmarks (task start/end overlap), not on instance createdAt.
2776
- // Query workflow instances
2777
- const { items: instances } = await this.workflowInstanceData.query({
2778
- skip: options?.skip ?? 0,
2779
- take: options?.take ?? 20,
2780
- filter: baseFilter,
2781
- });
2782
- // Extract tasks from bookmarks for each instance
2783
- const tasks = [];
2784
- for (const instance of instances) {
2785
- try {
2786
- // Get active bookmarks from instance entity (workflowInstance.bookmarks)
2787
- const bookmarks = this.getActiveBookmarksFromInstance(instance);
2788
- // Process each bookmark (typically one per suspended activity)
2789
- for (const bookmark of bookmarks) {
2790
- try {
2791
- // Get payload from entity (payload object or parse payloadJson)
2792
- let payload;
2793
- try {
2794
- const raw = bookmark.payload ?? (bookmark.payloadJson ? JSON.parse(bookmark.payloadJson) : null);
2795
- payload =
2796
- typeof raw === 'object' && raw !== null
2797
- ? raw
2798
- : {};
2799
- }
2800
- catch {
2801
- continue;
2802
- }
2803
- // Task board: human-task and cartable (pooled); exclude other suspended UI bookmarks
2804
- if (!this.isTaskBoardBookmarkPayload(payload)) {
2805
- continue;
2806
- }
2807
- // Check assignment filter if provided
2808
- if (options?.assigneeIds && options.assigneeIds.length > 0) {
2809
- const assignedIds = payload.assignedUserIds || [];
2810
- const candidateIds = payload.candidateUserIds || [];
2811
- const allUserIds = [...assignedIds, ...candidateIds].map(String);
2812
- // TODO: Also check candidateRoleIds by resolving role members
2813
- if (!matchesTaskBoardAssigneeUserIdsFilter(allUserIds, options.assigneeIds)) {
2814
- continue;
2815
- }
2816
- }
2817
- // Map bookmark to task
2818
- const task = await this.mapBookmarkToTask(instance, bookmark, payload);
2819
- tasks.push(task);
2820
- }
2821
- catch {
2822
- // Skip this bookmark and continue
2823
- }
2824
- }
3018
+ //#region ---- Hook ----
3019
+ async offerAfterWorkflowStep(context) {
3020
+ try {
3021
+ const instance = await this.bookmarkAccess.loadInstance(context.instanceId);
3022
+ if (!instance) {
3023
+ return;
2825
3024
  }
2826
- catch {
2827
- // Skip this instance and continue
3025
+ const activeActivityIds = this.bookmarkAccess
3026
+ .getActiveBookmarks(instance)
3027
+ .map((b) => b.activityId);
3028
+ if (!shouldOfferWorkflowContinuationAfterStep(context, activeActivityIds)) {
3029
+ return;
2828
3030
  }
2829
- }
2830
- const rangeFiltered = filterTasksOverlappingRange(tasks, options?.range);
2831
- const total = rangeFiltered.length;
2832
- const skip = options?.skip ?? 0;
2833
- const take = options?.take ?? total;
2834
- const items = rangeFiltered.slice(skip, skip + take);
2835
- return { items, total };
2836
- }
2837
- /**
2838
- * Get active (non-consumed) bookmarks from workflow instance entity.
2839
- * Reads from instance.workflowInstance?.bookmarks — no direct DB access.
2840
- */
2841
- getActiveBookmarksFromInstance(instance) {
2842
- const wi = instance?.workflowInstance;
2843
- const bookmarks = wi?.bookmarks ?? [];
2844
- const active = bookmarks.filter((b) => !b.isConsumed && !b.consumed);
2845
- return active;
2846
- }
2847
- /**
2848
- * Task-board reporter: signed-in user who is viewing the app (workflow initiator context).
2849
- */
2850
- buildReporterFromSession(instance) {
2851
- const sessionUser = this.sessionService.user;
2852
- if (sessionUser?.id) {
2853
- const label = sessionUser.title?.trim() || sessionUser.name?.trim() || sessionUser.id;
2854
- return { id: sessionUser.id, type: 'user', fullName: label };
2855
- }
2856
- const audit = instance.auditInfo?.created?.by;
2857
- return {
2858
- id: audit?.id ?? '',
2859
- type: 'user',
2860
- fullName: audit?.fullName ?? '',
2861
- };
2862
- }
2863
- /**
2864
- * Builds interpolation params from `context._taskI18n` (workflow-defined; provider stays domain-agnostic).
2865
- */
2866
- buildTaskTranslationParams(context) {
2867
- const params = {};
2868
- const i18n = context?.[AXP_WORKFLOW_TASK_CONTEXT_I18N_KEY];
2869
- if (!i18n || typeof i18n !== 'object' || Array.isArray(i18n)) {
2870
- return params;
2871
- }
2872
- for (const [key, value] of Object.entries(i18n)) {
2873
- const text = this.toTaskTranslationParam(value);
2874
- if (text.length > 0) {
2875
- params[key] = text;
3031
+ if (context.pendingNextTask &&
3032
+ axpIsWorkflowTaskBoardActivityType(context.pendingNextTask.activityType)) {
3033
+ const offered = await this.offerFromPendingNextTask(instance, context, context.pendingNextTask);
3034
+ if (offered) {
3035
+ return;
3036
+ }
2876
3037
  }
3038
+ await this.offerFromInstanceBookmarks(instance, context);
2877
3039
  }
2878
- return params;
2879
- }
2880
- /**
2881
- * Normalizes bookmark context values for i18n interpolation (strings or multi-language maps).
2882
- */
2883
- toTaskTranslationParam(value) {
2884
- if (value == null) {
2885
- return '';
2886
- }
2887
- if (typeof value === 'string') {
2888
- return value.trim();
2889
- }
2890
- if (typeof value === 'number' || typeof value === 'boolean') {
2891
- return String(value);
2892
- }
2893
- if (typeof value === 'object') {
2894
- const resolved = this.translationService.resolve(value);
2895
- return resolved?.trim() ?? '';
3040
+ catch (error) {
3041
+ console.warn('[AXPWorkflowTaskContinuationService] offerAfterWorkflowStep failed', error);
2896
3042
  }
2897
- return String(value).trim();
2898
3043
  }
2899
- /**
2900
- * Resolves task copy: literal strings pass through; keys starting with `@` are translated with context params.
2901
- */
2902
- async resolveTaskDisplayText(value, params) {
2903
- const raw = value?.trim();
2904
- if (!raw) {
2905
- return '';
2906
- }
2907
- if (!raw.startsWith('@')) {
2908
- return raw;
3044
+ //#endregion
3045
+ //#region ---- Offer paths ----
3046
+ async offerFromPendingNextTask(instance, context, nextTask) {
3047
+ const payload = this.buildPayloadFromWorkflowTask(nextTask);
3048
+ const bookmark = this.bookmarkAccess
3049
+ .getActiveBookmarks(instance)
3050
+ .find((b) => b.activityId === nextTask.activityId);
3051
+ const continuationCtx = {
3052
+ instance,
3053
+ bookmark: bookmark ?? { id: '', activityId: nextTask.activityId, type: 'user-task' },
3054
+ payload,
3055
+ sessionService: this.sessionService,
3056
+ completedBookmarkId: context.completedBookmarkId,
3057
+ completedActivityId: context.completedActivityId,
3058
+ };
3059
+ if (!shouldOfferWorkflowTaskContinuation(continuationCtx)) {
3060
+ return false;
2909
3061
  }
2910
- return this.translationService.translateAsync(raw, { params });
3062
+ return this.confirmAndAdvance(instance.id, context, continuationCtx, nextTask.activityId, bookmark?.id);
2911
3063
  }
2912
- /**
2913
- * Builds a display title from `context._taskTitleParts` when bookmark title is still generic.
2914
- */
2915
- composeTaskTitleFromContext(context) {
2916
- const parts = context?.[AXP_WORKFLOW_TASK_CONTEXT_TITLE_PARTS_KEY];
2917
- if (!Array.isArray(parts)) {
2918
- return '';
3064
+ async offerFromInstanceBookmarks(instance, context) {
3065
+ for (const bookmark of this.bookmarkAccess.getActiveBookmarks(instance)) {
3066
+ if (this.isCompletedBookmark(bookmark, context)) {
3067
+ continue;
3068
+ }
3069
+ const payload = parseWorkflowTaskContinuationPayload(bookmark);
3070
+ if (!payload) {
3071
+ continue;
3072
+ }
3073
+ const continuationCtx = {
3074
+ instance,
3075
+ bookmark,
3076
+ payload,
3077
+ sessionService: this.sessionService,
3078
+ completedBookmarkId: context.completedBookmarkId,
3079
+ completedActivityId: context.completedActivityId,
3080
+ };
3081
+ if (!shouldOfferWorkflowTaskContinuation(continuationCtx)) {
3082
+ continue;
3083
+ }
3084
+ await this.confirmAndAdvance(instance.id, context, continuationCtx, bookmark.activityId, bookmark.id);
3085
+ return;
2919
3086
  }
2920
- return parts
2921
- .map((part) => this.toTaskTranslationParam(part))
2922
- .filter((segment) => segment.length > 0)
2923
- .join(' — ');
2924
- }
2925
- /**
2926
- * True when bookmark title is the generic activity label, not workflow-specific copy.
2927
- */
2928
- isGenericHumanTaskTitle(title) {
2929
- const normalized = title?.trim().toLowerCase();
2930
- return (!normalized ||
2931
- normalized === 'human task' ||
2932
- normalized === 'cartable task' ||
2933
- normalized === 'workflow-activity:human-task' ||
2934
- normalized === 'workflow-activity:cartable' ||
2935
- normalized === 'workflow task');
2936
3087
  }
2937
- /**
2938
- * Resolve platform user id to a display label for the task board grid.
2939
- */
2940
- async resolveAssigneeReference(userId) {
2941
- const id = userId?.trim();
2942
- if (!id) {
2943
- return undefined;
3088
+ async confirmAndAdvance(instanceId, context, continuationCtx, nextActivityId, nextBookmarkId) {
3089
+ const takeOver = needsTakeOverForWorkflowTaskContinuation(continuationCtx);
3090
+ const confirmed = await this.confirmContinueToNextStep(takeOver);
3091
+ if (!confirmed) {
3092
+ return true;
2944
3093
  }
2945
- try {
2946
- const row = await this.userEntityData.byKey(id);
2947
- if (!row || typeof row !== 'object') {
2948
- return { id, type: 'user', fullName: id };
3094
+ if (takeOver) {
3095
+ let bookmarkIdToUse = nextBookmarkId;
3096
+ if (!bookmarkIdToUse) {
3097
+ const found = await this.bookmarkAccess.findActiveBookmark(instanceId, nextActivityId);
3098
+ bookmarkIdToUse = found?.bookmark.id;
2949
3099
  }
2950
- const displayName = 'displayName' in row ? String(row.displayName ?? '').trim() : '';
2951
- const username = 'username' in row ? String(row.username ?? '').trim() : '';
2952
- const fullName = displayName || username || id;
2953
- const ref = { id, type: 'user', fullName };
2954
- if (username) {
2955
- ref.username = username;
3100
+ if (!bookmarkIdToUse) {
3101
+ return true;
3102
+ }
3103
+ const reassigned = await this.humanTaskService.reassignBookmarkToCurrentUser(instanceId, bookmarkIdToUse, nextActivityId);
3104
+ if (!reassigned) {
3105
+ return true;
2956
3106
  }
2957
- return ref;
2958
- }
2959
- catch {
2960
- return { id, type: 'user', fullName: id };
2961
3107
  }
3108
+ await this.humanTaskService.executePrimaryHumanTaskAction(instanceId, nextActivityId, {
3109
+ suppressContinuation: true,
3110
+ notifyViews: true,
3111
+ });
3112
+ return true;
2962
3113
  }
2963
- /**
2964
- * Map bookmark to task board task format.
2965
- */
2966
- async mapBookmarkToTask(instance, bookmark, payload) {
2967
- // Extract dates
2968
- const dueDate = payload.dueDate
2969
- ? typeof payload.dueDate === 'string'
2970
- ? new Date(payload.dueDate)
2971
- : payload.dueDate
2972
- : instance.createdAt
2973
- ? new Date(instance.createdAt)
2974
- : new Date();
2975
- const startDate = instance.createdAt ? new Date(instance.createdAt) : dueDate;
2976
- // If startDate and endDate are the same, set endDate to one day after startDate
2977
- let endDate = dueDate;
2978
- if (startDate.getTime() === dueDate.getTime()) {
2979
- endDate = new Date(startDate);
2980
- endDate.setDate(endDate.getDate() + 1);
3114
+ //#endregion
3115
+ //#region ---- Helpers ----
3116
+ isCompletedBookmark(bookmark, context) {
3117
+ if (context.completedBookmarkId && bookmark.id === context.completedBookmarkId) {
3118
+ return true;
2981
3119
  }
2982
- // Map priority
2983
- const priority = this.mapPriorityToTaskPriority(payload.priority || 'Normal');
2984
- const taskTranslationParams = this.buildTaskTranslationParams(payload.context);
2985
- let titleSource = payload.title || payload.activityName || 'Workflow Task';
2986
- if (this.isGenericHumanTaskTitle(titleSource)) {
2987
- const composed = this.composeTaskTitleFromContext(payload.context);
2988
- if (composed) {
2989
- titleSource = composed;
2990
- }
3120
+ if (context.completedActivityId && bookmark.activityId === context.completedActivityId) {
3121
+ return true;
2991
3122
  }
2992
- const title = await this.resolveTaskDisplayText(titleSource, taskTranslationParams);
2993
- const description = await this.resolveTaskDisplayText(payload.description || `Action required: ${payload.activityName}`, taskTranslationParams);
2994
- const assigneeId = payload.assignedUserIds?.[0];
2995
- const assignee = await this.resolveAssigneeReference(assigneeId);
3123
+ return false;
3124
+ }
3125
+ buildPayloadFromWorkflowTask(task) {
3126
+ const input = task.input ?? {};
3127
+ const assigned = input['assignedUserIds'];
3128
+ const assignedUserIds = Array.isArray(assigned)
3129
+ ? assigned.map(String)
3130
+ : assigned != null && String(assigned).length > 0
3131
+ ? [String(assigned)]
3132
+ : null;
2996
3133
  return {
2997
- id: bookmark.id, // Use bookmark ID as task ID
2998
- title,
2999
- description,
3000
- startDate,
3001
- endDate,
3002
- allDay: false,
3003
- assignee,
3004
- index: 2,
3005
- status: {
3006
- id: AXPSystemStatuses.Pending.name,
3007
- title: this.translationService.translateSync('@workflow-management:tasks.states.pending'),
3008
- },
3009
- priority,
3010
- reporter: this.buildReporterFromSession(instance),
3011
- data: {
3012
- // Store workflow instance and bookmark metadata
3013
- instanceId: instance.id,
3014
- bookmarkId: bookmark.id,
3015
- activityId: bookmark.activityId,
3016
- activityType: payload.activityType,
3017
- activityName: payload.activityName,
3018
- taskToken: payload.taskToken,
3019
- entityRefId: instance.entityRefId,
3020
- entityRefType: instance.entityRefType,
3021
- definitionId: instance.definitionId,
3022
- // Store full payload for actions
3023
- payload: payload,
3024
- },
3134
+ activityType: task.activityType,
3135
+ activityName: task.activityName ?? task.activityType,
3136
+ taskToken: task.taskToken,
3137
+ assignedUserIds,
3138
+ candidateUserIds: input['candidateUserIds'],
3139
+ title: input['title'],
3140
+ description: input['description'],
3141
+ actions: input['actions'],
3142
+ context: input['context'],
3025
3143
  };
3026
3144
  }
3027
- /**
3028
- * Map priority to task board priority.
3029
- */
3030
- mapPriorityToTaskPriority(priority) {
3031
- switch (priority) {
3032
- case 'Urgent':
3033
- return 'highest';
3034
- case 'High':
3035
- return 'high';
3036
- case 'Normal':
3037
- return 'medium';
3038
- case 'Low':
3039
- return 'low';
3040
- default:
3041
- return 'medium';
3042
- }
3043
- }
3044
- //#endregion
3045
- //#region ---- Task Updates ----
3046
- /**
3047
- * Update tasks (not applicable for workflow instances - they are read-only from task provider perspective).
3048
- */
3049
- async updateTasks(tasksToUpdate) {
3050
- // Workflow instances are managed by workflow engine
3051
- // Task updates should be done through workflow resume, not direct updates
3052
- return tasksToUpdate;
3053
- }
3054
- //#endregion
3055
- //#region ---- Command Execution ----
3056
- /**
3057
- * Execute commands on tasks.
3058
- *
3059
- * Supports:
3060
- * - Workflow resume commands (Complete, Cancel)
3061
- */
3062
- async executeCommand(command) {
3063
- if (!command?.name)
3064
- return { success: true };
3065
- const taskData = command.options?.['data'];
3066
- const instanceId = taskData?.instanceId ?? command.options?.['instanceId'] ?? '';
3067
- const bookmarkId = taskData?.bookmarkId ?? command.options?.['bookmarkId'] ?? '';
3068
- const taskToken = taskData?.taskToken ?? command.options?.['taskToken'] ?? '';
3069
- const activityId = taskData?.activityId ?? command.options?.['activityId'] ?? command.options?.['stepId'] ?? '';
3070
- const outcome = command.options?.['outcome'] ?? 'Done';
3071
- const userInput = command.options?.['userInput'] ?? {};
3072
- if (command.name === 'WorkflowManagement.WorkflowInstance:ClaimTask') {
3073
- if (!instanceId || !bookmarkId || !activityId) {
3074
- return {
3075
- success: false,
3076
- message: {
3077
- text: 'Missing required parameters: instanceId, bookmarkId, activityId',
3078
- },
3079
- };
3080
- }
3081
- const claimResult = await this.workflowManager.claimTask(instanceId, bookmarkId, activityId);
3082
- if (!claimResult.success && claimResult.error) {
3083
- this.toastService.show({
3084
- color: 'danger',
3085
- title: await this.translationService.translateAsync('@general:messages.generic.error.title'),
3086
- content: claimResult.error,
3087
- });
3088
- }
3089
- return {
3090
- success: claimResult.success,
3091
- message: claimResult.error
3092
- ? {
3093
- text: claimResult.error,
3094
- }
3095
- : undefined,
3096
- };
3097
- }
3098
- if (command.name === 'WorkflowManagement.WorkflowInstance:ReassignToSelf') {
3099
- if (!instanceId || !bookmarkId || !activityId) {
3100
- return {
3101
- success: false,
3102
- message: {
3103
- text: 'Missing required parameters: instanceId, bookmarkId, activityId',
3104
- },
3105
- };
3106
- }
3107
- if (!this.canTakeOverTask()) {
3108
- await this.showWorkflowTaskToast('@workflow-management:tasks.errors.not-assignee');
3109
- return { success: false };
3110
- }
3111
- const confirmed = await this.confirmReassignToSelf();
3112
- if (!confirmed) {
3113
- return { success: true };
3114
- }
3115
- const reassigned = await this.reassignTaskToSelf(instanceId, bookmarkId, activityId);
3116
- return { success: reassigned };
3117
- }
3118
- // Handle workflow resume commands
3119
- if (command.name === 'WorkflowManagement.WorkflowInstance:Resume' || command.name === 'resume-workflow') {
3120
- if (!instanceId || !taskToken || !activityId) {
3121
- return {
3122
- success: false,
3123
- message: {
3124
- text: 'Missing required parameters: instanceId, taskToken, activityId',
3125
- },
3126
- };
3127
- }
3128
- const result = await this.resumeWorkflowTask(instanceId, bookmarkId, activityId, outcome, userInput, taskToken);
3129
- return {
3130
- success: result.success,
3131
- message: result.error
3132
- ? {
3133
- text: result.error,
3134
- }
3135
- : undefined,
3136
- };
3137
- }
3138
- return { success: true };
3139
- }
3140
- //#endregion
3141
- //#region ---- Actions & Statuses ----
3142
- /**
3143
- * Get available actions for a task.
3144
- *
3145
- * Extracts actions from bookmark payload.
3146
- */
3147
- async getActions(task) {
3148
- const actions = [];
3149
- if (!task)
3150
- return actions;
3151
- const taskData = task.data;
3152
- const payload = taskData?.payload;
3153
- if (!payload)
3154
- return actions;
3155
- if (this.isPooledClaimablePayload(payload)) {
3156
- actions.push({
3157
- name: 'claim',
3158
- title: this.translationService.translateSync('@workflow-management:tasks.actions.claim.title'),
3159
- icon: 'fa-light fa-hand',
3160
- color: 'primary',
3161
- priority: 'primary',
3162
- command: {
3163
- name: 'WorkflowManagement.WorkflowInstance:ClaimTask',
3164
- options: {
3165
- instanceId: taskData.instanceId,
3166
- bookmarkId: taskData.bookmarkId,
3167
- activityId: taskData.activityId,
3168
- },
3169
- },
3170
- });
3171
- return actions;
3172
- }
3173
- if (this.isReassignableHumanTaskPayload(payload) && this.canTakeOverTask()) {
3174
- actions.push({
3175
- name: 'reassign-to-self',
3176
- title: this.translationService.translateSync('@workflow-management:tasks.actions.reassign-to-self.title'),
3177
- icon: 'fa-light fa-user-check',
3178
- color: 'warning',
3179
- priority: 'secondary',
3180
- command: {
3181
- name: 'WorkflowManagement.WorkflowInstance:ReassignToSelf',
3182
- options: {
3183
- instanceId: taskData.instanceId,
3184
- bookmarkId: taskData.bookmarkId,
3185
- activityId: taskData.activityId,
3186
- },
3187
- },
3188
- });
3189
- }
3190
- // Extract actions from payload
3191
- if (payload.actions) {
3192
- const allActions = [...(payload.actions.prefix || []), ...(payload.actions.suffix || [])];
3193
- for (const action of allActions) {
3194
- const actionName = action.command?.name || action.name || 'unknown';
3195
- actions.push({
3196
- name: actionName,
3197
- title: action.title || actionName,
3198
- icon: action.icon,
3199
- color: action.color,
3200
- priority: 'primary',
3201
- command: {
3202
- name: 'WorkflowManagement.WorkflowInstance:Resume',
3203
- options: {
3204
- instanceId: taskData.instanceId,
3205
- bookmarkId: taskData.bookmarkId,
3206
- activityId: taskData.activityId,
3207
- taskToken: taskData.taskToken,
3208
- outcome: actionName,
3209
- userInput: {},
3210
- },
3211
- },
3212
- });
3213
- }
3214
- }
3215
- else {
3216
- // Default actions if none provided
3217
- actions.push({
3218
- name: 'submit',
3219
- title: this.translationService.translateSync('@general:actions.submit.title'),
3220
- icon: 'fa-light fa-check',
3221
- color: 'primary',
3222
- priority: 'primary',
3223
- command: {
3224
- name: 'WorkflowManagement.WorkflowInstance:Resume',
3225
- options: {
3226
- instanceId: taskData.instanceId,
3227
- bookmarkId: taskData.bookmarkId,
3228
- activityId: taskData.activityId,
3229
- taskToken: taskData.taskToken,
3230
- outcome: 'submit',
3231
- userInput: {},
3232
- },
3233
- },
3234
- });
3235
- actions.push({
3236
- name: 'cancel',
3237
- title: this.translationService.translateSync('@general:actions.cancel.title'),
3238
- icon: 'fa-light fa-times',
3239
- color: 'default',
3240
- priority: 'secondary',
3241
- command: {
3242
- name: 'WorkflowManagement.WorkflowInstance:Resume',
3243
- options: {
3244
- instanceId: taskData.instanceId,
3245
- bookmarkId: taskData.bookmarkId,
3246
- activityId: taskData.activityId,
3247
- taskToken: taskData.taskToken,
3248
- outcome: 'cancel',
3249
- userInput: {},
3250
- },
3251
- },
3252
- });
3253
- }
3254
- return actions;
3255
- }
3256
- async getExtraFields() {
3257
- return [];
3258
- }
3259
- async getStatuses() {
3260
- return [
3261
- {
3262
- index: 0,
3263
- key: AXPSystemStatuses.Pending.name,
3264
- title: await this.translationService.translateAsync('@workflow-management:tasks.states.pending'),
3265
- color: 'warning',
3266
- },
3267
- ];
3268
- }
3269
- //#endregion
3270
- //#region ---- Component ----
3271
- getComponent() {
3272
- return () => import('./acorex-modules-workflow-management-workflow-task-popover.component-DMszilef.mjs').then((m) => m.AXMWorkflowTaskPopoverComponent);
3145
+ async confirmContinueToNextStep(requiresTakeOver) {
3146
+ const title = await this.translationService.translateAsync('@workflow-management:tasks.dialogs.continue-next-step.title');
3147
+ const messageKey = requiresTakeOver
3148
+ ? '@workflow-management:tasks.dialogs.continue-next-step.take-over-message'
3149
+ : '@workflow-management:tasks.dialogs.continue-next-step.message';
3150
+ const message = await this.translationService.translateAsync(messageKey);
3151
+ const dialogResult = await this.dialogService.confirm(title, message, 'primary', 'horizontal', false, 'cancel');
3152
+ return dialogResult.result === true;
3273
3153
  }
3274
- 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 }); }
3275
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPGenericWorkflowTaskProvider }); }
3276
- }
3277
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPGenericWorkflowTaskProvider, decorators: [{
3278
- type: Injectable
3279
- }], ctorParameters: () => [{ type: undefined, decorators: [{
3280
- type: Inject,
3281
- args: [AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG]
3282
- }] }] });
3283
-
3284
- function provideTaskWorkflow() {
3285
- return makeEnvironmentProviders([
3286
- {
3287
- provide: AXP_WORKFLOW_TASK_PROVIDER,
3288
- multi: true,
3289
- useFactory: (injector) => {
3290
- return (async () => {
3291
- const workflowDefinitionService = injector.get(AXPWorkflowDefinitionService);
3292
- const multiLanguageResolver = injector.get(AXTranslationService);
3293
- const categories = await workflowDefinitionService.getCategories();
3294
- const providers = [];
3295
- const seenDefinitionNames = new Set();
3296
- for (const category of categories) {
3297
- const workflows = await workflowDefinitionService.getWorkflowsByCategoryId(category.id);
3298
- for (const workflow of workflows) {
3299
- const key = workflow.name;
3300
- if (!key || seenDefinitionNames.has(key)) {
3301
- continue;
3302
- }
3303
- seenDefinitionNames.add(key);
3304
- const provider = runInInjectionContext(injector, () => new AXPGenericWorkflowTaskProvider({
3305
- name: workflow.name,
3306
- title: multiLanguageResolver.resolve(workflow.title) ?? workflow.name,
3307
- icon: 'fa-light fa-diagram-project',
3308
- definitionId: workflow.name,
3309
- }));
3310
- providers.push(provider);
3311
- }
3312
- }
3313
- return providers;
3314
- })();
3315
- },
3316
- deps: [Injector],
3317
- },
3318
- ]);
3154
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowTaskContinuationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3155
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowTaskContinuationService, providedIn: 'root' }); }
3319
3156
  }
3157
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowTaskContinuationService, decorators: [{
3158
+ type: Injectable,
3159
+ args: [{ providedIn: 'root' }]
3160
+ }] });
3320
3161
 
3321
3162
  class AXMWorkflowManagementModule {
3322
3163
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMWorkflowManagementModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
@@ -3380,8 +3221,8 @@ class AXMWorkflowManagementModule {
3380
3221
  useClass: AXMWorkflowManagementModuleEntityProvider,
3381
3222
  multi: true,
3382
3223
  },
3383
- provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-Eh5DDK-V.mjs').then((m) => m.AXMWorkflowInstanceActivityInstancesPageComponentProvider)),
3384
- provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-RRzkvrNM.mjs').then((m) => m.AXMWorkflowDefinitionActivitiesPageComponentProvider)),
3224
+ provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-DC_9M9dk.mjs').then((m) => m.AXMWorkflowInstanceActivityInstancesPageComponentProvider)),
3225
+ provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-BhVZ1Bcw.mjs').then((m) => m.AXMWorkflowDefinitionActivitiesPageComponentProvider)),
3385
3226
  // Automation condition builder: default automation.rules(refType, refId); modules override for their refTypes
3386
3227
  {
3387
3228
  provide: AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER,
@@ -3440,29 +3281,18 @@ class AXMWorkflowManagementModule {
3440
3281
  CartableTaskActivity,
3441
3282
  ShowToastActivity,
3442
3283
  CollectSignatureActivity,
3443
- // Generic Workflow Task Provider (all workflows no definitionId filter).
3444
- // For one provider per definition, register in your module with definitionId, e.g.:
3445
- // { provide: AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG, useValue: { name: 'leave-request-workflow-tasks', title: 'Leave Request', definitionId: 'LeaveRequestWorkflow' } },
3446
- // { provide: AXP_WORKFLOW_TASK_PROVIDER, multi: true, useFactory: (c) => new AXPGenericWorkflowTaskProvider(c), deps: [AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG] }
3447
- // Leave Request workflow: task board shows suspended human-tasks.
3448
- // definitionId must match instance.definitionId: mock engine uses workflow name ('createLeaveRequest'); real API may use definition entity id.
3449
- // {
3450
- // provide: AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG,
3451
- // useValue: {
3452
- // name: 'leave-request',
3453
- // title: 'Leave Request Tasks',
3454
- // icon: 'fa-light fa-diagram-project',
3455
- // definitionId: 'createLeaveRequest',
3456
- // } as AXPGenericWorkflowTaskProviderConfig,
3457
- // },
3458
- // {
3459
- // provide: AXP_WORKFLOW_TASK_PROVIDER,
3460
- // multi: true,
3461
- // useFactory: (config: AXPGenericWorkflowTaskProviderConfig) =>
3462
- // new AXPGenericWorkflowTaskProvider(config),
3463
- // deps: [AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG],
3464
- // },
3465
- provideTaskWorkflow()
3284
+ // Per-workflow task provider (lazy-loaded). Import provideGenericWorkflowTaskProvider from provider.task.ts:
3285
+ // provideGenericWorkflowTaskProvider({
3286
+ // name: 'leave-request',
3287
+ // title: 'Leave Request Tasks',
3288
+ // icon: 'fa-light fa-diagram-project',
3289
+ // definitionId: 'createLeaveRequest',
3290
+ // }),
3291
+ provideTaskWorkflow(),
3292
+ {
3293
+ provide: AXP_WORKFLOW_CONTINUATION_HOOK,
3294
+ useExisting: AXPWorkflowTaskContinuationService,
3295
+ },
3466
3296
  ], imports: [AXMCalendarManagementModule,
3467
3297
  AXPDomainModule,
3468
3298
  AXMWorkflowPluginModule, // Register workflow plugin
@@ -3533,8 +3363,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3533
3363
  useClass: AXMWorkflowManagementModuleEntityProvider,
3534
3364
  multi: true,
3535
3365
  },
3536
- provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-Eh5DDK-V.mjs').then((m) => m.AXMWorkflowInstanceActivityInstancesPageComponentProvider)),
3537
- provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-RRzkvrNM.mjs').then((m) => m.AXMWorkflowDefinitionActivitiesPageComponentProvider)),
3366
+ provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-DC_9M9dk.mjs').then((m) => m.AXMWorkflowInstanceActivityInstancesPageComponentProvider)),
3367
+ provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-modules-workflow-management-index-BhVZ1Bcw.mjs').then((m) => m.AXMWorkflowDefinitionActivitiesPageComponentProvider)),
3538
3368
  // Automation condition builder: default automation.rules(refType, refId); modules override for their refTypes
3539
3369
  {
3540
3370
  provide: AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER,
@@ -3593,29 +3423,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3593
3423
  CartableTaskActivity,
3594
3424
  ShowToastActivity,
3595
3425
  CollectSignatureActivity,
3596
- // Generic Workflow Task Provider (all workflows no definitionId filter).
3597
- // For one provider per definition, register in your module with definitionId, e.g.:
3598
- // { provide: AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG, useValue: { name: 'leave-request-workflow-tasks', title: 'Leave Request', definitionId: 'LeaveRequestWorkflow' } },
3599
- // { provide: AXP_WORKFLOW_TASK_PROVIDER, multi: true, useFactory: (c) => new AXPGenericWorkflowTaskProvider(c), deps: [AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG] }
3600
- // Leave Request workflow: task board shows suspended human-tasks.
3601
- // definitionId must match instance.definitionId: mock engine uses workflow name ('createLeaveRequest'); real API may use definition entity id.
3602
- // {
3603
- // provide: AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG,
3604
- // useValue: {
3605
- // name: 'leave-request',
3606
- // title: 'Leave Request Tasks',
3607
- // icon: 'fa-light fa-diagram-project',
3608
- // definitionId: 'createLeaveRequest',
3609
- // } as AXPGenericWorkflowTaskProviderConfig,
3610
- // },
3611
- // {
3612
- // provide: AXP_WORKFLOW_TASK_PROVIDER,
3613
- // multi: true,
3614
- // useFactory: (config: AXPGenericWorkflowTaskProviderConfig) =>
3615
- // new AXPGenericWorkflowTaskProvider(config),
3616
- // deps: [AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG],
3617
- // },
3618
- provideTaskWorkflow()
3426
+ // Per-workflow task provider (lazy-loaded). Import provideGenericWorkflowTaskProvider from provider.task.ts:
3427
+ // provideGenericWorkflowTaskProvider({
3428
+ // name: 'leave-request',
3429
+ // title: 'Leave Request Tasks',
3430
+ // icon: 'fa-light fa-diagram-project',
3431
+ // definitionId: 'createLeaveRequest',
3432
+ // }),
3433
+ provideTaskWorkflow(),
3434
+ {
3435
+ provide: AXP_WORKFLOW_CONTINUATION_HOOK,
3436
+ useExisting: AXPWorkflowTaskContinuationService,
3437
+ },
3619
3438
  ],
3620
3439
  }]
3621
3440
  }] });
@@ -3626,9 +3445,1264 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3626
3445
  // Entity exports - services and modules removed, handled by middleware
3627
3446
  // Exporting entity types for use in feature components
3628
3447
 
3448
+ //#region ---- Workflow task context (reserved keys) ----
3449
+ /**
3450
+ * Human-task / cartable `context` payload: technical ids at the root; display metadata under reserved keys.
3451
+ *
3452
+ * @example
3453
+ * ```json
3454
+ * {
3455
+ * "leaveRequestId": "{{ variables.leaveRequestId }}",
3456
+ * "_taskI18n": {
3457
+ * "employeeDisplayName": "{{ variables.employeeDisplayName }}",
3458
+ * "leaveTypeTitle": "{{ variables.leaveTypeTitle }}"
3459
+ * },
3460
+ * "_taskTitleParts": [
3461
+ * "{{ variables.employeeDisplayName }}",
3462
+ * "{{ variables.leaveTypeTitle }}"
3463
+ * ]
3464
+ * }
3465
+ * ```
3466
+ */
3467
+ /** Interpolation map for `@scope:key` task title and description strings. */
3468
+ const AXP_WORKFLOW_TASK_CONTEXT_I18N_KEY = '_taskI18n';
3469
+ /** Ordered segments joined with " — " when bookmark title is still a generic activity label. */
3470
+ const AXP_WORKFLOW_TASK_CONTEXT_TITLE_PARTS_KEY = '_taskTitleParts';
3471
+ //#endregion
3472
+
3473
+ /**
3474
+ * Injection token for provider config. Use when registering via DI (provide token + useFactory with deps).
3475
+ * Prefer {@link provideGenericWorkflowTaskProvider} (dynamic import) instead of a static class import in NgModule providers.
3476
+ */
3477
+ const AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG = new InjectionToken('AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG');
3478
+ //#endregion
3479
+ //#region ---- Provider Class ----
3480
+ /**
3481
+ * Generic Workflow Task Provider
3482
+ *
3483
+ * Provides tasks from Workflow Instances directly (no Work Items).
3484
+ * Queries suspended workflow instances and extracts tasks from bookmarks.
3485
+ *
3486
+ * Create one provider per workflow definition by passing a config (name, title, definitionId).
3487
+ * E.g. leave request: { name: 'leave-request-workflow-tasks', title: 'Leave Request', definitionId: 'LeaveRequestWorkflow' }
3488
+ *
3489
+ * Architecture:
3490
+ * - Queries Workflow Instances with subStatus = 'Suspended'
3491
+ * - Filters by config.definitionId when set (one provider = one definition)
3492
+ * - Extracts active bookmarks for each instance
3493
+ * - Parses bookmark payload for assignment/actions
3494
+ * - Maps to task board format
3495
+ */
3496
+ class AXPGenericWorkflowTaskProvider extends AXPWorkflowTaskProvider {
3497
+ //#endregion
3498
+ //#region ---- Constructor ----
3499
+ constructor(config) {
3500
+ super();
3501
+ //#endregion
3502
+ //#region ---- Services & Dependencies ----
3503
+ this.entityService = inject(AXPEntityService);
3504
+ this.workflowInstanceData = this.entityService
3505
+ .withEntity('WorkflowManagement', 'WorkflowInstance')
3506
+ .data();
3507
+ this.userEntityData = this.entityService.withEntity('SecurityManagement', 'User').data();
3508
+ this.translationService = inject(AXTranslationService);
3509
+ this.formatService = inject(AXFormatService);
3510
+ this.settingsService = inject(AXPSettingsService);
3511
+ this.entityRegistry = inject(AXPEntityDefinitionRegistryService);
3512
+ this.statusDefinitionService = inject(AXPStatusDefinitionProviderService);
3513
+ this.workflowDefinitionService = inject(AXPWorkflowDefinitionService);
3514
+ this.workflowManager = inject(AXPWorkflowManager);
3515
+ this.humanTaskService = inject(AXPWorkflowInstanceHumanTaskService);
3516
+ this.sessionService = inject(AXPSessionService);
3517
+ this.toastService = inject(AXToastService);
3518
+ /** Per-provider caches (one instance per workflow definition). */
3519
+ this.entityDefinitionCache = new Map();
3520
+ this.statusDefinitionKeyByEntityType = new Map();
3521
+ this.statusProviderByDefinitionKey = new Map();
3522
+ this.userReferenceCache = new Map();
3523
+ this.entityStatusIdCache = new Map();
3524
+ this.config = config;
3525
+ }
3526
+ //#endregion
3527
+ //#region ---- Provider Metadata ----
3528
+ get name() {
3529
+ return this.config.name;
3530
+ }
3531
+ get title() {
3532
+ return this.config.title;
3533
+ }
3534
+ get icon() {
3535
+ return this.config.icon ?? 'fa-light fa-diagram-project';
3536
+ }
3537
+ //#endregion
3538
+ //#region ---- Bookmark Helpers ----
3539
+ /** Bookmark types shown on the workflow task board. */
3540
+ isTaskBoardBookmarkPayload(payload) {
3541
+ const t = payload.activityType;
3542
+ return t === 'workflow-activity:human-task' || t === 'workflow-activity:cartable';
3543
+ }
3544
+ /** Pooled task: must be claimed before submit/cancel (cartable, or human-task with candidates only). */
3545
+ isPooledClaimablePayload(payload) {
3546
+ const assigned = this.normalizeUserIdList(payload.assignedUserIds);
3547
+ const candidates = this.normalizeUserIdList(payload.candidateUserIds);
3548
+ if (payload.activityType === 'workflow-activity:cartable') {
3549
+ return assigned.length === 0 && candidates.length > 0;
3550
+ }
3551
+ return payload.activityType === 'workflow-activity:human-task' && assigned.length === 0 && candidates.length > 0;
3552
+ }
3553
+ normalizeUserIdList(value) {
3554
+ if (!value || value.length === 0)
3555
+ return [];
3556
+ return value.map((id) => String(id)).filter((s) => s.length > 0);
3557
+ }
3558
+ /** Human-task assigned to another user; current user may take over when permitted. */
3559
+ isReassignableHumanTaskPayload(payload) {
3560
+ if (payload.activityType !== 'workflow-activity:human-task') {
3561
+ return false;
3562
+ }
3563
+ const assigned = this.normalizeUserIdList(payload.assignedUserIds);
3564
+ if (assigned.length === 0) {
3565
+ return false;
3566
+ }
3567
+ const currentUserId = this.sessionService.user?.id;
3568
+ if (currentUserId == null) {
3569
+ return false;
3570
+ }
3571
+ return !assigned.includes(String(currentUserId));
3572
+ }
3573
+ canTakeOverTask() {
3574
+ return canReassignWorkflowTaskToSelf(this.sessionService);
3575
+ }
3576
+ //#endregion
3577
+ //#region ---- Task Retrieval ----
3578
+ /**
3579
+ * Get tasks from suspended workflow instances.
3580
+ *
3581
+ * Queries workflow instances filtered by:
3582
+ * - subStatus = 'Suspended'
3583
+ * - entityRefType (if provided in filter)
3584
+ * - definitionId (if provided in filter)
3585
+ * - assignee/claimant (if filter provided)
3586
+ *
3587
+ * Then extracts active bookmarks and maps to task board format.
3588
+ */
3589
+ async getTasks(options) {
3590
+ // Build filter for workflow instances
3591
+ const baseFilter = { logic: 'and', filters: [] };
3592
+ // Filter by subStatus = 'Suspended' (only suspended workflows have pending tasks)
3593
+ baseFilter.filters?.push({
3594
+ field: 'subStatus',
3595
+ operator: { type: 'equal' },
3596
+ value: 'Suspended',
3597
+ });
3598
+ // Scope this provider to one workflow definition
3599
+ if (this.config.definitionId) {
3600
+ baseFilter.filters?.push({
3601
+ field: 'definitionId',
3602
+ operator: { type: 'equal' },
3603
+ value: this.config.definitionId,
3604
+ });
3605
+ }
3606
+ // Date range is applied after mapping bookmarks (task start/end overlap), not on instance createdAt.
3607
+ // Query workflow instances
3608
+ const { items: instances } = await this.workflowInstanceData.query({
3609
+ skip: options?.skip ?? 0,
3610
+ take: options?.take ?? 20,
3611
+ filter: baseFilter,
3612
+ });
3613
+ // Extract tasks from bookmarks for each instance
3614
+ const tasks = [];
3615
+ for (const instance of instances) {
3616
+ try {
3617
+ // Get active bookmarks from instance entity (workflowInstance.bookmarks)
3618
+ const bookmarks = this.getActiveBookmarksFromInstance(instance);
3619
+ // Process each bookmark (typically one per suspended activity)
3620
+ for (const bookmark of bookmarks) {
3621
+ try {
3622
+ // Get payload from entity (payload object or parse payloadJson)
3623
+ let payload;
3624
+ try {
3625
+ const raw = bookmark.payload ?? (bookmark.payloadJson ? JSON.parse(bookmark.payloadJson) : null);
3626
+ payload =
3627
+ typeof raw === 'object' && raw !== null
3628
+ ? raw
3629
+ : {};
3630
+ }
3631
+ catch {
3632
+ continue;
3633
+ }
3634
+ // Task board: human-task and cartable (pooled); exclude other suspended UI bookmarks
3635
+ if (!this.isTaskBoardBookmarkPayload(payload)) {
3636
+ continue;
3637
+ }
3638
+ // Check assignment filter if provided
3639
+ if (options?.assigneeIds && options.assigneeIds.length > 0) {
3640
+ const assignedIds = payload.assignedUserIds || [];
3641
+ const candidateIds = payload.candidateUserIds || [];
3642
+ const allUserIds = [...assignedIds, ...candidateIds].map(String);
3643
+ // TODO: Also check candidateRoleIds by resolving role members
3644
+ if (!matchesTaskBoardAssigneeUserIdsFilter(allUserIds, options.assigneeIds)) {
3645
+ continue;
3646
+ }
3647
+ }
3648
+ // Map bookmark to task
3649
+ const task = await this.mapBookmarkToTask(instance, bookmark, payload);
3650
+ tasks.push(task);
3651
+ }
3652
+ catch {
3653
+ // Skip this bookmark and continue
3654
+ }
3655
+ }
3656
+ }
3657
+ catch {
3658
+ // Skip this instance and continue
3659
+ }
3660
+ }
3661
+ const rangeFiltered = filterTasksOverlappingRange(tasks, options?.range);
3662
+ const total = rangeFiltered.length;
3663
+ const skip = options?.skip ?? 0;
3664
+ const take = options?.take ?? total;
3665
+ const items = rangeFiltered.slice(skip, skip + take);
3666
+ return { items, total };
3667
+ }
3668
+ /**
3669
+ * Get active (non-consumed) bookmarks from workflow instance entity.
3670
+ * Reads from instance.workflowInstance?.bookmarks — no direct DB access.
3671
+ */
3672
+ getActiveBookmarksFromInstance(instance) {
3673
+ const wi = instance?.workflowInstance;
3674
+ const bookmarks = wi?.bookmarks ?? [];
3675
+ const active = bookmarks.filter((b) => !b.isConsumed && !b.consumed);
3676
+ return active;
3677
+ }
3678
+ //#endregion
3679
+ //#region ---- Task Display & Translation ----
3680
+ /** Task-board "started by": workflow instance creator (initiator), not the current viewer. */
3681
+ buildStartedByFromInstance(instance) {
3682
+ const audit = instance.auditInfo?.created?.by;
3683
+ if (audit?.id) {
3684
+ return {
3685
+ id: audit.id,
3686
+ type: 'user',
3687
+ fullName: audit.fullName?.trim() || audit.id,
3688
+ };
3689
+ }
3690
+ const sessionUser = this.sessionService.user;
3691
+ if (sessionUser?.id) {
3692
+ const label = sessionUser.title?.trim() || sessionUser.name?.trim() || sessionUser.id;
3693
+ return { id: sessionUser.id, type: 'user', fullName: label };
3694
+ }
3695
+ return { id: '', type: 'user', fullName: '' };
3696
+ }
3697
+ /**
3698
+ * Builds interpolation params from `context._taskI18n` (workflow-defined; provider stays domain-agnostic).
3699
+ */
3700
+ async buildTaskTranslationParams(context) {
3701
+ const params = {};
3702
+ const i18n = context?.[AXP_WORKFLOW_TASK_CONTEXT_I18N_KEY];
3703
+ if (!i18n || typeof i18n !== 'object' || Array.isArray(i18n)) {
3704
+ return params;
3705
+ }
3706
+ for (const [key, value] of Object.entries(i18n)) {
3707
+ const text = await this.toTaskTranslationParam(value);
3708
+ if (text.length > 0) {
3709
+ params[key] = text;
3710
+ }
3711
+ }
3712
+ return params;
3713
+ }
3714
+ /**
3715
+ * Normalizes bookmark context values for i18n interpolation (strings or multi-language maps).
3716
+ */
3717
+ async toTaskTranslationParam(value) {
3718
+ if (value == null) {
3719
+ return '';
3720
+ }
3721
+ if (value instanceof Date) {
3722
+ return this.formatDateForTaskDisplay(value);
3723
+ }
3724
+ if (typeof value === 'string') {
3725
+ const trimmed = value.trim();
3726
+ if (!trimmed) {
3727
+ return '';
3728
+ }
3729
+ if (this.isDateLikeString(trimmed)) {
3730
+ return this.formatDateForTaskDisplay(trimmed);
3731
+ }
3732
+ return trimmed;
3733
+ }
3734
+ if (typeof value === 'number' || typeof value === 'boolean') {
3735
+ return String(value);
3736
+ }
3737
+ if (typeof value === 'object') {
3738
+ const resolved = this.translationService.resolve(value);
3739
+ return resolved?.trim() ?? '';
3740
+ }
3741
+ return String(value).trim();
3742
+ }
3743
+ /**
3744
+ * Formats dates for task title/description interpolation using regional short-date settings.
3745
+ */
3746
+ async formatDateForTaskDisplay(value) {
3747
+ const date = value instanceof Date
3748
+ ? value
3749
+ : this.parseDateOnlyString(value) ?? this.parseIsoDateString(value);
3750
+ if (!date || Number.isNaN(date.getTime())) {
3751
+ return typeof value === 'string' ? value.trim() : '';
3752
+ }
3753
+ const format = await this.settingsService.get(AXPRegionalSetting.ShortDate);
3754
+ const formatted = this.formatService.format(date, 'date', { format });
3755
+ return typeof formatted === 'string' ? formatted : String(formatted ?? '');
3756
+ }
3757
+ isDateLikeString(value) {
3758
+ return /^\d{4}-\d{2}-\d{2}(?:T|$)/.test(value.trim());
3759
+ }
3760
+ parseIsoDateString(value) {
3761
+ const parsed = new Date(value);
3762
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
3763
+ }
3764
+ /**
3765
+ * Resolves task copy: literal strings pass through; keys starting with `@` are translated with context params.
3766
+ */
3767
+ async resolveTaskDisplayText(value, params) {
3768
+ const raw = value?.trim();
3769
+ if (!raw) {
3770
+ return '';
3771
+ }
3772
+ if (!raw.startsWith('@')) {
3773
+ return raw;
3774
+ }
3775
+ return this.translationService.translateAsync(raw, { params });
3776
+ }
3777
+ /**
3778
+ * Builds a display title from `context._taskTitleParts` when bookmark title is still generic.
3779
+ */
3780
+ async composeTaskTitleFromContext(context) {
3781
+ const parts = context?.[AXP_WORKFLOW_TASK_CONTEXT_TITLE_PARTS_KEY];
3782
+ if (!Array.isArray(parts)) {
3783
+ return '';
3784
+ }
3785
+ const segments = [];
3786
+ for (const part of parts) {
3787
+ const segment = await this.toTaskTranslationParam(part);
3788
+ if (segment.length > 0) {
3789
+ segments.push(segment);
3790
+ }
3791
+ }
3792
+ return segments.join(' — ');
3793
+ }
3794
+ /**
3795
+ * True when bookmark title is the generic activity label, not workflow-specific copy.
3796
+ */
3797
+ isGenericHumanTaskTitle(title) {
3798
+ const normalized = title?.trim().toLowerCase();
3799
+ return (!normalized ||
3800
+ normalized === 'human task' ||
3801
+ normalized === 'cartable task' ||
3802
+ normalized === 'workflow-activity:human-task' ||
3803
+ normalized === 'workflow-activity:cartable' ||
3804
+ normalized === 'workflow task');
3805
+ }
3806
+ //#endregion
3807
+ //#region ---- User Resolution ----
3808
+ /** Resolve platform user id to a display label for the task board grid. */
3809
+ async resolveAssigneeReference(userId) {
3810
+ const id = userId?.trim();
3811
+ if (!id) {
3812
+ return undefined;
3813
+ }
3814
+ const cached = this.userReferenceCache.get(id);
3815
+ if (cached) {
3816
+ return cached;
3817
+ }
3818
+ const load = this.loadUserReference(id);
3819
+ this.userReferenceCache.set(id, load);
3820
+ return load;
3821
+ }
3822
+ async loadUserReference(id) {
3823
+ try {
3824
+ const row = await this.userEntityData.byKey(id);
3825
+ if (!row || typeof row !== 'object') {
3826
+ return { id, type: 'user', fullName: id };
3827
+ }
3828
+ const displayName = 'displayName' in row ? String(row.displayName ?? '').trim() : '';
3829
+ const username = 'username' in row ? String(row.username ?? '').trim() : '';
3830
+ const fullName = displayName || username || id;
3831
+ const ref = { id, type: 'user', fullName };
3832
+ if (username) {
3833
+ ref.username = username;
3834
+ }
3835
+ return ref;
3836
+ }
3837
+ catch {
3838
+ return { id, type: 'user', fullName: id };
3839
+ }
3840
+ }
3841
+ //#endregion
3842
+ //#region ---- Task Mapping ----
3843
+ /** Map bookmark to task board task format. */
3844
+ async mapBookmarkToTask(instance, bookmark, payload) {
3845
+ // Extract dates
3846
+ const dueDate = payload.dueDate
3847
+ ? typeof payload.dueDate === 'string'
3848
+ ? new Date(payload.dueDate)
3849
+ : payload.dueDate
3850
+ : instance.createdAt
3851
+ ? new Date(instance.createdAt)
3852
+ : new Date();
3853
+ const startDate = instance.createdAt ? new Date(instance.createdAt) : dueDate;
3854
+ // If startDate and endDate are the same, set endDate to one day after startDate
3855
+ let endDate = dueDate;
3856
+ if (startDate.getTime() === dueDate.getTime()) {
3857
+ endDate = new Date(startDate);
3858
+ endDate.setDate(endDate.getDate() + 1);
3859
+ }
3860
+ // Map priority
3861
+ const priority = this.mapPriorityToTaskPriority(payload.priority || 'Normal');
3862
+ const taskTranslationParams = await this.buildTaskTranslationParams(payload.context);
3863
+ let titleSource = payload.title || payload.activityName || 'Workflow Task';
3864
+ if (this.isGenericHumanTaskTitle(titleSource)) {
3865
+ const composed = await this.composeTaskTitleFromContext(payload.context);
3866
+ if (composed) {
3867
+ titleSource = composed;
3868
+ }
3869
+ }
3870
+ const title = await this.resolveTaskDisplayText(titleSource, taskTranslationParams);
3871
+ const description = await this.resolveTaskDisplayText(payload.description || `Action required: ${payload.activityName}`, taskTranslationParams);
3872
+ const assigneeId = payload.assignedUserIds?.[0];
3873
+ const assignee = await this.resolveAssigneeReference(assigneeId);
3874
+ const instanceCreatedAt = instance.createdAt ? new Date(instance.createdAt) : startDate;
3875
+ const resolvedStatus = await this.resolveTaskStatus(payload, instance);
3876
+ return {
3877
+ id: bookmark.id, // Use bookmark ID as task ID
3878
+ title,
3879
+ description,
3880
+ startDate,
3881
+ endDate,
3882
+ allDay: false,
3883
+ assignee,
3884
+ index: 2,
3885
+ createdAt: instanceCreatedAt,
3886
+ updatedAt: instance.updatedAt ? new Date(instance.updatedAt) : instanceCreatedAt,
3887
+ status: {
3888
+ id: resolvedStatus.id,
3889
+ title: resolvedStatus.title,
3890
+ },
3891
+ priority,
3892
+ reporter: this.buildStartedByFromInstance(instance),
3893
+ data: {
3894
+ // Store workflow instance and bookmark metadata
3895
+ instanceId: instance.id,
3896
+ bookmarkId: bookmark.id,
3897
+ activityId: bookmark.activityId,
3898
+ activityType: payload.activityType,
3899
+ activityName: payload.activityName,
3900
+ taskToken: payload.taskToken,
3901
+ entityRefId: instance.entityRefId,
3902
+ entityRefType: instance.entityRefType,
3903
+ definitionId: instance.definitionId,
3904
+ statusColor: resolvedStatus.color,
3905
+ entityStatusDefinition: resolvedStatus.definition,
3906
+ entityStatusDefinitionKey: resolvedStatus.definitionKey,
3907
+ // Store full payload for actions
3908
+ payload: payload,
3909
+ },
3910
+ };
3911
+ }
3912
+ /** Map workflow bookmark priority to task board priority. */
3913
+ mapPriorityToTaskPriority(priority) {
3914
+ switch (priority) {
3915
+ case 'Urgent':
3916
+ return 'highest';
3917
+ case 'High':
3918
+ return 'high';
3919
+ case 'Normal':
3920
+ return 'medium';
3921
+ case 'Low':
3922
+ return 'low';
3923
+ default:
3924
+ return 'medium';
3925
+ }
3926
+ }
3927
+ //#endregion
3928
+ //#region ---- Task Updates ----
3929
+ /**
3930
+ * Update tasks (not applicable for workflow instances - they are read-only from task provider perspective).
3931
+ */
3932
+ async updateTasks(tasksToUpdate) {
3933
+ // Workflow instances are managed by workflow engine
3934
+ // Task updates should be done through workflow resume, not direct updates
3935
+ return tasksToUpdate;
3936
+ }
3937
+ //#endregion
3938
+ //#region ---- Command Execution ----
3939
+ /**
3940
+ * Execute commands on tasks.
3941
+ *
3942
+ * Supports:
3943
+ * - Workflow resume commands (Complete, Cancel)
3944
+ */
3945
+ async executeCommand(command) {
3946
+ if (!command?.name)
3947
+ return { success: true };
3948
+ const taskData = command.options?.['data'];
3949
+ const instanceId = taskData?.instanceId ?? command.options?.['instanceId'] ?? '';
3950
+ const bookmarkId = taskData?.bookmarkId ?? command.options?.['bookmarkId'] ?? '';
3951
+ const taskToken = taskData?.taskToken ?? command.options?.['taskToken'] ?? '';
3952
+ const activityId = taskData?.activityId ?? command.options?.['activityId'] ?? command.options?.['stepId'] ?? '';
3953
+ const outcome = command.options?.['outcome'] ?? 'Done';
3954
+ const userInput = command.options?.['userInput'] ?? {};
3955
+ if (command.name === 'WorkflowManagement.WorkflowInstance:ClaimTask') {
3956
+ if (!instanceId || !bookmarkId || !activityId) {
3957
+ return {
3958
+ success: false,
3959
+ message: {
3960
+ text: 'Missing required parameters: instanceId, bookmarkId, activityId',
3961
+ },
3962
+ };
3963
+ }
3964
+ const claimResult = await this.workflowManager.claimTask(instanceId, bookmarkId, activityId);
3965
+ if (!claimResult.success && claimResult.error) {
3966
+ this.toastService.show({
3967
+ color: 'danger',
3968
+ title: await this.translationService.translateAsync('@general:messages.generic.error.title'),
3969
+ content: claimResult.error,
3970
+ });
3971
+ }
3972
+ return {
3973
+ success: claimResult.success,
3974
+ message: claimResult.error
3975
+ ? {
3976
+ text: claimResult.error,
3977
+ }
3978
+ : undefined,
3979
+ };
3980
+ }
3981
+ if (command.name === 'WorkflowManagement.WorkflowInstance:ReassignToSelf') {
3982
+ if (!instanceId || !bookmarkId || !activityId) {
3983
+ return {
3984
+ success: false,
3985
+ message: {
3986
+ text: 'Missing required parameters: instanceId, bookmarkId, activityId',
3987
+ },
3988
+ };
3989
+ }
3990
+ const reassigned = await this.humanTaskService.reassignBookmarkToCurrentUserWithConfirm(instanceId, bookmarkId, activityId);
3991
+ return { success: reassigned };
3992
+ }
3993
+ // Handle workflow resume commands
3994
+ if (command.name === 'WorkflowManagement.WorkflowInstance:Resume' || command.name === 'resume-workflow') {
3995
+ if (!instanceId || !taskToken || !activityId) {
3996
+ return {
3997
+ success: false,
3998
+ message: {
3999
+ text: 'Missing required parameters: instanceId, taskToken, activityId',
4000
+ },
4001
+ };
4002
+ }
4003
+ const result = await this.humanTaskService.resumeSuspendedHumanTask({
4004
+ instanceId,
4005
+ bookmarkId,
4006
+ activityId,
4007
+ taskToken,
4008
+ outcome,
4009
+ userInput: { ...userInput, bookmarkId },
4010
+ });
4011
+ if (result.success) {
4012
+ this.refresh();
4013
+ }
4014
+ return {
4015
+ success: result.success,
4016
+ message: result.error
4017
+ ? {
4018
+ text: result.error,
4019
+ }
4020
+ : undefined,
4021
+ };
4022
+ }
4023
+ return { success: true };
4024
+ }
4025
+ //#endregion
4026
+ //#region ---- Actions & Statuses ----
4027
+ /**
4028
+ * Get available actions for a task.
4029
+ *
4030
+ * Extracts actions from bookmark payload.
4031
+ */
4032
+ async getActions(task) {
4033
+ const actions = [];
4034
+ if (!task)
4035
+ return actions;
4036
+ const taskData = task.data;
4037
+ const payload = taskData?.payload;
4038
+ if (!payload)
4039
+ return actions;
4040
+ if (this.isPooledClaimablePayload(payload)) {
4041
+ actions.push({
4042
+ name: 'claim',
4043
+ title: this.translationService.translateSync('@workflow-management:tasks.actions.claim.title'),
4044
+ icon: 'fa-light fa-hand',
4045
+ color: 'primary',
4046
+ priority: 'primary',
4047
+ command: {
4048
+ name: 'WorkflowManagement.WorkflowInstance:ClaimTask',
4049
+ options: {
4050
+ instanceId: taskData.instanceId,
4051
+ bookmarkId: taskData.bookmarkId,
4052
+ activityId: taskData.activityId,
4053
+ },
4054
+ },
4055
+ });
4056
+ return actions;
4057
+ }
4058
+ // if (this.isReassignableHumanTaskPayload(payload) && this.canTakeOverTask()) {
4059
+ // actions.push({
4060
+ // name: 'reassign-to-self',
4061
+ // title: this.translationService.translateSync('@workflow-management:tasks.actions.reassign-to-self.title'),
4062
+ // icon: 'fa-light fa-user-check',
4063
+ // color: 'warning',
4064
+ // priority: 'secondary',
4065
+ // command: {
4066
+ // name: 'WorkflowManagement.WorkflowInstance:ReassignToSelf',
4067
+ // options: {
4068
+ // instanceId: taskData.instanceId,
4069
+ // bookmarkId: taskData.bookmarkId,
4070
+ // activityId: taskData.activityId,
4071
+ // },
4072
+ // },
4073
+ // });
4074
+ // }
4075
+ // Extract actions from payload
4076
+ if (payload.actions) {
4077
+ const allActions = [...(payload.actions.prefix || []), ...(payload.actions.suffix || [])];
4078
+ for (const action of allActions) {
4079
+ const actionName = action.command?.name || action.name || 'unknown';
4080
+ actions.push({
4081
+ name: actionName,
4082
+ title: action.title || actionName,
4083
+ icon: action.icon,
4084
+ color: action.color,
4085
+ priority: 'primary',
4086
+ command: {
4087
+ name: 'WorkflowManagement.WorkflowInstance:Resume',
4088
+ options: {
4089
+ instanceId: taskData.instanceId,
4090
+ bookmarkId: taskData.bookmarkId,
4091
+ activityId: taskData.activityId,
4092
+ taskToken: taskData.taskToken,
4093
+ outcome: actionName,
4094
+ userInput: {},
4095
+ },
4096
+ },
4097
+ });
4098
+ }
4099
+ }
4100
+ else {
4101
+ // Default actions if none provided
4102
+ actions.push({
4103
+ name: 'submit',
4104
+ title: this.translationService.translateSync('@general:actions.submit.title'),
4105
+ icon: 'fa-light fa-check',
4106
+ color: 'primary',
4107
+ priority: 'primary',
4108
+ command: {
4109
+ name: 'WorkflowManagement.WorkflowInstance:Resume',
4110
+ options: {
4111
+ instanceId: taskData.instanceId,
4112
+ bookmarkId: taskData.bookmarkId,
4113
+ activityId: taskData.activityId,
4114
+ taskToken: taskData.taskToken,
4115
+ outcome: 'submit',
4116
+ userInput: {},
4117
+ },
4118
+ },
4119
+ });
4120
+ actions.push({
4121
+ name: 'cancel',
4122
+ title: this.translationService.translateSync('@general:actions.cancel.title'),
4123
+ icon: 'fa-light fa-times',
4124
+ color: 'default',
4125
+ priority: 'secondary',
4126
+ command: {
4127
+ name: 'WorkflowManagement.WorkflowInstance:Resume',
4128
+ options: {
4129
+ instanceId: taskData.instanceId,
4130
+ bookmarkId: taskData.bookmarkId,
4131
+ activityId: taskData.activityId,
4132
+ taskToken: taskData.taskToken,
4133
+ outcome: 'cancel',
4134
+ userInput: {},
4135
+ },
4136
+ },
4137
+ });
4138
+ }
4139
+ return actions;
4140
+ }
4141
+ async getExtraFields() {
4142
+ return [];
4143
+ }
4144
+ async getStatuses() {
4145
+ const entityType = await this.resolvePrimaryEntityTypeForProvider();
4146
+ if (entityType) {
4147
+ const provider = await this.getEntityStatusProvider(entityType);
4148
+ if (provider) {
4149
+ return this.mapStatusProviderToTaskStatuses(provider);
4150
+ }
4151
+ }
4152
+ return this.getWorkflowTaskStatuses();
4153
+ }
4154
+ //#endregion
4155
+ //#region ---- Entity Status Resolution ----
4156
+ /** Resolves task status from bookmark context `statusId` and entity status plugin; falls back to workflow Pending. */
4157
+ async resolveTaskStatus(payload, instance) {
4158
+ const context = payload.context;
4159
+ const entityType = await this.resolveEntityTypeForTask(context, instance);
4160
+ if (!entityType) {
4161
+ return this.getWorkflowPendingStatus();
4162
+ }
4163
+ const definitionKey = this.getStatusDefinitionKeyForEntityType(entityType);
4164
+ if (!definitionKey) {
4165
+ return this.getWorkflowPendingStatus();
4166
+ }
4167
+ const provider = await this.getStatusProviderByDefinitionKey(definitionKey);
4168
+ if (!provider) {
4169
+ return this.getWorkflowPendingStatus();
4170
+ }
4171
+ let statusId = this.readContextString(context, 'statusId');
4172
+ if (this.isUnresolvedWorkflowExpression(statusId)) {
4173
+ statusId = null;
4174
+ }
4175
+ if (!statusId) {
4176
+ statusId = await this.loadEntityStatusIdFromContext(context, entityType, instance);
4177
+ }
4178
+ if (!statusId) {
4179
+ statusId = await this.loadEntityStatusIdByWorkflowInstance(entityType, instance.id);
4180
+ }
4181
+ if (!statusId) {
4182
+ const defaultStatus = provider.defaultStatus;
4183
+ statusId = typeof defaultStatus === 'string' && defaultStatus.trim().length > 0 ? defaultStatus.trim() : null;
4184
+ }
4185
+ if (statusId) {
4186
+ const definition = provider.statuses.find((status) => status.name === statusId);
4187
+ if (definition) {
4188
+ return {
4189
+ id: definition.name,
4190
+ title: await this.translateStatusTitle(definition.title),
4191
+ color: definition.color,
4192
+ definition,
4193
+ definitionKey,
4194
+ };
4195
+ }
4196
+ }
4197
+ return this.getWorkflowPendingStatus();
4198
+ }
4199
+ async resolveEntityTypeForTask(context, instance) {
4200
+ const fromContext = this.readContextString(context, 'entityType');
4201
+ if (fromContext && (await this.entityTypeHasStatusPlugin(fromContext))) {
4202
+ return fromContext;
4203
+ }
4204
+ const refType = instance.entityRefType?.trim();
4205
+ if (refType && (await this.entityTypeHasStatusPlugin(refType))) {
4206
+ return refType;
4207
+ }
4208
+ return this.resolvePrimaryEntityTypeForProvider();
4209
+ }
4210
+ /** True when a bookmark value was stored without expression evaluation. */
4211
+ isUnresolvedWorkflowExpression(value) {
4212
+ if (!value) {
4213
+ return false;
4214
+ }
4215
+ return /\{\{/.test(value) || /\}\}/.test(value);
4216
+ }
4217
+ /**
4218
+ * Loads `statusId` from the linked entity row when bookmark context omits or stale-fails it.
4219
+ */
4220
+ async loadEntityStatusIdFromContext(context, entityType, instance) {
4221
+ const contextEntityId = this.readContextString(context, 'lifecycleEventId');
4222
+ const refType = instance.entityRefType?.trim();
4223
+ const refId = instance.entityRefId?.trim();
4224
+ const entityId = contextEntityId ??
4225
+ (refType === entityType && refId ? refId : null);
4226
+ if (!entityId) {
4227
+ return null;
4228
+ }
4229
+ return this.loadEntityStatusId(entityType, entityId);
4230
+ }
4231
+ /**
4232
+ * Finds a row of `entityType` linked to this workflow instance (e.g. LifecycleEvent.workflowInfo.instanceId).
4233
+ */
4234
+ async loadEntityStatusIdByWorkflowInstance(entityType, workflowInstanceId) {
4235
+ const instanceId = workflowInstanceId?.trim();
4236
+ if (!instanceId) {
4237
+ return null;
4238
+ }
4239
+ const cacheKey = `${entityType}::wi::${instanceId}`;
4240
+ const cached = this.entityStatusIdCache.get(cacheKey);
4241
+ if (cached) {
4242
+ return cached;
4243
+ }
4244
+ const load = this.fetchEntityStatusIdByWorkflowInstance(entityType, instanceId);
4245
+ this.entityStatusIdCache.set(cacheKey, load);
4246
+ return load;
4247
+ }
4248
+ async fetchEntityStatusIdByWorkflowInstance(entityType, instanceId) {
4249
+ const parsed = this.parseQualifiedEntityType(entityType);
4250
+ if (!parsed) {
4251
+ return null;
4252
+ }
4253
+ try {
4254
+ const { items } = await this.entityService.withEntity(parsed.module, parsed.name).data().query({
4255
+ skip: 0,
4256
+ take: 1,
4257
+ filter: {
4258
+ logic: 'and',
4259
+ filters: [
4260
+ { field: AXP_RECORD_WORKFLOW_INFO_INSTANCE_ID_FIELD, operator: { type: 'equal' }, value: instanceId },
4261
+ ],
4262
+ },
4263
+ });
4264
+ const row = items?.[0];
4265
+ if (!row || typeof row !== 'object') {
4266
+ return null;
4267
+ }
4268
+ const raw = row.statusId;
4269
+ if (raw == null) {
4270
+ return null;
4271
+ }
4272
+ const text = String(raw).trim();
4273
+ return text.length > 0 ? text : null;
4274
+ }
4275
+ catch {
4276
+ return null;
4277
+ }
4278
+ }
4279
+ async loadEntityStatusId(entityType, entityId) {
4280
+ const cacheKey = `${entityType}::${entityId}`;
4281
+ const cached = this.entityStatusIdCache.get(cacheKey);
4282
+ if (cached) {
4283
+ return cached;
4284
+ }
4285
+ const load = this.fetchEntityStatusIdByKey(entityType, entityId);
4286
+ this.entityStatusIdCache.set(cacheKey, load);
4287
+ return load;
4288
+ }
4289
+ async fetchEntityStatusIdByKey(entityType, entityId) {
4290
+ const parsed = this.parseQualifiedEntityType(entityType);
4291
+ if (!parsed) {
4292
+ return null;
4293
+ }
4294
+ try {
4295
+ const row = await this.entityService.withEntity(parsed.module, parsed.name).data().byKey(entityId);
4296
+ if (!row || typeof row !== 'object') {
4297
+ return null;
4298
+ }
4299
+ const raw = row.statusId;
4300
+ if (raw == null) {
4301
+ return null;
4302
+ }
4303
+ const text = String(raw).trim();
4304
+ return text.length > 0 ? text : null;
4305
+ }
4306
+ catch {
4307
+ return null;
4308
+ }
4309
+ }
4310
+ //#endregion
4311
+ //#region ---- Task Board Status Labels ----
4312
+ /** Fallback workflow task-board status when no entity status plugin applies. */
4313
+ getWorkflowPendingStatus() {
4314
+ return {
4315
+ id: AXPSystemStatuses.Pending.name,
4316
+ title: this.translationService.translateSync('@workflow-management:tasks.states.pending'),
4317
+ color: 'warning',
4318
+ };
4319
+ }
4320
+ async getWorkflowTaskStatuses() {
4321
+ const pending = this.getWorkflowPendingStatus();
4322
+ return [
4323
+ {
4324
+ index: 0,
4325
+ key: pending.id,
4326
+ title: pending.title,
4327
+ color: pending.color,
4328
+ },
4329
+ ];
4330
+ }
4331
+ async mapStatusProviderToTaskStatuses(provider) {
4332
+ const sorted = [...provider.statuses].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
4333
+ const statuses = [];
4334
+ for (let index = 0; index < sorted.length; index++) {
4335
+ const status = sorted[index];
4336
+ statuses.push({
4337
+ index,
4338
+ key: status.name,
4339
+ title: await this.translateStatusTitle(status.title),
4340
+ color: status.color,
4341
+ });
4342
+ }
4343
+ return statuses;
4344
+ }
4345
+ async translateStatusTitle(title) {
4346
+ const raw = title?.trim();
4347
+ if (!raw) {
4348
+ return '';
4349
+ }
4350
+ if (raw.startsWith('@')) {
4351
+ return this.translationService.translateAsync(raw);
4352
+ }
4353
+ return raw;
4354
+ }
4355
+ //#endregion
4356
+ //#region ---- Entity Status Cache & Registry ----
4357
+ readContextString(context, key) {
4358
+ const value = context?.[key];
4359
+ if (value == null) {
4360
+ return null;
4361
+ }
4362
+ const text = String(value).trim();
4363
+ return text.length > 0 ? text : null;
4364
+ }
4365
+ parseQualifiedEntityType(entityType) {
4366
+ const trimmed = entityType.trim();
4367
+ const dot = trimmed.indexOf('.');
4368
+ if (dot <= 0 || dot >= trimmed.length - 1) {
4369
+ return null;
4370
+ }
4371
+ return { module: trimmed.slice(0, dot), name: trimmed.slice(dot + 1) };
4372
+ }
4373
+ async resolveEntityDefinition(entityType) {
4374
+ const key = entityType.trim();
4375
+ if (!key) {
4376
+ return null;
4377
+ }
4378
+ const existing = this.entityDefinitionCache.get(key);
4379
+ if (existing) {
4380
+ return existing;
4381
+ }
4382
+ const load = this.fetchEntityDefinition(key);
4383
+ this.entityDefinitionCache.set(key, load);
4384
+ return load;
4385
+ }
4386
+ async fetchEntityDefinition(entityType) {
4387
+ const parsed = this.parseQualifiedEntityType(entityType);
4388
+ if (!parsed) {
4389
+ return null;
4390
+ }
4391
+ try {
4392
+ return await this.entityRegistry.resolve(parsed.module, parsed.name);
4393
+ }
4394
+ catch {
4395
+ return null;
4396
+ }
4397
+ }
4398
+ getStatusPluginDefinitionKey(entity) {
4399
+ const plugin = entity.plugins?.find((p) => p.name === 'status');
4400
+ const definition = plugin?.options?.['definition'];
4401
+ return typeof definition === 'string' && definition.trim().length > 0 ? definition.trim() : null;
4402
+ }
4403
+ async entityTypeHasStatusPlugin(entityType) {
4404
+ if (!entityType?.trim()) {
4405
+ return false;
4406
+ }
4407
+ await this.warmStatusDefinitionKeyCache(entityType);
4408
+ return this.getStatusDefinitionKeyForEntityType(entityType) != null;
4409
+ }
4410
+ getStatusDefinitionKeyForEntityType(entityType) {
4411
+ const key = entityType.trim();
4412
+ if (!key) {
4413
+ return null;
4414
+ }
4415
+ if (this.statusDefinitionKeyByEntityType.has(key)) {
4416
+ return this.statusDefinitionKeyByEntityType.get(key) ?? null;
4417
+ }
4418
+ return null;
4419
+ }
4420
+ /**
4421
+ * Warms status-definition-key cache for an entity type (call after resolveEntityDefinition).
4422
+ */
4423
+ rememberStatusDefinitionKeyForEntityType(entityType, entity) {
4424
+ const key = entityType.trim();
4425
+ if (!key || this.statusDefinitionKeyByEntityType.has(key)) {
4426
+ return;
4427
+ }
4428
+ const definitionKey = entity ? this.getStatusPluginDefinitionKey(entity) : null;
4429
+ this.statusDefinitionKeyByEntityType.set(key, definitionKey);
4430
+ }
4431
+ async getEntityStatusProvider(entityType) {
4432
+ let definitionKey = this.getStatusDefinitionKeyForEntityType(entityType);
4433
+ if (!definitionKey) {
4434
+ const entity = await this.resolveEntityDefinition(entityType);
4435
+ this.rememberStatusDefinitionKeyForEntityType(entityType, entity);
4436
+ definitionKey = this.getStatusDefinitionKeyForEntityType(entityType);
4437
+ }
4438
+ if (!definitionKey) {
4439
+ return undefined;
4440
+ }
4441
+ return this.getStatusProviderByDefinitionKey(definitionKey);
4442
+ }
4443
+ getStatusProviderByDefinitionKey(definitionKey) {
4444
+ const key = definitionKey.trim();
4445
+ const existing = this.statusProviderByDefinitionKey.get(key);
4446
+ if (existing) {
4447
+ return existing;
4448
+ }
4449
+ const load = this.statusDefinitionService.getStatus(key);
4450
+ this.statusProviderByDefinitionKey.set(key, load);
4451
+ return load;
4452
+ }
4453
+ //#endregion
4454
+ //#region ---- Entity Status Presentation ----
4455
+ /** Maps entity status semantic colors to badge-layout tokens (`info` → `accent3`). */
4456
+ mapEntityStatusColorForBadge(color, statusId) {
4457
+ const normalized = color?.trim().toLowerCase();
4458
+ if (normalized === 'info') {
4459
+ return 'accent3';
4460
+ }
4461
+ const badgeColors = new Set([
4462
+ 'primary',
4463
+ 'secondary',
4464
+ 'success',
4465
+ 'warning',
4466
+ 'danger',
4467
+ 'neutral',
4468
+ 'ghost',
4469
+ 'accent1',
4470
+ 'accent2',
4471
+ 'accent3',
4472
+ ]);
4473
+ if (normalized && badgeColors.has(normalized)) {
4474
+ return normalized;
4475
+ }
4476
+ return this.resolveTaskStatusColor(statusId);
4477
+ }
4478
+ async findStatusDefinition(entityType, statusId) {
4479
+ const provider = await this.getEntityStatusProvider(entityType);
4480
+ return provider?.statuses.find((status) => status.name === statusId);
4481
+ }
4482
+ async warmStatusDefinitionKeyCache(entityType) {
4483
+ if (this.statusDefinitionKeyByEntityType.has(entityType.trim())) {
4484
+ return;
4485
+ }
4486
+ const entity = await this.resolveEntityDefinition(entityType);
4487
+ this.rememberStatusDefinitionKeyForEntityType(entityType, entity);
4488
+ }
4489
+ /**
4490
+ * First `entity-create` target in this workflow whose entity has a status plugin (cached per provider).
4491
+ */
4492
+ async resolvePrimaryEntityTypeForProvider() {
4493
+ if (this.primaryEntityTypeWithStatus !== undefined) {
4494
+ return this.primaryEntityTypeWithStatus;
4495
+ }
4496
+ let resolved = null;
4497
+ const definitionId = this.config.definitionId?.trim();
4498
+ if (definitionId) {
4499
+ const definition = await this.workflowDefinitionService.getWorkflowByName(definitionId);
4500
+ for (const activity of definition?.graph?.activities ?? []) {
4501
+ if (activity.name !== 'workflow-activity:entity-create') {
4502
+ continue;
4503
+ }
4504
+ const entity = activity.inputs?.['entity'];
4505
+ if (typeof entity !== 'string' || !entity.trim()) {
4506
+ continue;
4507
+ }
4508
+ const entityType = entity.trim();
4509
+ await this.warmStatusDefinitionKeyCache(entityType);
4510
+ if (this.getStatusDefinitionKeyForEntityType(entityType)) {
4511
+ resolved = entityType;
4512
+ break;
4513
+ }
4514
+ }
4515
+ }
4516
+ this.primaryEntityTypeWithStatus = resolved;
4517
+ return resolved;
4518
+ }
4519
+ //#endregion
4520
+ //#region ---- Popover Metadata ----
4521
+ async getPopoverMetadata(task) {
4522
+ return this.buildPopoverMetadata(task);
4523
+ }
4524
+ /**
4525
+ * Builds label/value metadata rows for the workflow task popover (view-mode widgets).
4526
+ */
4527
+ async buildPopoverMetadata(task) {
4528
+ const context = {};
4529
+ const fields = [];
4530
+ const payload = task.data?.payload;
4531
+ const pushField = (name, title, widgetType, value, options = {}, allowEmpty = false) => {
4532
+ if (!allowEmpty && !this.hasMeaningfulPopoverValue(value)) {
4533
+ return;
4534
+ }
4535
+ context[name] = value;
4536
+ fields.push({
4537
+ name,
4538
+ title,
4539
+ node: {
4540
+ type: widgetType,
4541
+ name,
4542
+ path: name,
4543
+ mode: 'view',
4544
+ options,
4545
+ },
4546
+ });
4547
+ };
4548
+ if (task.status?.id != null && String(task.status.id).trim()) {
4549
+ const taskData = task.data;
4550
+ const statusId = String(task.status.id);
4551
+ const statusDefinition = taskData?.entityStatusDefinition;
4552
+ const statusDefinitionKey = taskData?.entityStatusDefinitionKey;
4553
+ if (statusDefinitionKey && statusDefinition) {
4554
+ // Pass the full status definition so the chip renders before async provider load completes.
4555
+ pushField('status', '@general:terms.status.title', AXPWidgetsList.Advanced.Status, statusDefinition, {
4556
+ definitionKey: statusDefinitionKey,
4557
+ readonly: true,
4558
+ });
4559
+ }
4560
+ else {
4561
+ const statusColor = this.mapEntityStatusColorForBadge(statusDefinition?.color ??
4562
+ task.data?.statusColor, task.status.id);
4563
+ pushField('status', '@general:terms.status.title', AXPWidgetsList.Layouts.BadgeLayout, {
4564
+ text: task.status.title,
4565
+ color: statusColor,
4566
+ icon: statusDefinition?.icon ?? 'fa-light fa-flag',
4567
+ }, { look: 'twotone' });
4568
+ }
4569
+ }
4570
+ pushField('assignee', '@workflow-management:tasks.popover.assignee', AXPWidgetsCatalog.text, this.formatUserReferenceLabel(task.assignee), {}, true);
4571
+ pushField('startedBy', '@workflow-management:tasks.popover.started-by', AXPWidgetsCatalog.text, this.formatUserReferenceLabel(task.reporter), {}, true);
4572
+ const createdAt = task.createdAt ?? task.startDate;
4573
+ if (createdAt) {
4574
+ pushField('createdAt', '@workflow-management:tasks.popover.created', AXPWidgetsCatalog.dateTime, createdAt, {
4575
+ showTime: false,
4576
+ });
4577
+ }
4578
+ const effectiveDate = this.resolveEffectiveDateValue(payload?.context);
4579
+ if (effectiveDate.kind === 'date') {
4580
+ pushField('effectiveDate', '@workflow-management:tasks.popover.effective-date', AXPWidgetsCatalog.dateTime, effectiveDate.value, { showTime: false });
4581
+ }
4582
+ else if (effectiveDate.kind === 'text') {
4583
+ pushField('effectiveDate', '@workflow-management:tasks.popover.effective-date', AXPWidgetsCatalog.text, effectiveDate.value);
4584
+ }
4585
+ if (task.priority) {
4586
+ pushField('priority', '@workflow-management:tasks.popover.priority', AXPWidgetsList.Layouts.BadgeLayout, {
4587
+ text: task.priority.charAt(0).toUpperCase() + task.priority.slice(1),
4588
+ color: this.resolveTaskPriorityColor(task.priority),
4589
+ icon: 'fa-light fa-exclamation-circle',
4590
+ }, { look: 'twotone' });
4591
+ }
4592
+ return { context, fields };
4593
+ }
4594
+ //#endregion
4595
+ //#region ---- Popover Helpers ----
4596
+ hasMeaningfulPopoverValue(value) {
4597
+ if (value === null || value === undefined) {
4598
+ return false;
4599
+ }
4600
+ if (typeof value === 'string') {
4601
+ const trimmed = value.trim();
4602
+ return trimmed.length > 0 && trimmed !== '—';
4603
+ }
4604
+ if (value instanceof Date) {
4605
+ return !Number.isNaN(value.getTime());
4606
+ }
4607
+ return true;
4608
+ }
4609
+ formatUserReferenceLabel(user) {
4610
+ return user?.fullName?.trim() || user?.username?.trim() || '—';
4611
+ }
4612
+ resolveDueDate(raw) {
4613
+ if (raw == null || raw === '') {
4614
+ return null;
4615
+ }
4616
+ const date = typeof raw === 'string' ? new Date(raw) : raw;
4617
+ return Number.isNaN(date.getTime()) ? null : date;
4618
+ }
4619
+ resolveEffectiveDateValue(context) {
4620
+ if (!context || typeof context !== 'object') {
4621
+ return { kind: 'none' };
4622
+ }
4623
+ const i18n = context[AXP_WORKFLOW_TASK_CONTEXT_I18N_KEY];
4624
+ const rawFromI18n = i18n && typeof i18n === 'object' && !Array.isArray(i18n)
4625
+ ? i18n['effectiveDate']
4626
+ : undefined;
4627
+ const raw = rawFromI18n ??
4628
+ context['effectiveDate'] ??
4629
+ (context['result'] && typeof context['result'] === 'object' && !Array.isArray(context['result'])
4630
+ ? context['result']['effectiveDate']
4631
+ : undefined);
4632
+ if (raw instanceof Date) {
4633
+ return Number.isNaN(raw.getTime()) ? { kind: 'none' } : { kind: 'date', value: raw };
4634
+ }
4635
+ if (typeof raw !== 'string' || !raw.trim()) {
4636
+ return { kind: 'none' };
4637
+ }
4638
+ const trimmed = raw.trim();
4639
+ const parsed = this.parseDateOnlyString(trimmed);
4640
+ if (parsed) {
4641
+ return { kind: 'date', value: parsed };
4642
+ }
4643
+ return { kind: 'text', value: trimmed };
4644
+ }
4645
+ /** Parses `yyyy-mm-dd` (and ISO date prefixes) in local time to avoid UTC day shifts in the date widget. */
4646
+ parseDateOnlyString(value) {
4647
+ const dateOnlyMatch = /^(\d{4})-(\d{2})-(\d{2})/.exec(value.trim());
4648
+ if (!dateOnlyMatch) {
4649
+ return null;
4650
+ }
4651
+ const year = Number(dateOnlyMatch[1]);
4652
+ const month = Number(dateOnlyMatch[2]);
4653
+ const day = Number(dateOnlyMatch[3]);
4654
+ if (!year || month < 1 || month > 12 || day < 1 || day > 31) {
4655
+ return null;
4656
+ }
4657
+ const local = new Date(year, month - 1, day);
4658
+ return Number.isNaN(local.getTime()) ? null : local;
4659
+ }
4660
+ resolveTaskStatusColor(statusId) {
4661
+ const id = String(statusId);
4662
+ if (id === AXPSystemStatuses.Pending.name) {
4663
+ return 'warning';
4664
+ }
4665
+ return 'primary';
4666
+ }
4667
+ resolveTaskPriorityColor(priority) {
4668
+ switch (priority) {
4669
+ case 'highest':
4670
+ return 'danger';
4671
+ case 'high':
4672
+ return 'warning';
4673
+ case 'medium':
4674
+ return 'secondary';
4675
+ case 'low':
4676
+ case 'lowest':
4677
+ return 'neutral';
4678
+ default:
4679
+ return 'primary';
4680
+ }
4681
+ }
4682
+ //#endregion
4683
+ //#region ---- Component ----
4684
+ getComponent() {
4685
+ return () => import('./acorex-modules-workflow-management-workflow-task-popover.component-DjYDwHWU.mjs').then((m) => m.AXMWorkflowTaskPopoverComponent);
4686
+ }
4687
+ 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 }); }
4688
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPGenericWorkflowTaskProvider }); }
4689
+ }
4690
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPGenericWorkflowTaskProvider, decorators: [{
4691
+ type: Injectable
4692
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
4693
+ type: Inject,
4694
+ args: [AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG]
4695
+ }] }] });
4696
+
4697
+ var genericWorkflowTask_provider = /*#__PURE__*/Object.freeze({
4698
+ __proto__: null,
4699
+ AXPGenericWorkflowTaskProvider: AXPGenericWorkflowTaskProvider,
4700
+ AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG: AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG
4701
+ });
4702
+
3629
4703
  /**
3630
4704
  * Generated bundle index. Do not edit.
3631
4705
  */
3632
4706
 
3633
- export { AXCCategoryProvider, AXMMenuProvider, AXMPermissionsKeys, AXMWorkflowActivitiesDefinitionProvider, AXMWorkflowManagementModule, AXMWorkflowManagementModuleEntityProvider, AXPCreateEntityActivity, AXPGenericWorkflowTaskProvider, AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG, AXP_WORKFLOW_TASK_CONTEXT_I18N_KEY, AXP_WORKFLOW_TASK_CONTEXT_TITLE_PARTS_KEY, CartableTaskActivity, CollectSignatureActivity, CreateEntityFormActivity, HumanTaskActivity, RootConfig, ShowConfirmPopupActivity, ShowLayoutPopupActivity, ShowToastActivity };
4707
+ export { AXCCategoryProvider, AXMMenuProvider, AXMPermissionsKeys, AXMWorkflowActivitiesDefinitionProvider, AXMWorkflowManagementModule, AXMWorkflowManagementModuleEntityProvider, AXPCreateEntityActivity, AXPGenericWorkflowTaskProvider, AXPWorkflowInstanceHumanTaskService, AXPWorkflowTaskContinuationService, AXP_GENERIC_WORKFLOW_TASK_PROVIDER_CONFIG, AXP_WORKFLOW_TASK_CONTEXT_I18N_KEY, AXP_WORKFLOW_TASK_CONTEXT_TITLE_PARTS_KEY, CartableTaskActivity, CollectSignatureActivity, CreateEntityFormActivity, HumanTaskActivity, RootConfig, ShowConfirmPopupActivity, ShowLayoutPopupActivity, ShowToastActivity, createWorkflowInstanceBookmarkAccess, getWorkflowInstanceInitiatorUserId, isWorkflowPlatformRootUser, isWorkflowPooledClaimablePayload, isWorkflowReassignableHumanTaskPayload, isWorkflowTaskBoardBookmarkPayload, needsTakeOverForWorkflowTaskContinuation, normalizeWorkflowTaskUserIds, parseWorkflowTaskContinuationPayload, provideGenericWorkflowTaskProvider, provideTaskWorkflow, shouldOfferWorkflowContinuationAfterStep, shouldOfferWorkflowTaskContinuation };
3634
4708
  //# sourceMappingURL=acorex-modules-workflow-management.mjs.map