@hotmeshio/long-tail 0.21.0 → 0.21.1

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 (217) hide show
  1. package/build/api/escalations/accumulate.d.ts +8 -0
  2. package/build/api/escalations/accumulate.js +25 -0
  3. package/build/api/escalations/index.d.ts +1 -1
  4. package/build/api/escalations/index.js +2 -1
  5. package/build/api/scan-codes/context.d.ts +14 -1
  6. package/build/api/scan-codes/context.js +30 -2
  7. package/build/api/scan-codes/identity.js +1 -0
  8. package/build/api/scan-codes/verbs.d.ts +9 -3
  9. package/build/api/scan-codes/verbs.js +77 -23
  10. package/build/index.d.ts +2 -1
  11. package/build/index.js +3 -2
  12. package/build/routes/escalations/accumulate.js +8 -0
  13. package/build/sdk/index.d.ts +3 -0
  14. package/build/sdk/index.js +1 -0
  15. package/build/services/scan-code/index.d.ts +1 -1
  16. package/build/services/scan-code/index.js +3 -1
  17. package/build/services/scan-code/parse.d.ts +17 -3
  18. package/build/services/scan-code/parse.js +37 -4
  19. package/build/services/scan-code/validate.js +19 -0
  20. package/build/system/mcp-servers/admin/escalations.js +6 -1
  21. package/build/system/mcp-servers/admin/schemas.d.ts +6 -3
  22. package/build/system/mcp-servers/admin/schemas.js +2 -1
  23. package/build/system/seed/tool-manifests-admin.d.ts +189 -0
  24. package/build/system/seed/tool-manifests-admin.js +1 -1
  25. package/build/types/index.d.ts +2 -2
  26. package/build/types/index.js +2 -1
  27. package/build/types/scan-code.d.ts +31 -1
  28. package/build/types/scan-code.js +20 -2
  29. package/dashboard/dist/assets/{AdminDashboard-uarpHB88.js → AdminDashboard-Covdam48.js} +2 -2
  30. package/dashboard/dist/assets/{AdminDashboard-uarpHB88.js.map → AdminDashboard-Covdam48.js.map} +1 -1
  31. package/dashboard/dist/assets/{AgentConfigPage-BcUaDD5E.js → AgentConfigPage-CE1k6J5r.js} +2 -2
  32. package/dashboard/dist/assets/{AgentConfigPage-BcUaDD5E.js.map → AgentConfigPage-CE1k6J5r.js.map} +1 -1
  33. package/dashboard/dist/assets/{AgentDetailPage-BaZBhK6i.js → AgentDetailPage-CWJZIZP1.js} +2 -2
  34. package/dashboard/dist/assets/{AgentDetailPage-BaZBhK6i.js.map → AgentDetailPage-CWJZIZP1.js.map} +1 -1
  35. package/dashboard/dist/assets/{AgentsPage-CuVFSDc4.js → AgentsPage---Dg5ufF.js} +2 -2
  36. package/dashboard/dist/assets/{AgentsPage-CuVFSDc4.js.map → AgentsPage---Dg5ufF.js.map} +1 -1
  37. package/dashboard/dist/assets/{AvailableEscalationsPage-iO5NyyIK.js → AvailableEscalationsPage-CpbC8oTN.js} +2 -2
  38. package/dashboard/dist/assets/{AvailableEscalationsPage-iO5NyyIK.js.map → AvailableEscalationsPage-CpbC8oTN.js.map} +1 -1
  39. package/dashboard/dist/assets/{BotPicker-CClMby6B.js → BotPicker-D3drO3-T.js} +2 -2
  40. package/dashboard/dist/assets/{BotPicker-CClMby6B.js.map → BotPicker-D3drO3-T.js.map} +1 -1
  41. package/dashboard/dist/assets/{BulkAssignModal-BL8FRgkN.js → BulkAssignModal-BOAWsViq.js} +2 -2
  42. package/dashboard/dist/assets/{BulkAssignModal-BL8FRgkN.js.map → BulkAssignModal-BOAWsViq.js.map} +1 -1
  43. package/dashboard/dist/assets/{CapabilitiesPage-D53ogPor.js → CapabilitiesPage-RGgD3YZO.js} +2 -2
  44. package/dashboard/dist/assets/{CapabilitiesPage-D53ogPor.js.map → CapabilitiesPage-RGgD3YZO.js.map} +1 -1
  45. package/dashboard/dist/assets/{CollapsibleSection-ow8jpbtD.js → CollapsibleSection-DNkZn87n.js} +2 -2
  46. package/dashboard/dist/assets/{CollapsibleSection-ow8jpbtD.js.map → CollapsibleSection-DNkZn87n.js.map} +1 -1
  47. package/dashboard/dist/assets/{ConfirmDeleteModal-CeEDt9iJ.js → ConfirmDeleteModal-BqzOwhPr.js} +2 -2
  48. package/dashboard/dist/assets/{ConfirmDeleteModal-CeEDt9iJ.js.map → ConfirmDeleteModal-BqzOwhPr.js.map} +1 -1
  49. package/dashboard/dist/assets/{CountdownTimer-CSqyZMCG.js → CountdownTimer-BaexQMK6.js} +2 -2
  50. package/dashboard/dist/assets/{CountdownTimer-CSqyZMCG.js.map → CountdownTimer-BaexQMK6.js.map} +1 -1
  51. package/dashboard/dist/assets/{CredentialsPage-Dx7SxA23.js → CredentialsPage-D7abp0aS.js} +2 -2
  52. package/dashboard/dist/assets/{CredentialsPage-Dx7SxA23.js.map → CredentialsPage-D7abp0aS.js.map} +1 -1
  53. package/dashboard/dist/assets/{CronLabel-LYPxpvNN.js → CronLabel-DZiWmTwJ.js} +2 -2
  54. package/dashboard/dist/assets/{CronLabel-LYPxpvNN.js.map → CronLabel-DZiWmTwJ.js.map} +1 -1
  55. package/dashboard/dist/assets/{ElapsedCell-BZJTSm9N.js → ElapsedCell-BdGO_w4v.js} +2 -2
  56. package/dashboard/dist/assets/{ElapsedCell-BZJTSm9N.js.map → ElapsedCell-BdGO_w4v.js.map} +1 -1
  57. package/dashboard/dist/assets/{EntityTimelinePanel-0wIIW2en.js → EntityTimelinePanel-DIDcF5Yu.js} +2 -2
  58. package/dashboard/dist/assets/{EntityTimelinePanel-0wIIW2en.js.map → EntityTimelinePanel-DIDcF5Yu.js.map} +1 -1
  59. package/dashboard/dist/assets/{EscalationListSchemaPage-CoYvtMzj.js → EscalationListSchemaPage-C28rn9XC.js} +2 -2
  60. package/dashboard/dist/assets/{EscalationListSchemaPage-CoYvtMzj.js.map → EscalationListSchemaPage-C28rn9XC.js.map} +1 -1
  61. package/dashboard/dist/assets/{EscalationListView-DWFHPufv.js → EscalationListView-CkBnkpDJ.js} +2 -2
  62. package/dashboard/dist/assets/{EscalationListView-DWFHPufv.js.map → EscalationListView-CkBnkpDJ.js.map} +1 -1
  63. package/dashboard/dist/assets/{EscalationSchemaPage-C9Xu_A25.js → EscalationSchemaPage-W5r0A1kj.js} +2 -2
  64. package/dashboard/dist/assets/{EscalationSchemaPage-C9Xu_A25.js.map → EscalationSchemaPage-W5r0A1kj.js.map} +1 -1
  65. package/dashboard/dist/assets/{EscalationTimeline-D8W2LNNk.js → EscalationTimeline-DKyTz6sM.js} +2 -2
  66. package/dashboard/dist/assets/{EscalationTimeline-D8W2LNNk.js.map → EscalationTimeline-DKyTz6sM.js.map} +1 -1
  67. package/dashboard/dist/assets/{EscalationTitleSelect-DLK8NWMp.js → EscalationTitleSelect-CzKfavri.js} +2 -2
  68. package/dashboard/dist/assets/{EscalationTitleSelect-DLK8NWMp.js.map → EscalationTitleSelect-CzKfavri.js.map} +1 -1
  69. package/dashboard/dist/assets/{EscalationsOverview-CW57FaP9.js → EscalationsOverview-Tdu3Yx2c.js} +2 -2
  70. package/dashboard/dist/assets/{EscalationsOverview-CW57FaP9.js.map → EscalationsOverview-Tdu3Yx2c.js.map} +1 -1
  71. package/dashboard/dist/assets/{EventTable-D1ctWhKf.js → EventTable-DiIxOJwO.js} +2 -2
  72. package/dashboard/dist/assets/{EventTable-D1ctWhKf.js.map → EventTable-DiIxOJwO.js.map} +1 -1
  73. package/dashboard/dist/assets/{FilterBar-C-iur-Nj.js → FilterBar-CvMBCVIo.js} +2 -2
  74. package/dashboard/dist/assets/{FilterBar-C-iur-Nj.js.map → FilterBar-CvMBCVIo.js.map} +1 -1
  75. package/dashboard/dist/assets/{GraphInvokePage-CcA_44M4.js → GraphInvokePage-DO-yyhi6.js} +2 -2
  76. package/dashboard/dist/assets/{GraphInvokePage-CcA_44M4.js.map → GraphInvokePage-DO-yyhi6.js.map} +1 -1
  77. package/dashboard/dist/assets/{HomePage-Dc085ghJ.js → HomePage-DSS3eHR2.js} +2 -2
  78. package/dashboard/dist/assets/{HomePage-Dc085ghJ.js.map → HomePage-DSS3eHR2.js.map} +1 -1
  79. package/dashboard/dist/assets/{ListToolbar-h_ziBt4O.js → ListToolbar-C3-Tqqub.js} +2 -2
  80. package/dashboard/dist/assets/{ListToolbar-h_ziBt4O.js.map → ListToolbar-C3-Tqqub.js.map} +1 -1
  81. package/dashboard/dist/assets/{McpOverview-qXXhbNWV.js → McpOverview-DEJmsdVi.js} +2 -2
  82. package/dashboard/dist/assets/{McpOverview-qXXhbNWV.js.map → McpOverview-DEJmsdVi.js.map} +1 -1
  83. package/dashboard/dist/assets/{McpQueryDetailPage-SEzSbZrd.js → McpQueryDetailPage-DYJr16l7.js} +2 -2
  84. package/dashboard/dist/assets/{McpQueryDetailPage-SEzSbZrd.js.map → McpQueryDetailPage-DYJr16l7.js.map} +1 -1
  85. package/dashboard/dist/assets/{McpQueryPage-Cy0V0kv9.js → McpQueryPage-BBcG_UuU.js} +2 -2
  86. package/dashboard/dist/assets/{McpQueryPage-Cy0V0kv9.js.map → McpQueryPage-BBcG_UuU.js.map} +1 -1
  87. package/dashboard/dist/assets/{McpRunDetailPage-DjJO5vSb.js → McpRunDetailPage-C6xw0kBg.js} +2 -2
  88. package/dashboard/dist/assets/{McpRunDetailPage-DjJO5vSb.js.map → McpRunDetailPage-C6xw0kBg.js.map} +1 -1
  89. package/dashboard/dist/assets/{McpRunsPage-BfjiJ8mM.js → McpRunsPage-CRQqrF4Q.js} +2 -2
  90. package/dashboard/dist/assets/{McpRunsPage-BfjiJ8mM.js.map → McpRunsPage-CRQqrF4Q.js.map} +1 -1
  91. package/dashboard/dist/assets/{OperationsPage-dJcER0T_.js → OperationsPage-Dlfwzf-0.js} +2 -2
  92. package/dashboard/dist/assets/{OperationsPage-dJcER0T_.js.map → OperationsPage-Dlfwzf-0.js.map} +1 -1
  93. package/dashboard/dist/assets/{OperatorDashboard-zCkW4eqk.js → OperatorDashboard-DoiDGZ9R.js} +2 -2
  94. package/dashboard/dist/assets/{OperatorDashboard-zCkW4eqk.js.map → OperatorDashboard-DoiDGZ9R.js.map} +1 -1
  95. package/dashboard/dist/assets/{PersonaDetailPage-Cx6L3Jvu.js → PersonaDetailPage-BzbA4Prr.js} +2 -2
  96. package/dashboard/dist/assets/{PersonaDetailPage-Cx6L3Jvu.js.map → PersonaDetailPage-BzbA4Prr.js.map} +1 -1
  97. package/dashboard/dist/assets/{PersonasPage-DOgGUlJl.js → PersonasPage-B36yn4hU.js} +2 -2
  98. package/dashboard/dist/assets/{PersonasPage-DOgGUlJl.js.map → PersonasPage-B36yn4hU.js.map} +1 -1
  99. package/dashboard/dist/assets/{PortalPage-BKuL1BeJ.js → PortalPage-BkD4YfDf.js} +2 -2
  100. package/dashboard/dist/assets/{PortalPage-BKuL1BeJ.js.map → PortalPage-BkD4YfDf.js.map} +1 -1
  101. package/dashboard/dist/assets/{ProcessDetailPage-BFcFSDUv.js → ProcessDetailPage-BT0eiBWY.js} +2 -2
  102. package/dashboard/dist/assets/{ProcessDetailPage-BFcFSDUv.js.map → ProcessDetailPage-BT0eiBWY.js.map} +1 -1
  103. package/dashboard/dist/assets/{ProcessesListPage-BaHV2cXp.js → ProcessesListPage-BEqeeNae.js} +2 -2
  104. package/dashboard/dist/assets/{ProcessesListPage-BaHV2cXp.js.map → ProcessesListPage-BEqeeNae.js.map} +1 -1
  105. package/dashboard/dist/assets/{ResolverForm-Bgc0Zrya.js → ResolverForm-BwgjIX97.js} +2 -2
  106. package/dashboard/dist/assets/{ResolverForm-Bgc0Zrya.js.map → ResolverForm-BwgjIX97.js.map} +1 -1
  107. package/dashboard/dist/assets/{RoleDetailPage-BPY6i3CU.js → RoleDetailPage-BFuLNJXa.js} +2 -2
  108. package/dashboard/dist/assets/{RoleDetailPage-BPY6i3CU.js.map → RoleDetailPage-BFuLNJXa.js.map} +1 -1
  109. package/dashboard/dist/assets/{RolesPage-DSqqKPbv.js → RolesPage-80quJU5-.js} +2 -2
  110. package/dashboard/dist/assets/{RolesPage-DSqqKPbv.js.map → RolesPage-80quJU5-.js.map} +1 -1
  111. package/dashboard/dist/assets/{RunAsSelector-B29iWwel.js → RunAsSelector-BoePhWVD.js} +2 -2
  112. package/dashboard/dist/assets/{RunAsSelector-B29iWwel.js.map → RunAsSelector-BoePhWVD.js.map} +1 -1
  113. package/dashboard/dist/assets/{ScanCodesPage-S8aAJfnC.js → ScanCodesPage-Cu1bKEix.js} +2 -2
  114. package/dashboard/dist/assets/{ScanCodesPage-S8aAJfnC.js.map → ScanCodesPage-Cu1bKEix.js.map} +1 -1
  115. package/dashboard/dist/assets/ScanSchemeDetailPage-D9AbS6UY.js +2 -0
  116. package/dashboard/dist/assets/ScanSchemeDetailPage-D9AbS6UY.js.map +1 -0
  117. package/dashboard/dist/assets/{ScanStationPage-R9t1-CeQ.js → ScanStationPage-gcZGefvT.js} +2 -2
  118. package/dashboard/dist/assets/{ScanStationPage-R9t1-CeQ.js.map → ScanStationPage-gcZGefvT.js.map} +1 -1
  119. package/dashboard/dist/assets/{StickyPagination-CkW_A507.js → StickyPagination-9ITrei_d.js} +2 -2
  120. package/dashboard/dist/assets/{StickyPagination-CkW_A507.js.map → StickyPagination-9ITrei_d.js.map} +1 -1
  121. package/dashboard/dist/assets/{StreamMessageDetail-yzWX0wac.js → StreamMessageDetail-BkYvEHFY.js} +2 -2
  122. package/dashboard/dist/assets/{StreamMessageDetail-yzWX0wac.js.map → StreamMessageDetail-BkYvEHFY.js.map} +1 -1
  123. package/dashboard/dist/assets/{SwimlaneTimeline-Cf4DXFxj.js → SwimlaneTimeline-B1rotFix.js} +2 -2
  124. package/dashboard/dist/assets/{SwimlaneTimeline-Cf4DXFxj.js.map → SwimlaneTimeline-B1rotFix.js.map} +1 -1
  125. package/dashboard/dist/assets/{TaskDetailPage-DCDcEps9.js → TaskDetailPage-zhn_U_eC.js} +2 -2
  126. package/dashboard/dist/assets/{TaskDetailPage-DCDcEps9.js.map → TaskDetailPage-zhn_U_eC.js.map} +1 -1
  127. package/dashboard/dist/assets/{TasksListPage-BBATgpf7.js → TasksListPage-CNbNeagx.js} +2 -2
  128. package/dashboard/dist/assets/{TasksListPage-BBATgpf7.js.map → TasksListPage-CNbNeagx.js.map} +1 -1
  129. package/dashboard/dist/assets/{TimeAgo-CSNVEjch.js → TimeAgo-0YVMBwls.js} +2 -2
  130. package/dashboard/dist/assets/{TimeAgo-CSNVEjch.js.map → TimeAgo-0YVMBwls.js.map} +1 -1
  131. package/dashboard/dist/assets/{TimestampCell-Du1nBrPn.js → TimestampCell-DB7r3np8.js} +2 -2
  132. package/dashboard/dist/assets/{TimestampCell-Du1nBrPn.js.map → TimestampCell-DB7r3np8.js.map} +1 -1
  133. package/dashboard/dist/assets/{ToolTestPanel-CF-h_5Rg.js → ToolTestPanel-BLfA02wv.js} +2 -2
  134. package/dashboard/dist/assets/{ToolTestPanel-CF-h_5Rg.js.map → ToolTestPanel-BLfA02wv.js.map} +1 -1
  135. package/dashboard/dist/assets/{TopicDetailPage-Dr1UmWcp.js → TopicDetailPage-eAqPKShq.js} +2 -2
  136. package/dashboard/dist/assets/{TopicDetailPage-Dr1UmWcp.js.map → TopicDetailPage-eAqPKShq.js.map} +1 -1
  137. package/dashboard/dist/assets/{TopicsPage-CUUo-Ylf.js → TopicsPage-BNNWD-zl.js} +2 -2
  138. package/dashboard/dist/assets/{TopicsPage-CUUo-Ylf.js.map → TopicsPage-BNNWD-zl.js.map} +1 -1
  139. package/dashboard/dist/assets/{UserName-kBh1dc39.js → UserName-Pw46tO_k.js} +2 -2
  140. package/dashboard/dist/assets/{UserName-kBh1dc39.js.map → UserName-Pw46tO_k.js.map} +1 -1
  141. package/dashboard/dist/assets/{WorkflowExecutionPage-CCRSbnDx.js → WorkflowExecutionPage-DvA51lT3.js} +2 -2
  142. package/dashboard/dist/assets/{WorkflowExecutionPage-CCRSbnDx.js.map → WorkflowExecutionPage-DvA51lT3.js.map} +1 -1
  143. package/dashboard/dist/assets/{WorkflowsDashboard-BNQVvyek.js → WorkflowsDashboard-DFDTwnhn.js} +2 -2
  144. package/dashboard/dist/assets/{WorkflowsDashboard-BNQVvyek.js.map → WorkflowsDashboard-DFDTwnhn.js.map} +1 -1
  145. package/dashboard/dist/assets/{WorkflowsOverview-DswubNJN.js → WorkflowsOverview-5i2Tcy-p.js} +2 -2
  146. package/dashboard/dist/assets/{WorkflowsOverview-DswubNJN.js.map → WorkflowsOverview-5i2Tcy-p.js.map} +1 -1
  147. package/dashboard/dist/assets/{YamlWorkflowDetailPage-Cw9Dlmup.js → YamlWorkflowDetailPage-p4VEYZS0.js} +2 -2
  148. package/dashboard/dist/assets/{YamlWorkflowDetailPage-Cw9Dlmup.js.map → YamlWorkflowDetailPage-p4VEYZS0.js.map} +1 -1
  149. package/dashboard/dist/assets/{YamlWorkflowsPage-DB8xnIXy.js → YamlWorkflowsPage-Cq-hMVxl.js} +2 -2
  150. package/dashboard/dist/assets/{YamlWorkflowsPage-DB8xnIXy.js.map → YamlWorkflowsPage-Cq-hMVxl.js.map} +1 -1
  151. package/dashboard/dist/assets/{agents-BwEnf6N9.js → agents-EyBPJMYa.js} +2 -2
  152. package/dashboard/dist/assets/{agents-BwEnf6N9.js.map → agents-EyBPJMYa.js.map} +1 -1
  153. package/dashboard/dist/assets/{bots-CCmJTT2u.js → bots-DX6jjqtF.js} +2 -2
  154. package/dashboard/dist/assets/{bots-CCmJTT2u.js.map → bots-DX6jjqtF.js.map} +1 -1
  155. package/dashboard/dist/assets/{capabilities-BZHgp_nh.js → capabilities-ZdLv9xBQ.js} +2 -2
  156. package/dashboard/dist/assets/{capabilities-BZHgp_nh.js.map → capabilities-ZdLv9xBQ.js.map} +1 -1
  157. package/dashboard/dist/assets/{controlplane-CyfwUlFA.js → controlplane-CpvZaJuw.js} +2 -2
  158. package/dashboard/dist/assets/{controlplane-CyfwUlFA.js.map → controlplane-CpvZaJuw.js.map} +1 -1
  159. package/dashboard/dist/assets/{escalation-columns-BJPTNmLW.js → escalation-columns-Mvsze5eV.js} +2 -2
  160. package/dashboard/dist/assets/{escalation-columns-BJPTNmLW.js.map → escalation-columns-Mvsze5eV.js.map} +1 -1
  161. package/dashboard/dist/assets/{index-CDrqqbSR.js → index-B_GT23TE.js} +3 -3
  162. package/dashboard/dist/assets/{index-CDrqqbSR.js.map → index-B_GT23TE.js.map} +1 -1
  163. package/dashboard/dist/assets/{index-CVwzCZ43.js → index-BbCjGO3M.js} +2 -2
  164. package/dashboard/dist/assets/{index-CVwzCZ43.js.map → index-BbCjGO3M.js.map} +1 -1
  165. package/dashboard/dist/assets/{index-CuVkSmj5.js → index-Bhb89oHH.js} +2 -2
  166. package/dashboard/dist/assets/{index-CuVkSmj5.js.map → index-Bhb89oHH.js.map} +1 -1
  167. package/dashboard/dist/assets/{index-3gbd5neL.js → index-CgUcYveM.js} +33 -33
  168. package/dashboard/dist/assets/index-CgUcYveM.js.map +1 -0
  169. package/dashboard/dist/assets/{index-BAAVTyZ-.js → index-Cn8uJsd7.js} +2 -2
  170. package/dashboard/dist/assets/{index-BAAVTyZ-.js.map → index-Cn8uJsd7.js.map} +1 -1
  171. package/dashboard/dist/assets/{index-C7KHqOTQ.js → index-D-Xs4rAW.js} +2 -2
  172. package/dashboard/dist/assets/{index-C7KHqOTQ.js.map → index-D-Xs4rAW.js.map} +1 -1
  173. package/dashboard/dist/assets/{index-DZ8X_Gp4.js → index-DGmzBY9D.js} +2 -2
  174. package/dashboard/dist/assets/{index-DZ8X_Gp4.js.map → index-DGmzBY9D.js.map} +1 -1
  175. package/dashboard/dist/assets/{index-DBWS5QL8.js → index-DZhtP2Ok.js} +2 -2
  176. package/dashboard/dist/assets/{index-DBWS5QL8.js.map → index-DZhtP2Ok.js.map} +1 -1
  177. package/dashboard/dist/assets/{index-ClVbfe4z.js → index-DkrBFFSO.js} +2 -2
  178. package/dashboard/dist/assets/{index-ClVbfe4z.js.map → index-DkrBFFSO.js.map} +1 -1
  179. package/dashboard/dist/assets/{index-BC6Jenlo.js → index-Eo-l3Lqo.js} +2 -2
  180. package/dashboard/dist/assets/{index-BC6Jenlo.js.map → index-Eo-l3Lqo.js.map} +1 -1
  181. package/dashboard/dist/assets/{index-DIWCI6HC.js → index-PfSRKerc.js} +2 -2
  182. package/dashboard/dist/assets/{index-DIWCI6HC.js.map → index-PfSRKerc.js.map} +1 -1
  183. package/dashboard/dist/assets/{index-DAuX_PlL.js → index-oFKUFGQL.js} +2 -2
  184. package/dashboard/dist/assets/{index-DAuX_PlL.js.map → index-oFKUFGQL.js.map} +1 -1
  185. package/dashboard/dist/assets/{index-CaGF6TCC.js → index-z5Hpeidu.js} +2 -2
  186. package/dashboard/dist/assets/{index-CaGF6TCC.js.map → index-z5Hpeidu.js.map} +1 -1
  187. package/dashboard/dist/assets/{knowledge-CqyLhUMg.js → knowledge-CgloEkaf.js} +2 -2
  188. package/dashboard/dist/assets/{knowledge-CqyLhUMg.js.map → knowledge-CgloEkaf.js.map} +1 -1
  189. package/dashboard/dist/assets/{mcp-Cvu6bFYH.js → mcp-Bix7QYO7.js} +2 -2
  190. package/dashboard/dist/assets/{mcp-Cvu6bFYH.js.map → mcp-Bix7QYO7.js.map} +1 -1
  191. package/dashboard/dist/assets/{mcp-query-qC6A3e9l.js → mcp-query-o-sGX2ST.js} +2 -2
  192. package/dashboard/dist/assets/{mcp-query-qC6A3e9l.js.map → mcp-query-o-sGX2ST.js.map} +1 -1
  193. package/dashboard/dist/assets/{personas-BKN_lJuV.js → personas-30azkJ_s.js} +2 -2
  194. package/dashboard/dist/assets/{personas-BKN_lJuV.js.map → personas-30azkJ_s.js.map} +1 -1
  195. package/dashboard/dist/assets/{pipelines-BldIfv85.js → pipelines-Bfk2GFK7.js} +2 -2
  196. package/dashboard/dist/assets/{pipelines-BldIfv85.js.map → pipelines-Bfk2GFK7.js.map} +1 -1
  197. package/dashboard/dist/assets/{tasks-B-Uay8uL.js → tasks-CpdopewW.js} +2 -2
  198. package/dashboard/dist/assets/{tasks-B-Uay8uL.js.map → tasks-CpdopewW.js.map} +1 -1
  199. package/dashboard/dist/assets/{topics-438EQogt.js → topics--bvCV9Yp.js} +2 -2
  200. package/dashboard/dist/assets/{topics-438EQogt.js.map → topics--bvCV9Yp.js.map} +1 -1
  201. package/dashboard/dist/assets/{useDebouncedValue-Cw8hYZ8y.js → useDebouncedValue-Da0lPmj3.js} +2 -2
  202. package/dashboard/dist/assets/{useDebouncedValue-Cw8hYZ8y.js.map → useDebouncedValue-Da0lPmj3.js.map} +1 -1
  203. package/dashboard/dist/assets/{useNamespace-D1218GQ8.js → useNamespace-DD_Esl6n.js} +2 -2
  204. package/dashboard/dist/assets/{useNamespace-D1218GQ8.js.map → useNamespace-DD_Esl6n.js.map} +1 -1
  205. package/dashboard/dist/assets/{useYamlActivityEvents-BAQf_y_U.js → useYamlActivityEvents-AeAhZJJk.js} +2 -2
  206. package/dashboard/dist/assets/{useYamlActivityEvents-BAQf_y_U.js.map → useYamlActivityEvents-AeAhZJJk.js.map} +1 -1
  207. package/dashboard/dist/assets/{yaml-workflows-CN01gEB0.js → yaml-workflows-BHAOOGvn.js} +2 -2
  208. package/dashboard/dist/assets/{yaml-workflows-CN01gEB0.js.map → yaml-workflows-BHAOOGvn.js.map} +1 -1
  209. package/dashboard/dist/index.html +1 -1
  210. package/docs/accumulator.md +3 -3
  211. package/docs/api/http/escalations.md +2 -1
  212. package/docs/api/sdk/escalations.md +3 -2
  213. package/docs/scan-codes.md +20 -9
  214. package/package.json +1 -1
  215. package/dashboard/dist/assets/ScanSchemeDetailPage-CUBRAtmJ.js +0 -2
  216. package/dashboard/dist/assets/ScanSchemeDetailPage-CUBRAtmJ.js.map +0 -1
  217. package/dashboard/dist/assets/index-3gbd5neL.js.map +0 -1
@@ -1,2 +1,2 @@
1
- import{a as f,j as e}from"./vendor-query-DvWWuNIB.js";import{aZ as N,b4 as S,bc as w,bd as I,a4 as F,be as v,a6 as j,Z as _,w as O,bf as A,aX as k,j as M,aG as $,a0 as V}from"./index-3gbd5neL.js";import{u as W}from"./useContainerWidth-DSLp1gEm.js";import{u as T,E as q,a as z,b as B}from"./EscalationTimeline-D8W2LNNk.js";import{E as G}from"./EscalationListView-DWFHPufv.js";import{P as K,ak as Y,al as H,am as U,aA as X,L as C}from"./vendor-icons-B7OcUM6b.js";import{u as Z,L as y,e as D}from"./vendor-react-_9U4mKFr.js";import"./DataTable-spX1dFyb.js";import"./EmptyState-DgC_6njU.js";import"./escalation-columns-BJPTNmLW.js";import"./EntityTimelinePanel-0wIIW2en.js";import"./FilterBar-C-iur-Nj.js";import"./PriorityBadge-r33mpDju.js";import"./RolePill-BafrASDX.js";import"./WorkflowPill-ZepbO_ny.js";import"./UserName-kBh1dc39.js";import"./CountdownTimer-CSqyZMCG.js";import"./StatusBadge-DHVwxre2.js";import"./StickyPagination-CkW_A507.js";const E="system.escalation.",L=[["escalations"]];function Q(t,i){const l=new Set;let c=!1;for(const{url:d}of t){const s=N(i(d));if(!s)continue;const n=S(s);n?l.add(n):c=!0}if(c||l.size===0)return{patterns:c?[w({})]:[],keysFor:()=>L};const a=new Map([...l].map(d=>[I(d),d]));return{patterns:[...l].sort().map(d=>w({role:d})),keysFor(d){const s=d.startsWith(E)?d.slice(E.length).split(".")[0]:"",n=a.get(s);return n?[["escalations",{role:n}],["escalations","available",{role:n}]]:L}}}const J=25,ee=15e3,te={statusFilter:"",facets:{}},se={"--lt-sticky-top":"0px"};function ae({pin:t,url:i,from:l}){const c=Z(),a=f.useMemo(()=>N(i),[i]),[p,d]=f.useState(null),[s,n]=f.useState(void 0),m=s??(a==null?void 0:a.facets.orderBy),o=f.useMemo(()=>a?m===a.facets.orderBy?a:{...a,facets:{...a.facets,orderBy:m}}:null,[a,m]),r=T(o??te,{limit:J,offset:0,staleTime:ee,enabled:o!==null}),h=o?F(p??o.view,r.hasRichView):null,b=f.useMemo(()=>Object.keys((o==null?void 0:o.facets.facets)??{}),[o]),g=x=>c(`/escalations/detail/${x.id}`,{state:{from:l}}),u=Math.max(0,r.total-r.escalations.length);return e.jsxs("section",{className:"min-h-0 flex flex-col overflow-hidden border border-surface-border bg-surface-sunken rounded-[var(--lt-radius-section)]",style:se,"data-testid":"portal-panel",children:[e.jsxs("header",{className:"flex items-center justify-between gap-2 px-4 py-2.5 shrink-0 border-b border-surface-border bg-surface-hover",children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx(K,{className:"w-3.5 h-3.5 shrink-0 text-accent/60",strokeWidth:1.5}),e.jsx("h2",{className:"section-h2 truncate",title:t.label,children:t.label}),o&&r.total>0&&e.jsx("span",{className:"text-2xs tabular-nums text-text-tertiary","data-testid":"portal-panel-count",children:v(r.total)})]}),e.jsxs("div",{className:"flex items-center gap-1.5 shrink-0",children:[o&&h!==j.TIMELINE&&r.hasRichView&&e.jsx("div",{role:"radiogroup","aria-label":"Panel view",className:"flex items-center rounded overflow-hidden border border-surface-border",children:[{key:j.TABLE,title:"Table view",Icon:Y},{key:j.RICH,title:"Rich view",Icon:H}].map(({key:x,title:P,Icon:R})=>e.jsx("button",{type:"button",role:"radio","aria-checked":h===x,onClick:()=>d(x),className:`px-1.5 py-1 transition-colors ${h===x?"bg-accent text-text-inverse":"icon-link hover:bg-surface-raised"}`,title:P,children:e.jsx(R,{className:"w-3.5 h-3.5"})},x))}),o&&e.jsx(q,{orderBy:m,onChange:n}),o&&e.jsx("button",{type:"button",onClick:r.refetch,disabled:r.isFetching,className:"inline-flex h-7 w-7 items-center justify-center rounded icon-link hover:bg-surface-hover disabled:opacity-50",title:"Refresh",children:e.jsx(U,{className:`w-3.5 h-3.5 ${r.isFetching?"animate-spin":""}`})}),e.jsx(y,{to:i,className:"inline-flex h-7 w-7 items-center justify-center rounded icon-link hover:bg-surface-hover",title:"Open the full view","data-testid":"portal-panel-open",children:e.jsx(X,{className:"w-3.5 h-3.5"})})]})]}),e.jsxs("div",{className:"flex-1 min-h-0 overflow-y-auto @container px-4 py-3",children:[o?r.error?e.jsxs("p",{className:"py-6 text-center text-xs text-status-error",role:"alert",children:["Failed to load: ",r.error.message]}):h===j.TIMELINE?e.jsx(z,{escalations:r.escalations,highlightKeys:b,onRowClick:g,total:r.total,page:1,totalPages:1,onPageChange:()=>{}}):h===j.RICH?e.jsx(G,{role:r.singleRole,listSchema:r.listSchema,activeEscalations:r.escalations,onRowClick:g,onOpenGroup:x=>c(x)}):e.jsx(B,{escalations:r.escalations,highlightKeys:b,onRowClick:g,isLoading:r.isLoading,layout:o.layout}):e.jsxs("p",{className:"py-6 text-center text-xs text-text-quaternary",children:[e.jsx(y,{to:i,className:"text-accent hover:underline",children:t.label})," opens as its own page."]}),u>0&&e.jsxs(y,{to:i,className:"block pt-3 pb-1 text-2xs text-accent hover:underline","data-testid":"portal-panel-more",children:[v(u)," more in the full view"]})]})]})}const ne=54;function re(){if(typeof document>"u")return 16;const t=parseFloat(getComputedStyle(document.documentElement).fontSize);return Number.isFinite(t)&&t>0?t:16}function le({rows:t,resolveUrl:i,from:l}){const[c,a]=W(),p=a!==null&&a<ne*re(),d=(s,n)=>e.jsx(ae,{pin:s,url:i(s.url),from:l},n);return p?e.jsx("div",{ref:c,className:"flex-1 min-h-0 overflow-y-auto grid grid-cols-1 gap-5 auto-rows-[minmax(18rem,auto)]","data-testid":"portal-grid","data-stacked":"true",children:t.flatMap((s,n)=>s.map((m,o)=>d(m,`${n}-${o}`)))}):e.jsx("div",{ref:c,className:"flex-1 min-h-0 grid gap-5",style:{gridTemplateRows:`repeat(${t.length}, minmax(0, 1fr))`},"data-testid":"portal-grid",children:t.map((s,n)=>e.jsx("div",{className:"min-h-0 grid gap-5",style:{gridTemplateColumns:`repeat(${s.length}, minmax(0, 1fr))`},"data-testid":"portal-row",children:s.map((m,o)=>d(m,`${n}-${o}`))},n))})}const oe={statusFilter:"",facets:{}},ie=15e3;function ce({count:t,url:i}){const l=f.useMemo(()=>N(i),[i]),c=T(l??oe,{limit:1,offset:0,staleTime:ie,enabled:l!==null}),a=l?c.isLoading&&c.total===0?null:c.total:null;return e.jsxs(y,{to:i,className:"block min-w-0 border border-surface-border bg-surface-sunken rounded-[var(--lt-radius-section)] px-4 py-3 hover:bg-surface-hover transition-colors",title:`Open ${t.label}`,"data-testid":"portal-count",children:[e.jsx("p",{className:"text-2xs uppercase tracking-widest text-text-tertiary truncate",children:t.label}),e.jsx("p",{className:"mt-1 text-3xl font-light leading-none text-text-primary","data-testid":"portal-count-value",children:a===null?e.jsx("span",{className:"text-text-quaternary",children:"—"}):v(a)}),t.blurb&&e.jsx("p",{className:"mt-1.5 text-xs text-text-secondary leading-snug",children:t.blurb})]})}function de({counts:t,resolveUrl:i}){return t.length===0?null:e.jsx("div",{className:"grid gap-4 shrink-0 mb-4",style:{gridTemplateColumns:"repeat(auto-fit, minmax(10rem, 1fr))"},"data-testid":"portal-counts",children:t.map((l,c)=>e.jsx(ce,{count:l,url:i(l.url)},`${l.label}-${c}`))})}function me({text:t}){return e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-center py-10 text-center",children:[e.jsx(C,{className:"w-6 h-6 text-text-quaternary/50 mb-2",strokeWidth:1}),e.jsx("p",{className:"text-xs text-text-quaternary",children:t})]})}function Se(){const{role:t="",portal:i}=D(),{data:l,isFetched:c}=_(),{resolveUrl:a}=O(),p=l==null?void 0:l.roles.find(u=>u.role===t),d=A(p),s=i?d.find(u=>u.key===i):d[0],n=(s==null?void 0:s.rows)??null,m=(s==null?void 0:s.counts)??[],o=s?k(t,s.key):k(t),r=f.useMemo(()=>Q(n?[...n.flat(),...m]:[],a),[n,m,a]),h=M("LIST");$(r.patterns,u=>{h(r.keysFor(u.type))});const b=n?n.reduce((u,x)=>u+x.length,0):0,g=c?d.length===0?"This role declares no portal yet. Compose one under Admin, Roles, Portal.":s?null:"This role has no portal by that name.":null;return e.jsxs("div",{className:"flex-1 min-h-0 flex flex-col -mt-[calc(2rem-var(--lt-space-page-x))] -mb-[calc(4rem-var(--lt-space-page-x))]",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3 shrink-0 text-2xs uppercase tracking-widest text-text-tertiary",children:[e.jsx(C,{className:"w-3 h-3 text-accent/60 shrink-0",strokeWidth:1.5}),e.jsx("h1",{className:"truncate font-semibold",title:t,children:V(p??{role:t})}),s&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"text-text-quaternary",children:"·"}),e.jsx("span",{className:"truncate","data-testid":"portal-title",children:s.label})]}),b>0&&e.jsxs("span",{className:"text-text-quaternary normal-case tracking-normal",children:[b," ",b===1?"view":"views"]})]}),c?g?e.jsx(me,{text:g}):e.jsxs(e.Fragment,{children:[e.jsx(de,{counts:m,resolveUrl:a}),e.jsx(le,{rows:n,resolveUrl:a,from:o})]}):null]})}export{Se as PortalPage};
2
- //# sourceMappingURL=PortalPage-BKuL1BeJ.js.map
1
+ import{a as f,j as e}from"./vendor-query-DvWWuNIB.js";import{aZ as N,b4 as S,bc as w,bd as I,a4 as F,be as v,a6 as j,Z as _,w as O,bf as A,aX as k,j as M,aG as $,a0 as V}from"./index-CgUcYveM.js";import{u as W}from"./useContainerWidth-DSLp1gEm.js";import{u as T,E as q,a as z,b as B}from"./EscalationTimeline-DKyTz6sM.js";import{E as G}from"./EscalationListView-CkBnkpDJ.js";import{P as K,ak as Y,al as H,am as U,aA as X,L as C}from"./vendor-icons-B7OcUM6b.js";import{u as Z,L as y,e as D}from"./vendor-react-_9U4mKFr.js";import"./DataTable-spX1dFyb.js";import"./EmptyState-DgC_6njU.js";import"./escalation-columns-Mvsze5eV.js";import"./EntityTimelinePanel-DIDcF5Yu.js";import"./FilterBar-CvMBCVIo.js";import"./PriorityBadge-r33mpDju.js";import"./RolePill-BafrASDX.js";import"./WorkflowPill-ZepbO_ny.js";import"./UserName-Pw46tO_k.js";import"./CountdownTimer-BaexQMK6.js";import"./StatusBadge-DHVwxre2.js";import"./StickyPagination-9ITrei_d.js";const E="system.escalation.",L=[["escalations"]];function Q(t,i){const l=new Set;let c=!1;for(const{url:d}of t){const s=N(i(d));if(!s)continue;const n=S(s);n?l.add(n):c=!0}if(c||l.size===0)return{patterns:c?[w({})]:[],keysFor:()=>L};const a=new Map([...l].map(d=>[I(d),d]));return{patterns:[...l].sort().map(d=>w({role:d})),keysFor(d){const s=d.startsWith(E)?d.slice(E.length).split(".")[0]:"",n=a.get(s);return n?[["escalations",{role:n}],["escalations","available",{role:n}]]:L}}}const J=25,ee=15e3,te={statusFilter:"",facets:{}},se={"--lt-sticky-top":"0px"};function ae({pin:t,url:i,from:l}){const c=Z(),a=f.useMemo(()=>N(i),[i]),[p,d]=f.useState(null),[s,n]=f.useState(void 0),m=s??(a==null?void 0:a.facets.orderBy),o=f.useMemo(()=>a?m===a.facets.orderBy?a:{...a,facets:{...a.facets,orderBy:m}}:null,[a,m]),r=T(o??te,{limit:J,offset:0,staleTime:ee,enabled:o!==null}),h=o?F(p??o.view,r.hasRichView):null,b=f.useMemo(()=>Object.keys((o==null?void 0:o.facets.facets)??{}),[o]),g=x=>c(`/escalations/detail/${x.id}`,{state:{from:l}}),u=Math.max(0,r.total-r.escalations.length);return e.jsxs("section",{className:"min-h-0 flex flex-col overflow-hidden border border-surface-border bg-surface-sunken rounded-[var(--lt-radius-section)]",style:se,"data-testid":"portal-panel",children:[e.jsxs("header",{className:"flex items-center justify-between gap-2 px-4 py-2.5 shrink-0 border-b border-surface-border bg-surface-hover",children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx(K,{className:"w-3.5 h-3.5 shrink-0 text-accent/60",strokeWidth:1.5}),e.jsx("h2",{className:"section-h2 truncate",title:t.label,children:t.label}),o&&r.total>0&&e.jsx("span",{className:"text-2xs tabular-nums text-text-tertiary","data-testid":"portal-panel-count",children:v(r.total)})]}),e.jsxs("div",{className:"flex items-center gap-1.5 shrink-0",children:[o&&h!==j.TIMELINE&&r.hasRichView&&e.jsx("div",{role:"radiogroup","aria-label":"Panel view",className:"flex items-center rounded overflow-hidden border border-surface-border",children:[{key:j.TABLE,title:"Table view",Icon:Y},{key:j.RICH,title:"Rich view",Icon:H}].map(({key:x,title:P,Icon:R})=>e.jsx("button",{type:"button",role:"radio","aria-checked":h===x,onClick:()=>d(x),className:`px-1.5 py-1 transition-colors ${h===x?"bg-accent text-text-inverse":"icon-link hover:bg-surface-raised"}`,title:P,children:e.jsx(R,{className:"w-3.5 h-3.5"})},x))}),o&&e.jsx(q,{orderBy:m,onChange:n}),o&&e.jsx("button",{type:"button",onClick:r.refetch,disabled:r.isFetching,className:"inline-flex h-7 w-7 items-center justify-center rounded icon-link hover:bg-surface-hover disabled:opacity-50",title:"Refresh",children:e.jsx(U,{className:`w-3.5 h-3.5 ${r.isFetching?"animate-spin":""}`})}),e.jsx(y,{to:i,className:"inline-flex h-7 w-7 items-center justify-center rounded icon-link hover:bg-surface-hover",title:"Open the full view","data-testid":"portal-panel-open",children:e.jsx(X,{className:"w-3.5 h-3.5"})})]})]}),e.jsxs("div",{className:"flex-1 min-h-0 overflow-y-auto @container px-4 py-3",children:[o?r.error?e.jsxs("p",{className:"py-6 text-center text-xs text-status-error",role:"alert",children:["Failed to load: ",r.error.message]}):h===j.TIMELINE?e.jsx(z,{escalations:r.escalations,highlightKeys:b,onRowClick:g,total:r.total,page:1,totalPages:1,onPageChange:()=>{}}):h===j.RICH?e.jsx(G,{role:r.singleRole,listSchema:r.listSchema,activeEscalations:r.escalations,onRowClick:g,onOpenGroup:x=>c(x)}):e.jsx(B,{escalations:r.escalations,highlightKeys:b,onRowClick:g,isLoading:r.isLoading,layout:o.layout}):e.jsxs("p",{className:"py-6 text-center text-xs text-text-quaternary",children:[e.jsx(y,{to:i,className:"text-accent hover:underline",children:t.label})," opens as its own page."]}),u>0&&e.jsxs(y,{to:i,className:"block pt-3 pb-1 text-2xs text-accent hover:underline","data-testid":"portal-panel-more",children:[v(u)," more in the full view"]})]})]})}const ne=54;function re(){if(typeof document>"u")return 16;const t=parseFloat(getComputedStyle(document.documentElement).fontSize);return Number.isFinite(t)&&t>0?t:16}function le({rows:t,resolveUrl:i,from:l}){const[c,a]=W(),p=a!==null&&a<ne*re(),d=(s,n)=>e.jsx(ae,{pin:s,url:i(s.url),from:l},n);return p?e.jsx("div",{ref:c,className:"flex-1 min-h-0 overflow-y-auto grid grid-cols-1 gap-5 auto-rows-[minmax(18rem,auto)]","data-testid":"portal-grid","data-stacked":"true",children:t.flatMap((s,n)=>s.map((m,o)=>d(m,`${n}-${o}`)))}):e.jsx("div",{ref:c,className:"flex-1 min-h-0 grid gap-5",style:{gridTemplateRows:`repeat(${t.length}, minmax(0, 1fr))`},"data-testid":"portal-grid",children:t.map((s,n)=>e.jsx("div",{className:"min-h-0 grid gap-5",style:{gridTemplateColumns:`repeat(${s.length}, minmax(0, 1fr))`},"data-testid":"portal-row",children:s.map((m,o)=>d(m,`${n}-${o}`))},n))})}const oe={statusFilter:"",facets:{}},ie=15e3;function ce({count:t,url:i}){const l=f.useMemo(()=>N(i),[i]),c=T(l??oe,{limit:1,offset:0,staleTime:ie,enabled:l!==null}),a=l?c.isLoading&&c.total===0?null:c.total:null;return e.jsxs(y,{to:i,className:"block min-w-0 border border-surface-border bg-surface-sunken rounded-[var(--lt-radius-section)] px-4 py-3 hover:bg-surface-hover transition-colors",title:`Open ${t.label}`,"data-testid":"portal-count",children:[e.jsx("p",{className:"text-2xs uppercase tracking-widest text-text-tertiary truncate",children:t.label}),e.jsx("p",{className:"mt-1 text-3xl font-light leading-none text-text-primary","data-testid":"portal-count-value",children:a===null?e.jsx("span",{className:"text-text-quaternary",children:"—"}):v(a)}),t.blurb&&e.jsx("p",{className:"mt-1.5 text-xs text-text-secondary leading-snug",children:t.blurb})]})}function de({counts:t,resolveUrl:i}){return t.length===0?null:e.jsx("div",{className:"grid gap-4 shrink-0 mb-4",style:{gridTemplateColumns:"repeat(auto-fit, minmax(10rem, 1fr))"},"data-testid":"portal-counts",children:t.map((l,c)=>e.jsx(ce,{count:l,url:i(l.url)},`${l.label}-${c}`))})}function me({text:t}){return e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-center py-10 text-center",children:[e.jsx(C,{className:"w-6 h-6 text-text-quaternary/50 mb-2",strokeWidth:1}),e.jsx("p",{className:"text-xs text-text-quaternary",children:t})]})}function Se(){const{role:t="",portal:i}=D(),{data:l,isFetched:c}=_(),{resolveUrl:a}=O(),p=l==null?void 0:l.roles.find(u=>u.role===t),d=A(p),s=i?d.find(u=>u.key===i):d[0],n=(s==null?void 0:s.rows)??null,m=(s==null?void 0:s.counts)??[],o=s?k(t,s.key):k(t),r=f.useMemo(()=>Q(n?[...n.flat(),...m]:[],a),[n,m,a]),h=M("LIST");$(r.patterns,u=>{h(r.keysFor(u.type))});const b=n?n.reduce((u,x)=>u+x.length,0):0,g=c?d.length===0?"This role declares no portal yet. Compose one under Admin, Roles, Portal.":s?null:"This role has no portal by that name.":null;return e.jsxs("div",{className:"flex-1 min-h-0 flex flex-col -mt-[calc(2rem-var(--lt-space-page-x))] -mb-[calc(4rem-var(--lt-space-page-x))]",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3 shrink-0 text-2xs uppercase tracking-widest text-text-tertiary",children:[e.jsx(C,{className:"w-3 h-3 text-accent/60 shrink-0",strokeWidth:1.5}),e.jsx("h1",{className:"truncate font-semibold",title:t,children:V(p??{role:t})}),s&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"text-text-quaternary",children:"·"}),e.jsx("span",{className:"truncate","data-testid":"portal-title",children:s.label})]}),b>0&&e.jsxs("span",{className:"text-text-quaternary normal-case tracking-normal",children:[b," ",b===1?"view":"views"]})]}),c?g?e.jsx(me,{text:g}):e.jsxs(e.Fragment,{children:[e.jsx(de,{counts:m,resolveUrl:a}),e.jsx(le,{rows:n,resolveUrl:a,from:o})]}):null]})}export{Se as PortalPage};
2
+ //# sourceMappingURL=PortalPage-BkD4YfDf.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PortalPage-BKuL1BeJ.js","sources":["../../src/lib/portal-refresh.ts","../../src/components/portal/PortalPanel.tsx","../../src/components/portal/PortalGrid.tsx","../../src/components/portal/PortalCounts.tsx","../../src/pages/operator/PortalPage.tsx"],"sourcesContent":["import type { QueryKey } from '@tanstack/react-query';\nimport type { RolePin } from '../api/roles';\nimport { escalationPattern, sanitizeSubjectToken } from './events/subjects';\nimport { parseEscalationListUrl, singleRoleOf } from './escalation-list-url';\n\n/** The subject root every escalation event shares; the role token follows it. */\nconst ESCALATION_TYPE_PREFIX = 'system.escalation.';\nconst WIDE_KEYS: QueryKey[] = [['escalations']];\n\nexport interface PortalRefreshPlan {\n /** One subscription pattern per queue the portal reads; one wide pattern when a URL names no single queue. */\n patterns: string[];\n /** The query keys an event of this type should refresh: the moved queue's lists, or every list when scope is wide. */\n keysFor(eventType: string): QueryKey[];\n}\n\n/**\n * How a portal stays fresh. Every list query key carries its params object,\n * and the query client matches object segments partially, so an event on\n * one queue refreshes only that queue's panels and tiles: `['escalations',\n * { role }]` and `['escalations', 'available', { role }]`. A URL that names\n * several roles or none widens the plan to the whole escalation family.\n */\nexport function portalRefreshPlan(urls: Array<Pick<RolePin, 'url'>>, resolveUrl: (url: string) => string): PortalRefreshPlan {\n const roles = new Set<string>();\n let wide = false;\n for (const { url } of urls) {\n const params = parseEscalationListUrl(resolveUrl(url));\n if (!params) continue;\n const scoped = singleRoleOf(params);\n if (scoped) roles.add(scoped); else wide = true;\n }\n if (wide || roles.size === 0) {\n return { patterns: wide ? [escalationPattern({})] : [], keysFor: () => WIDE_KEYS };\n }\n const byToken = new Map([...roles].map((role) => [sanitizeSubjectToken(role), role]));\n const patterns = [...roles].sort().map((role) => escalationPattern({ role }));\n return {\n patterns,\n keysFor(eventType) {\n const token = eventType.startsWith(ESCALATION_TYPE_PREFIX) ? eventType.slice(ESCALATION_TYPE_PREFIX.length).split('.')[0] : '';\n const role = byToken.get(token);\n return role ? [['escalations', { role }], ['escalations', 'available', { role }]] : WIDE_KEYS;\n },\n };\n}\n","import { useMemo, useState, type CSSProperties } from 'react';\nimport { Link, useNavigate } from 'react-router-dom';\nimport { ExternalLink, LayoutList, Pin, RefreshCw, Table } from 'lucide-react';\nimport type { RolePin } from '../../api/roles';\nimport type { FacetOrder } from '../../api/escalations';\nimport type { LTEscalationRecord } from '../../api/types';\nimport { useEscalationListQuery } from '../../hooks/useEscalationListQuery';\nimport { LIST_VIEWS, parseEscalationListUrl, resolveListView, type EscalationListParams, type ListView } from '../../lib/escalation-list-url';\nimport { EscalationSortControl } from '../../pages/operator/EscalationSortControl';\nimport { formatCountCompact } from '../../lib/format';\nimport { EscalationListView } from '../escalation/EscalationListView';\nimport { EscalationTimeline } from '../escalation/EscalationTimeline';\nimport { EscalationTableView } from '../escalation/EscalationTableView';\n\n/** Rows a panel shows before pointing at the full view. */\nexport const PORTAL_PANEL_ROWS = 25;\nconst PANEL_STALE_MS = 15_000;\nconst NO_LIST: EscalationListParams = { statusFilter: '', facets: {}, view: null, layout: null };\n// Table headers stick to the panel's own scroll, not the shell's offset.\nconst PANEL_STYLE = { '--lt-sticky-top': '0px' } as CSSProperties;\n\n/**\n * One portal cell: a pinned list view rendered live. The pin's URL is parsed\n * into the same query the list page runs and drawn with the same components,\n * so the panel and the page it opens onto always agree. No filters, no\n * selection, no pagination: the label, the count, a refresh, and the rows.\n * Each panel is its own bounded sheet, the section recipe (sunken surface,\n * border, section radius), so the portal reads as distinct segments. Two\n * light controls let a person at the screen adapt a panel: the view (table or\n * the role's rich view) and the sort direction. They hold for the visit only;\n * the pin stays as authored.\n */\nexport function PortalPanel({ pin, url, from }: {\n pin: RolePin;\n /** The pin's URL with link variables already resolved. */\n url: string;\n /** Where a detail page opened from here returns to. */\n from: string;\n}) {\n const navigate = useNavigate();\n const pinParams = useMemo(() => parseEscalationListUrl(url), [url]);\n // Visit-local adaptations over the pin: a chosen view, a chosen sort direction.\n const [chosenView, setChosenView] = useState<ListView | null>(null);\n const [chosenOrder, setChosenOrder] = useState<FacetOrder[] | undefined>(undefined);\n const orderBy = chosenOrder ?? pinParams?.facets.orderBy;\n const params = useMemo<EscalationListParams | null>(() => {\n if (!pinParams) return null;\n if (orderBy === pinParams.facets.orderBy) return pinParams;\n return { ...pinParams, facets: { ...pinParams.facets, orderBy } };\n }, [pinParams, orderBy]);\n const list = useEscalationListQuery(params ?? NO_LIST, {\n limit: PORTAL_PANEL_ROWS,\n offset: 0,\n staleTime: PANEL_STALE_MS,\n enabled: params !== null,\n });\n const view = params ? resolveListView(chosenView ?? params.view, list.hasRichView) : null;\n const highlightKeys = useMemo(() => Object.keys(params?.facets.facets ?? {}), [params]);\n const openRow = (row: LTEscalationRecord) => navigate(`/escalations/detail/${row.id}`, { state: { from } });\n const more = Math.max(0, list.total - list.escalations.length);\n\n return (\n <section\n className=\"min-h-0 flex flex-col overflow-hidden border border-surface-border bg-surface-sunken rounded-[var(--lt-radius-section)]\"\n style={PANEL_STYLE}\n data-testid=\"portal-panel\"\n >\n <header className=\"flex items-center justify-between gap-2 px-4 py-2.5 shrink-0 border-b border-surface-border bg-surface-hover\">\n <div className=\"flex items-center gap-2 min-w-0\">\n <Pin className=\"w-3.5 h-3.5 shrink-0 text-accent/60\" strokeWidth={1.5} />\n <h2 className=\"section-h2 truncate\" title={pin.label}>{pin.label}</h2>\n {params && list.total > 0 && (\n <span className=\"text-2xs tabular-nums text-text-tertiary\" data-testid=\"portal-panel-count\">\n {formatCountCompact(list.total)}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-1.5 shrink-0\">\n {params && view !== LIST_VIEWS.TIMELINE && list.hasRichView && (\n <div role=\"radiogroup\" aria-label=\"Panel view\" className=\"flex items-center rounded overflow-hidden border border-surface-border\">\n {[\n { key: LIST_VIEWS.TABLE, title: 'Table view', Icon: Table },\n { key: LIST_VIEWS.RICH, title: 'Rich view', Icon: LayoutList },\n ].map(({ key, title, Icon }) => (\n <button\n key={key}\n type=\"button\"\n role=\"radio\"\n aria-checked={view === key}\n onClick={() => setChosenView(key)}\n className={`px-1.5 py-1 transition-colors ${view === key ? 'bg-accent text-text-inverse' : 'icon-link hover:bg-surface-raised'}`}\n title={title}\n >\n <Icon className=\"w-3.5 h-3.5\" />\n </button>\n ))}\n </div>\n )}\n {params && <EscalationSortControl orderBy={orderBy} onChange={setChosenOrder} />}\n {params && (\n <button\n type=\"button\"\n onClick={list.refetch}\n disabled={list.isFetching}\n className=\"inline-flex h-7 w-7 items-center justify-center rounded icon-link hover:bg-surface-hover disabled:opacity-50\"\n title=\"Refresh\"\n >\n <RefreshCw className={`w-3.5 h-3.5 ${list.isFetching ? 'animate-spin' : ''}`} />\n </button>\n )}\n <Link\n to={url}\n className=\"inline-flex h-7 w-7 items-center justify-center rounded icon-link hover:bg-surface-hover\"\n title=\"Open the full view\"\n data-testid=\"portal-panel-open\"\n >\n <ExternalLink className=\"w-3.5 h-3.5\" />\n </Link>\n </div>\n </header>\n\n <div className=\"flex-1 min-h-0 overflow-y-auto @container px-4 py-3\">\n {!params ? (\n <p className=\"py-6 text-center text-xs text-text-quaternary\">\n <Link to={url} className=\"text-accent hover:underline\">{pin.label}</Link> opens as its own page.\n </p>\n ) : list.error ? (\n <p className=\"py-6 text-center text-xs text-status-error\" role=\"alert\">\n Failed to load: {list.error.message}\n </p>\n ) : view === LIST_VIEWS.TIMELINE ? (\n <EscalationTimeline\n escalations={list.escalations}\n highlightKeys={highlightKeys}\n onRowClick={openRow}\n total={list.total}\n page={1}\n totalPages={1}\n onPageChange={() => {}}\n />\n ) : view === LIST_VIEWS.RICH ? (\n <EscalationListView\n role={list.singleRole!}\n listSchema={list.listSchema!}\n activeEscalations={list.escalations}\n onRowClick={openRow}\n onOpenGroup={(target) => navigate(target)}\n />\n ) : (\n <EscalationTableView\n escalations={list.escalations}\n highlightKeys={highlightKeys}\n onRowClick={openRow}\n isLoading={list.isLoading}\n layout={params.layout}\n />\n )}\n {more > 0 && (\n <Link to={url} className=\"block pt-3 pb-1 text-2xs text-accent hover:underline\" data-testid=\"portal-panel-more\">\n {formatCountCompact(more)} more in the full view\n </Link>\n )}\n </div>\n </section>\n );\n}\n","import type { RolePin } from '../../api/roles';\nimport { useContainerWidth } from '../../hooks/useContainerWidth';\nimport { PortalPanel } from './PortalPanel';\n\n/** Below this container width (the `split` threshold) every cell stacks into one column. */\nexport const PORTAL_STACK_REM = 54;\n\nfunction rootFontPx(): number {\n if (typeof document === 'undefined') return 16;\n const size = parseFloat(getComputedStyle(document.documentElement).fontSize);\n return Number.isFinite(size) && size > 0 ? size : 16;\n}\n\n/**\n * The portal matrix as a page: one grid row per declared row, each dividing\n * its width evenly among its cells, every cell a live panel with its own\n * scroll. A narrow box stacks the cells in declaration order instead.\n */\nexport function PortalGrid({ rows, resolveUrl, from }: {\n rows: RolePin[][];\n /** Link-variable substitution for a pin URL, applied at render time. */\n resolveUrl: (url: string) => string;\n from: string;\n}) {\n const [ref, width] = useContainerWidth<HTMLDivElement>();\n const stacked = width !== null && width < PORTAL_STACK_REM * rootFontPx();\n const cell = (pin: RolePin, key: string) => <PortalPanel key={key} pin={pin} url={resolveUrl(pin.url)} from={from} />;\n\n if (stacked) {\n return (\n <div ref={ref} className=\"flex-1 min-h-0 overflow-y-auto grid grid-cols-1 gap-5 auto-rows-[minmax(18rem,auto)]\" data-testid=\"portal-grid\" data-stacked=\"true\">\n {rows.flatMap((row, r) => row.map((pin, c) => cell(pin, `${r}-${c}`)))}\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n className=\"flex-1 min-h-0 grid gap-5\"\n style={{ gridTemplateRows: `repeat(${rows.length}, minmax(0, 1fr))` }}\n data-testid=\"portal-grid\"\n >\n {rows.map((row, r) => (\n <div\n key={r}\n className=\"min-h-0 grid gap-5\"\n style={{ gridTemplateColumns: `repeat(${row.length}, minmax(0, 1fr))` }}\n data-testid=\"portal-row\"\n >\n {row.map((pin, c) => cell(pin, `${r}-${c}`))}\n </div>\n ))}\n </div>\n );\n}\n","import { useMemo } from 'react';\nimport { Link } from 'react-router-dom';\nimport type { PortalCount } from '../../api/roles';\nimport { useEscalationListQuery } from '../../hooks/useEscalationListQuery';\nimport { parseEscalationListUrl, type EscalationListParams } from '../../lib/escalation-list-url';\nimport { formatCountCompact } from '../../lib/format';\n\nconst NO_LIST: EscalationListParams = { statusFilter: '', facets: {}, view: null, layout: null };\nconst TILE_STALE_MS = 15_000;\n\n/**\n * One count tile: the live total of a list URL, the same number a pin badge\n * carries (limit 1, read total), under a label and over a blurb. The tile\n * links to the list it counts.\n */\nexport function PortalCountTile({ count, url }: { count: PortalCount; url: string }) {\n const params = useMemo(() => parseEscalationListUrl(url), [url]);\n const list = useEscalationListQuery(params ?? NO_LIST, { limit: 1, offset: 0, staleTime: TILE_STALE_MS, enabled: params !== null });\n const value = !params ? null : list.isLoading && list.total === 0 ? null : list.total;\n return (\n <Link\n to={url}\n className=\"block min-w-0 border border-surface-border bg-surface-sunken rounded-[var(--lt-radius-section)] px-4 py-3 hover:bg-surface-hover transition-colors\"\n title={`Open ${count.label}`}\n data-testid=\"portal-count\"\n >\n <p className=\"text-2xs uppercase tracking-widest text-text-tertiary truncate\">{count.label}</p>\n <p className=\"mt-1 text-3xl font-light leading-none text-text-primary\" data-testid=\"portal-count-value\">\n {value === null ? <span className=\"text-text-quaternary\">—</span> : formatCountCompact(value)}\n </p>\n {count.blurb && <p className=\"mt-1.5 text-xs text-text-secondary leading-snug\">{count.blurb}</p>}\n </Link>\n );\n}\n\n/** The row of count tiles above a portal's panels; every tile shares one grid so numbers align. */\nexport function PortalCounts({ counts, resolveUrl }: { counts: PortalCount[]; resolveUrl: (url: string) => string }) {\n if (counts.length === 0) return null;\n return (\n <div\n className=\"grid gap-4 shrink-0 mb-4\"\n style={{ gridTemplateColumns: `repeat(auto-fit, minmax(10rem, 1fr))` }}\n data-testid=\"portal-counts\"\n >\n {counts.map((count, i) => <PortalCountTile key={`${count.label}-${i}`} count={count} url={resolveUrl(count.url)} />)}\n </div>\n );\n}\n","import { useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { LayoutGrid } from 'lucide-react';\nimport { useRoleDetails } from '../../api/roles';\nimport { useLinkVariables } from '../../hooks/useLinkVariables';\nimport { useEventSubscriptions } from '../../hooks/useEventContext';\nimport { useThrottledInvalidation } from '../../hooks/useEventHooks';\nimport { portalPath, portalsOf } from '../../lib/portal-path';\nimport { portalRefreshPlan } from '../../lib/portal-refresh';\nimport { displayRoleTitle } from '../../lib/role-display';\nimport { PortalGrid } from '../../components/portal/PortalGrid';\nimport { PortalCounts } from '../../components/portal/PortalCounts';\n\nfunction EmptyPortal({ text }: { text: string }) {\n return (\n <div className=\"flex-1 flex flex-col items-center justify-center py-10 text-center\">\n <LayoutGrid className=\"w-6 h-6 text-text-quaternary/50 mb-2\" strokeWidth={1} />\n <p className=\"text-xs text-text-quaternary\">{text}</p>\n </div>\n );\n}\n\n/**\n * One of a role's portals: a named matrix of pinned views rendered as one\n * page of live panels. Any signed-in user may open it; every panel reads\n * through the same role-scoped list endpoints as the list page, so each\n * viewer sees what their read scope returns. With no portal key the role's\n * first portal shows. One subscription per queue the cells and tiles name\n * keeps them current, each event refreshing only the queue that moved.\n */\nexport function PortalPage() {\n const { role = '', portal: portalKey } = useParams<{ role: string; portal?: string }>();\n const { data: roleData, isFetched } = useRoleDetails();\n const { resolveUrl } = useLinkVariables();\n\n const detail = roleData?.roles.find((r) => r.role === role);\n const portals = portalsOf(detail);\n const portal = portalKey ? portals.find((p) => p.key === portalKey) : portals[0];\n const rows = portal?.rows ?? null;\n const counts = portal?.counts ?? [];\n const from = portal ? portalPath(role, portal.key) : portalPath(role);\n\n // One subscription per queue the cells and tiles name; an event refreshes\n // only that queue's panels and tiles, through the LIST-tier scheduler.\n const plan = useMemo(() => portalRefreshPlan(rows ? [...rows.flat(), ...counts] : [], resolveUrl), [rows, counts, resolveUrl]);\n const invalidate = useThrottledInvalidation('LIST');\n useEventSubscriptions(plan.patterns, (event) => { invalidate(plan.keysFor(event.type)); });\n\n const cellCount = rows ? rows.reduce((n, r) => n + r.length, 0) : 0;\n const empty = !isFetched ? null\n : portals.length === 0 ? 'This role declares no portal yet. Compose one under Admin, Roles, Portal.'\n : !portal ? 'This role has no portal by that name.'\n : null;\n\n // The panels are the page. The shell pads the content box py-8 pb-16; the\n // portal pulls those back to the side gutter so the frame reads evenly on\n // a screen, and the heading demotes to a quiet caption above the grid.\n return (\n <div className=\"flex-1 min-h-0 flex flex-col -mt-[calc(2rem-var(--lt-space-page-x))] -mb-[calc(4rem-var(--lt-space-page-x))]\">\n <div className=\"flex items-center gap-2 mb-3 shrink-0 text-2xs uppercase tracking-widest text-text-tertiary\">\n <LayoutGrid className=\"w-3 h-3 text-accent/60 shrink-0\" strokeWidth={1.5} />\n <h1 className=\"truncate font-semibold\" title={role}>{displayRoleTitle(detail ?? { role })}</h1>\n {portal && (\n <>\n <span className=\"text-text-quaternary\">·</span>\n <span className=\"truncate\" data-testid=\"portal-title\">{portal.label}</span>\n </>\n )}\n {cellCount > 0 && (\n <span className=\"text-text-quaternary normal-case tracking-normal\">\n {cellCount} {cellCount === 1 ? 'view' : 'views'}\n </span>\n )}\n </div>\n {!isFetched ? null\n : empty ? <EmptyPortal text={empty} />\n : (\n <>\n <PortalCounts counts={counts} resolveUrl={resolveUrl} />\n <PortalGrid rows={rows!} resolveUrl={resolveUrl} from={from} />\n </>\n )}\n </div>\n );\n}\n"],"names":["ESCALATION_TYPE_PREFIX","WIDE_KEYS","portalRefreshPlan","urls","resolveUrl","roles","wide","url","params","parseEscalationListUrl","scoped","singleRoleOf","escalationPattern","byToken","role","sanitizeSubjectToken","eventType","token","PORTAL_PANEL_ROWS","PANEL_STALE_MS","NO_LIST","PANEL_STYLE","PortalPanel","pin","from","navigate","useNavigate","pinParams","useMemo","chosenView","setChosenView","useState","chosenOrder","setChosenOrder","orderBy","list","useEscalationListQuery","view","resolveListView","highlightKeys","openRow","row","more","jsxs","jsx","Pin","formatCountCompact","LIST_VIEWS","Table","LayoutList","key","title","Icon","EscalationSortControl","RefreshCw","Link","ExternalLink","EscalationTimeline","EscalationListView","target","EscalationTableView","PORTAL_STACK_REM","rootFontPx","size","PortalGrid","rows","ref","width","useContainerWidth","stacked","cell","r","c","TILE_STALE_MS","PortalCountTile","count","value","PortalCounts","counts","i","EmptyPortal","text","LayoutGrid","PortalPage","portalKey","useParams","roleData","isFetched","useRoleDetails","useLinkVariables","detail","portals","portalsOf","portal","p","portalPath","plan","invalidate","useThrottledInvalidation","useEventSubscriptions","event","cellCount","n","empty","displayRoleTitle","Fragment"],"mappings":"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"}
1
+ {"version":3,"file":"PortalPage-BkD4YfDf.js","sources":["../../src/lib/portal-refresh.ts","../../src/components/portal/PortalPanel.tsx","../../src/components/portal/PortalGrid.tsx","../../src/components/portal/PortalCounts.tsx","../../src/pages/operator/PortalPage.tsx"],"sourcesContent":["import type { QueryKey } from '@tanstack/react-query';\nimport type { RolePin } from '../api/roles';\nimport { escalationPattern, sanitizeSubjectToken } from './events/subjects';\nimport { parseEscalationListUrl, singleRoleOf } from './escalation-list-url';\n\n/** The subject root every escalation event shares; the role token follows it. */\nconst ESCALATION_TYPE_PREFIX = 'system.escalation.';\nconst WIDE_KEYS: QueryKey[] = [['escalations']];\n\nexport interface PortalRefreshPlan {\n /** One subscription pattern per queue the portal reads; one wide pattern when a URL names no single queue. */\n patterns: string[];\n /** The query keys an event of this type should refresh: the moved queue's lists, or every list when scope is wide. */\n keysFor(eventType: string): QueryKey[];\n}\n\n/**\n * How a portal stays fresh. Every list query key carries its params object,\n * and the query client matches object segments partially, so an event on\n * one queue refreshes only that queue's panels and tiles: `['escalations',\n * { role }]` and `['escalations', 'available', { role }]`. A URL that names\n * several roles or none widens the plan to the whole escalation family.\n */\nexport function portalRefreshPlan(urls: Array<Pick<RolePin, 'url'>>, resolveUrl: (url: string) => string): PortalRefreshPlan {\n const roles = new Set<string>();\n let wide = false;\n for (const { url } of urls) {\n const params = parseEscalationListUrl(resolveUrl(url));\n if (!params) continue;\n const scoped = singleRoleOf(params);\n if (scoped) roles.add(scoped); else wide = true;\n }\n if (wide || roles.size === 0) {\n return { patterns: wide ? [escalationPattern({})] : [], keysFor: () => WIDE_KEYS };\n }\n const byToken = new Map([...roles].map((role) => [sanitizeSubjectToken(role), role]));\n const patterns = [...roles].sort().map((role) => escalationPattern({ role }));\n return {\n patterns,\n keysFor(eventType) {\n const token = eventType.startsWith(ESCALATION_TYPE_PREFIX) ? eventType.slice(ESCALATION_TYPE_PREFIX.length).split('.')[0] : '';\n const role = byToken.get(token);\n return role ? [['escalations', { role }], ['escalations', 'available', { role }]] : WIDE_KEYS;\n },\n };\n}\n","import { useMemo, useState, type CSSProperties } from 'react';\nimport { Link, useNavigate } from 'react-router-dom';\nimport { ExternalLink, LayoutList, Pin, RefreshCw, Table } from 'lucide-react';\nimport type { RolePin } from '../../api/roles';\nimport type { FacetOrder } from '../../api/escalations';\nimport type { LTEscalationRecord } from '../../api/types';\nimport { useEscalationListQuery } from '../../hooks/useEscalationListQuery';\nimport { LIST_VIEWS, parseEscalationListUrl, resolveListView, type EscalationListParams, type ListView } from '../../lib/escalation-list-url';\nimport { EscalationSortControl } from '../../pages/operator/EscalationSortControl';\nimport { formatCountCompact } from '../../lib/format';\nimport { EscalationListView } from '../escalation/EscalationListView';\nimport { EscalationTimeline } from '../escalation/EscalationTimeline';\nimport { EscalationTableView } from '../escalation/EscalationTableView';\n\n/** Rows a panel shows before pointing at the full view. */\nexport const PORTAL_PANEL_ROWS = 25;\nconst PANEL_STALE_MS = 15_000;\nconst NO_LIST: EscalationListParams = { statusFilter: '', facets: {}, view: null, layout: null };\n// Table headers stick to the panel's own scroll, not the shell's offset.\nconst PANEL_STYLE = { '--lt-sticky-top': '0px' } as CSSProperties;\n\n/**\n * One portal cell: a pinned list view rendered live. The pin's URL is parsed\n * into the same query the list page runs and drawn with the same components,\n * so the panel and the page it opens onto always agree. No filters, no\n * selection, no pagination: the label, the count, a refresh, and the rows.\n * Each panel is its own bounded sheet, the section recipe (sunken surface,\n * border, section radius), so the portal reads as distinct segments. Two\n * light controls let a person at the screen adapt a panel: the view (table or\n * the role's rich view) and the sort direction. They hold for the visit only;\n * the pin stays as authored.\n */\nexport function PortalPanel({ pin, url, from }: {\n pin: RolePin;\n /** The pin's URL with link variables already resolved. */\n url: string;\n /** Where a detail page opened from here returns to. */\n from: string;\n}) {\n const navigate = useNavigate();\n const pinParams = useMemo(() => parseEscalationListUrl(url), [url]);\n // Visit-local adaptations over the pin: a chosen view, a chosen sort direction.\n const [chosenView, setChosenView] = useState<ListView | null>(null);\n const [chosenOrder, setChosenOrder] = useState<FacetOrder[] | undefined>(undefined);\n const orderBy = chosenOrder ?? pinParams?.facets.orderBy;\n const params = useMemo<EscalationListParams | null>(() => {\n if (!pinParams) return null;\n if (orderBy === pinParams.facets.orderBy) return pinParams;\n return { ...pinParams, facets: { ...pinParams.facets, orderBy } };\n }, [pinParams, orderBy]);\n const list = useEscalationListQuery(params ?? NO_LIST, {\n limit: PORTAL_PANEL_ROWS,\n offset: 0,\n staleTime: PANEL_STALE_MS,\n enabled: params !== null,\n });\n const view = params ? resolveListView(chosenView ?? params.view, list.hasRichView) : null;\n const highlightKeys = useMemo(() => Object.keys(params?.facets.facets ?? {}), [params]);\n const openRow = (row: LTEscalationRecord) => navigate(`/escalations/detail/${row.id}`, { state: { from } });\n const more = Math.max(0, list.total - list.escalations.length);\n\n return (\n <section\n className=\"min-h-0 flex flex-col overflow-hidden border border-surface-border bg-surface-sunken rounded-[var(--lt-radius-section)]\"\n style={PANEL_STYLE}\n data-testid=\"portal-panel\"\n >\n <header className=\"flex items-center justify-between gap-2 px-4 py-2.5 shrink-0 border-b border-surface-border bg-surface-hover\">\n <div className=\"flex items-center gap-2 min-w-0\">\n <Pin className=\"w-3.5 h-3.5 shrink-0 text-accent/60\" strokeWidth={1.5} />\n <h2 className=\"section-h2 truncate\" title={pin.label}>{pin.label}</h2>\n {params && list.total > 0 && (\n <span className=\"text-2xs tabular-nums text-text-tertiary\" data-testid=\"portal-panel-count\">\n {formatCountCompact(list.total)}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-1.5 shrink-0\">\n {params && view !== LIST_VIEWS.TIMELINE && list.hasRichView && (\n <div role=\"radiogroup\" aria-label=\"Panel view\" className=\"flex items-center rounded overflow-hidden border border-surface-border\">\n {[\n { key: LIST_VIEWS.TABLE, title: 'Table view', Icon: Table },\n { key: LIST_VIEWS.RICH, title: 'Rich view', Icon: LayoutList },\n ].map(({ key, title, Icon }) => (\n <button\n key={key}\n type=\"button\"\n role=\"radio\"\n aria-checked={view === key}\n onClick={() => setChosenView(key)}\n className={`px-1.5 py-1 transition-colors ${view === key ? 'bg-accent text-text-inverse' : 'icon-link hover:bg-surface-raised'}`}\n title={title}\n >\n <Icon className=\"w-3.5 h-3.5\" />\n </button>\n ))}\n </div>\n )}\n {params && <EscalationSortControl orderBy={orderBy} onChange={setChosenOrder} />}\n {params && (\n <button\n type=\"button\"\n onClick={list.refetch}\n disabled={list.isFetching}\n className=\"inline-flex h-7 w-7 items-center justify-center rounded icon-link hover:bg-surface-hover disabled:opacity-50\"\n title=\"Refresh\"\n >\n <RefreshCw className={`w-3.5 h-3.5 ${list.isFetching ? 'animate-spin' : ''}`} />\n </button>\n )}\n <Link\n to={url}\n className=\"inline-flex h-7 w-7 items-center justify-center rounded icon-link hover:bg-surface-hover\"\n title=\"Open the full view\"\n data-testid=\"portal-panel-open\"\n >\n <ExternalLink className=\"w-3.5 h-3.5\" />\n </Link>\n </div>\n </header>\n\n <div className=\"flex-1 min-h-0 overflow-y-auto @container px-4 py-3\">\n {!params ? (\n <p className=\"py-6 text-center text-xs text-text-quaternary\">\n <Link to={url} className=\"text-accent hover:underline\">{pin.label}</Link> opens as its own page.\n </p>\n ) : list.error ? (\n <p className=\"py-6 text-center text-xs text-status-error\" role=\"alert\">\n Failed to load: {list.error.message}\n </p>\n ) : view === LIST_VIEWS.TIMELINE ? (\n <EscalationTimeline\n escalations={list.escalations}\n highlightKeys={highlightKeys}\n onRowClick={openRow}\n total={list.total}\n page={1}\n totalPages={1}\n onPageChange={() => {}}\n />\n ) : view === LIST_VIEWS.RICH ? (\n <EscalationListView\n role={list.singleRole!}\n listSchema={list.listSchema!}\n activeEscalations={list.escalations}\n onRowClick={openRow}\n onOpenGroup={(target) => navigate(target)}\n />\n ) : (\n <EscalationTableView\n escalations={list.escalations}\n highlightKeys={highlightKeys}\n onRowClick={openRow}\n isLoading={list.isLoading}\n layout={params.layout}\n />\n )}\n {more > 0 && (\n <Link to={url} className=\"block pt-3 pb-1 text-2xs text-accent hover:underline\" data-testid=\"portal-panel-more\">\n {formatCountCompact(more)} more in the full view\n </Link>\n )}\n </div>\n </section>\n );\n}\n","import type { RolePin } from '../../api/roles';\nimport { useContainerWidth } from '../../hooks/useContainerWidth';\nimport { PortalPanel } from './PortalPanel';\n\n/** Below this container width (the `split` threshold) every cell stacks into one column. */\nexport const PORTAL_STACK_REM = 54;\n\nfunction rootFontPx(): number {\n if (typeof document === 'undefined') return 16;\n const size = parseFloat(getComputedStyle(document.documentElement).fontSize);\n return Number.isFinite(size) && size > 0 ? size : 16;\n}\n\n/**\n * The portal matrix as a page: one grid row per declared row, each dividing\n * its width evenly among its cells, every cell a live panel with its own\n * scroll. A narrow box stacks the cells in declaration order instead.\n */\nexport function PortalGrid({ rows, resolveUrl, from }: {\n rows: RolePin[][];\n /** Link-variable substitution for a pin URL, applied at render time. */\n resolveUrl: (url: string) => string;\n from: string;\n}) {\n const [ref, width] = useContainerWidth<HTMLDivElement>();\n const stacked = width !== null && width < PORTAL_STACK_REM * rootFontPx();\n const cell = (pin: RolePin, key: string) => <PortalPanel key={key} pin={pin} url={resolveUrl(pin.url)} from={from} />;\n\n if (stacked) {\n return (\n <div ref={ref} className=\"flex-1 min-h-0 overflow-y-auto grid grid-cols-1 gap-5 auto-rows-[minmax(18rem,auto)]\" data-testid=\"portal-grid\" data-stacked=\"true\">\n {rows.flatMap((row, r) => row.map((pin, c) => cell(pin, `${r}-${c}`)))}\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n className=\"flex-1 min-h-0 grid gap-5\"\n style={{ gridTemplateRows: `repeat(${rows.length}, minmax(0, 1fr))` }}\n data-testid=\"portal-grid\"\n >\n {rows.map((row, r) => (\n <div\n key={r}\n className=\"min-h-0 grid gap-5\"\n style={{ gridTemplateColumns: `repeat(${row.length}, minmax(0, 1fr))` }}\n data-testid=\"portal-row\"\n >\n {row.map((pin, c) => cell(pin, `${r}-${c}`))}\n </div>\n ))}\n </div>\n );\n}\n","import { useMemo } from 'react';\nimport { Link } from 'react-router-dom';\nimport type { PortalCount } from '../../api/roles';\nimport { useEscalationListQuery } from '../../hooks/useEscalationListQuery';\nimport { parseEscalationListUrl, type EscalationListParams } from '../../lib/escalation-list-url';\nimport { formatCountCompact } from '../../lib/format';\n\nconst NO_LIST: EscalationListParams = { statusFilter: '', facets: {}, view: null, layout: null };\nconst TILE_STALE_MS = 15_000;\n\n/**\n * One count tile: the live total of a list URL, the same number a pin badge\n * carries (limit 1, read total), under a label and over a blurb. The tile\n * links to the list it counts.\n */\nexport function PortalCountTile({ count, url }: { count: PortalCount; url: string }) {\n const params = useMemo(() => parseEscalationListUrl(url), [url]);\n const list = useEscalationListQuery(params ?? NO_LIST, { limit: 1, offset: 0, staleTime: TILE_STALE_MS, enabled: params !== null });\n const value = !params ? null : list.isLoading && list.total === 0 ? null : list.total;\n return (\n <Link\n to={url}\n className=\"block min-w-0 border border-surface-border bg-surface-sunken rounded-[var(--lt-radius-section)] px-4 py-3 hover:bg-surface-hover transition-colors\"\n title={`Open ${count.label}`}\n data-testid=\"portal-count\"\n >\n <p className=\"text-2xs uppercase tracking-widest text-text-tertiary truncate\">{count.label}</p>\n <p className=\"mt-1 text-3xl font-light leading-none text-text-primary\" data-testid=\"portal-count-value\">\n {value === null ? <span className=\"text-text-quaternary\">—</span> : formatCountCompact(value)}\n </p>\n {count.blurb && <p className=\"mt-1.5 text-xs text-text-secondary leading-snug\">{count.blurb}</p>}\n </Link>\n );\n}\n\n/** The row of count tiles above a portal's panels; every tile shares one grid so numbers align. */\nexport function PortalCounts({ counts, resolveUrl }: { counts: PortalCount[]; resolveUrl: (url: string) => string }) {\n if (counts.length === 0) return null;\n return (\n <div\n className=\"grid gap-4 shrink-0 mb-4\"\n style={{ gridTemplateColumns: `repeat(auto-fit, minmax(10rem, 1fr))` }}\n data-testid=\"portal-counts\"\n >\n {counts.map((count, i) => <PortalCountTile key={`${count.label}-${i}`} count={count} url={resolveUrl(count.url)} />)}\n </div>\n );\n}\n","import { useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { LayoutGrid } from 'lucide-react';\nimport { useRoleDetails } from '../../api/roles';\nimport { useLinkVariables } from '../../hooks/useLinkVariables';\nimport { useEventSubscriptions } from '../../hooks/useEventContext';\nimport { useThrottledInvalidation } from '../../hooks/useEventHooks';\nimport { portalPath, portalsOf } from '../../lib/portal-path';\nimport { portalRefreshPlan } from '../../lib/portal-refresh';\nimport { displayRoleTitle } from '../../lib/role-display';\nimport { PortalGrid } from '../../components/portal/PortalGrid';\nimport { PortalCounts } from '../../components/portal/PortalCounts';\n\nfunction EmptyPortal({ text }: { text: string }) {\n return (\n <div className=\"flex-1 flex flex-col items-center justify-center py-10 text-center\">\n <LayoutGrid className=\"w-6 h-6 text-text-quaternary/50 mb-2\" strokeWidth={1} />\n <p className=\"text-xs text-text-quaternary\">{text}</p>\n </div>\n );\n}\n\n/**\n * One of a role's portals: a named matrix of pinned views rendered as one\n * page of live panels. Any signed-in user may open it; every panel reads\n * through the same role-scoped list endpoints as the list page, so each\n * viewer sees what their read scope returns. With no portal key the role's\n * first portal shows. One subscription per queue the cells and tiles name\n * keeps them current, each event refreshing only the queue that moved.\n */\nexport function PortalPage() {\n const { role = '', portal: portalKey } = useParams<{ role: string; portal?: string }>();\n const { data: roleData, isFetched } = useRoleDetails();\n const { resolveUrl } = useLinkVariables();\n\n const detail = roleData?.roles.find((r) => r.role === role);\n const portals = portalsOf(detail);\n const portal = portalKey ? portals.find((p) => p.key === portalKey) : portals[0];\n const rows = portal?.rows ?? null;\n const counts = portal?.counts ?? [];\n const from = portal ? portalPath(role, portal.key) : portalPath(role);\n\n // One subscription per queue the cells and tiles name; an event refreshes\n // only that queue's panels and tiles, through the LIST-tier scheduler.\n const plan = useMemo(() => portalRefreshPlan(rows ? [...rows.flat(), ...counts] : [], resolveUrl), [rows, counts, resolveUrl]);\n const invalidate = useThrottledInvalidation('LIST');\n useEventSubscriptions(plan.patterns, (event) => { invalidate(plan.keysFor(event.type)); });\n\n const cellCount = rows ? rows.reduce((n, r) => n + r.length, 0) : 0;\n const empty = !isFetched ? null\n : portals.length === 0 ? 'This role declares no portal yet. Compose one under Admin, Roles, Portal.'\n : !portal ? 'This role has no portal by that name.'\n : null;\n\n // The panels are the page. The shell pads the content box py-8 pb-16; the\n // portal pulls those back to the side gutter so the frame reads evenly on\n // a screen, and the heading demotes to a quiet caption above the grid.\n return (\n <div className=\"flex-1 min-h-0 flex flex-col -mt-[calc(2rem-var(--lt-space-page-x))] -mb-[calc(4rem-var(--lt-space-page-x))]\">\n <div className=\"flex items-center gap-2 mb-3 shrink-0 text-2xs uppercase tracking-widest text-text-tertiary\">\n <LayoutGrid className=\"w-3 h-3 text-accent/60 shrink-0\" strokeWidth={1.5} />\n <h1 className=\"truncate font-semibold\" title={role}>{displayRoleTitle(detail ?? { role })}</h1>\n {portal && (\n <>\n <span className=\"text-text-quaternary\">·</span>\n <span className=\"truncate\" data-testid=\"portal-title\">{portal.label}</span>\n </>\n )}\n {cellCount > 0 && (\n <span className=\"text-text-quaternary normal-case tracking-normal\">\n {cellCount} {cellCount === 1 ? 'view' : 'views'}\n </span>\n )}\n </div>\n {!isFetched ? null\n : empty ? <EmptyPortal text={empty} />\n : (\n <>\n <PortalCounts counts={counts} resolveUrl={resolveUrl} />\n <PortalGrid rows={rows!} resolveUrl={resolveUrl} from={from} />\n </>\n )}\n </div>\n );\n}\n"],"names":["ESCALATION_TYPE_PREFIX","WIDE_KEYS","portalRefreshPlan","urls","resolveUrl","roles","wide","url","params","parseEscalationListUrl","scoped","singleRoleOf","escalationPattern","byToken","role","sanitizeSubjectToken","eventType","token","PORTAL_PANEL_ROWS","PANEL_STALE_MS","NO_LIST","PANEL_STYLE","PortalPanel","pin","from","navigate","useNavigate","pinParams","useMemo","chosenView","setChosenView","useState","chosenOrder","setChosenOrder","orderBy","list","useEscalationListQuery","view","resolveListView","highlightKeys","openRow","row","more","jsxs","jsx","Pin","formatCountCompact","LIST_VIEWS","Table","LayoutList","key","title","Icon","EscalationSortControl","RefreshCw","Link","ExternalLink","EscalationTimeline","EscalationListView","target","EscalationTableView","PORTAL_STACK_REM","rootFontPx","size","PortalGrid","rows","ref","width","useContainerWidth","stacked","cell","r","c","TILE_STALE_MS","PortalCountTile","count","value","PortalCounts","counts","i","EmptyPortal","text","LayoutGrid","PortalPage","portalKey","useParams","roleData","isFetched","useRoleDetails","useLinkVariables","detail","portals","portalsOf","portal","p","portalPath","plan","invalidate","useThrottledInvalidation","useEventSubscriptions","event","cellCount","n","empty","displayRoleTitle","Fragment"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{a as b,j as e}from"./vendor-query-DvWWuNIB.js";import{a as z}from"./tasks-B-Uay8uL.js";import{D as S,f as L,C as V,b as J,c as q,d as G,J as P,S as T}from"./index-3gbd5neL.js";import{P as K}from"./PageHeaderWithStats-CSnk1p5A.js";import{S as W}from"./StatusBadge-DHVwxre2.js";import{W as Q}from"./WorkflowPill-ZepbO_ny.js";import{T as y}from"./TimestampCell-Du1nBrPn.js";import{L as D,e as X}from"./vendor-react-_9U4mKFr.js";import{R as Y}from"./RolePill-BafrASDX.js";import{U as Z}from"./UserName-kBh1dc39.js";import"./vendor-icons-B7OcUM6b.js";const ee="bg-stripes animate-pulse opacity-70";function $(t){switch(t){case"completed":return"text-status-success";case"in_progress":case"pending":return"text-status-warning";case"needs_intervention":return"text-status-error";case"cancelled":return"text-text-tertiary";default:return"text-text-tertiary"}}function I(t){switch(t){case"resolved":return"text-status-success";case"pending":return"text-status-warning";case"cancelled":return"text-text-tertiary";default:return"text-text-tertiary"}}function te(t,a,l){return`${t==="task"?"Task":l?"Notification":"Escalation"} is ${a.replace(/_/g," ")}`}function se(t,a){if(a)return ee;switch(t){case"completed":case"resolved":return"bg-status-success";case"pending":case"in_progress":case"needs_intervention":return"bg-status-warning";case"cancelled":return"bg-status-error";default:return"bg-text-tertiary"}}function ae(t){return t.startsWith("mcp")||t.startsWith("Mcp")}function E(t){return!t.workflow_type}function A(t,a){if(t.length<=a)return t;const l=Math.floor((a-1)/2);return`${t.slice(0,l)}…${t.slice(t.length-l)}`}function ne(t,a){const l=Date.now(),c=new Map,x=[];for(const s of a)s.task_id?(c.has(s.task_id)||c.set(s.task_id,[]),c.get(s.task_id).push(s)):x.push(s);const r=[...t].sort((s,d)=>new Date(s.created_at).getTime()-new Date(d.created_at).getTime()),i=[];for(const s of t)i.push(new Date(s.created_at).getTime()),s.completed_at&&i.push(new Date(s.completed_at).getTime());for(const s of a)i.push(new Date(s.created_at).getTime()),s.resolved_at&&i.push(new Date(s.resolved_at).getTime()),s.claimed_at&&i.push(new Date(s.claimed_at).getTime());if(i.length===0)return{lanes:[],timeMin:0,timeMax:1};const o=Math.min(...i),f=t.some(s=>!s.completed_at)||a.some(s=>!s.resolved_at)?Math.max(l,Math.max(...i)):Math.max(...i),p=f-o||1,m=s=>(s-o)/p*100,h=[];for(const s of r){const d=new Date(s.created_at).getTime(),j=s.completed_at?new Date(s.completed_at).getTime():l,g=!s.completed_at;h.push({kind:"task",id:s.id,label:s.workflow_type,taskId:s.id,startMs:d,endMs:j,startPct:m(d),widthPct:Math.max((j-d)/p*100,.5),durationMs:j-d,isOpen:g,task:s});const v=(c.get(s.id)||[]).sort((n,u)=>new Date(n.created_at).getTime()-new Date(u.created_at).getTime());for(const n of v){const u=new Date(n.created_at).getTime(),N=n.resolved_at?new Date(n.resolved_at).getTime():l,M=!n.resolved_at;let w=null;if(n.claimed_at){const U=new Date(n.claimed_at).getTime(),H=N-u||1;w=(U-u)/H*100}h.push({kind:"escalation",id:n.id,label:n.role,taskId:s.id,startMs:u,endMs:N,startPct:m(u),widthPct:Math.max((N-u)/p*100,.5),durationMs:N-u,isOpen:M,escalation:n,claimPct:w})}}for(const s of x){const d=new Date(s.created_at).getTime(),j=s.resolved_at?new Date(s.resolved_at).getTime():l;let g=null;if(s.claimed_at){const v=new Date(s.claimed_at).getTime(),n=j-d||1;g=(v-d)/n*100}h.push({kind:"escalation",id:s.id,label:s.role,taskId:"",startMs:d,endMs:j,startPct:m(d),widthPct:Math.max((j-d)/p*100,.5),durationMs:j-d,isOpen:!s.resolved_at,escalation:s,claimPct:g})}return{lanes:h,timeMin:o,timeMax:f}}function re(t,a,l,c=500){const[x,r]=b.useState(0),i=b.useRef(null),o=l-a||1;b.useEffect(()=>{if(t===0)return;i.current=null,r(0);let f;const p=m=>{i.current===null&&(i.current=m);const h=m-i.current,s=Math.min(h/c,1),d=1-Math.pow(1-s,3);r(d),s<1&&(f=requestAnimationFrame(p))};return f=requestAnimationFrame(p),()=>cancelAnimationFrame(f)},[t,c]);const k=b.useCallback(f=>{const p=(f.startMs-a)/o,m=(f.endMs-a)/o;if(x<p)return{width:0,opacity:0};const h=m-p||.001,s=Math.min((x-p)/h,1),d=f.widthPct*s,j=Math.min(s/.1,1);return{width:d,opacity:j}},[x,a,o]);return{progress:x,animatedBar:k}}function R({className:t}){return e.jsx("svg",{className:t,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"})})}function B({className:t}){return e.jsx("svg",{className:t,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09zM18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.455 2.456L21.75 6l-1.036.259a3.375 3.375 0 00-2.455 2.456zM16.894 20.567L16.5 21.75l-.394-1.183a2.25 2.25 0 00-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 001.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 001.423 1.423l1.183.394-1.183.394a2.25 2.25 0 00-1.423 1.423z"})})}function O({className:t}){return e.jsx("svg",{className:t,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0"})})}function F({className:t}){return e.jsx("svg",{className:t,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z"})})}function ie({allExpanded:t,onToggleAll:a}){return e.jsxs("div",{className:"flex items-center gap-4 mb-4 flex-wrap",children:[e.jsx("button",{onClick:a,className:"text-2xs text-accent hover:underline",children:t?"Collapse all":"Expand all"}),e.jsxs("div",{className:"flex items-center gap-4 ml-auto",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(R,{className:"w-3.5 h-3.5 text-text-tertiary"}),e.jsx("span",{className:"text-2xs text-text-tertiary",children:"Task"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(B,{className:"w-3.5 h-3.5 text-text-tertiary"}),e.jsx("span",{className:"text-2xs text-text-tertiary",children:"AI Task"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(F,{className:"w-3.5 h-3.5 text-text-tertiary"}),e.jsx("span",{className:"text-2xs text-text-tertiary",children:"Escalation"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(O,{className:"w-3.5 h-3.5 text-text-tertiary"}),e.jsx("span",{className:"text-2xs text-text-tertiary",children:"Notification"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{className:"w-2.5 h-2.5 rounded-full dot-ring bg-status-success"}),e.jsx("span",{className:"text-2xs text-text-tertiary",children:"Done"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{className:"w-2.5 h-2.5 rounded-full dot-ring bg-status-warning"}),e.jsx("span",{className:"text-2xs text-text-tertiary",children:"Active"})]})]})]})}function oe({ticks:t}){return e.jsxs("div",{className:"flex",children:[e.jsx("div",{className:"w-52 shrink-0"}),e.jsx("div",{className:"flex-1 relative h-6 border-b border-surface-border",children:t.map(a=>e.jsx("span",{className:"absolute text-2xs font-mono text-text-tertiary -translate-x-1/2 bottom-1 whitespace-nowrap",style:{left:`${a.pct}%`},children:a.label},a.pct))})]})}function _({label:t,children:a}){return e.jsxs("div",{children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-0.5",children:t}),e.jsx("div",{className:"text-xs text-text-primary",children:a})]})}function le({traceId:t,href:a}){const[l,c]=b.useState(!1),x=i=>{i.stopPropagation(),navigator.clipboard.writeText(t),c(!0),setTimeout(()=>c(!1),1500)},r=i=>{i.stopPropagation(),a&&window.open(a,"_blank","noopener,noreferrer")};return e.jsxs("span",{className:"group/trace inline-flex items-center gap-1.5",children:[a&&e.jsx("button",{onClick:r,title:"Open trace",className:"opacity-0 group-hover/trace:opacity-100 transition-opacity p-0.5",children:e.jsx("svg",{className:"w-3 h-3 text-text-tertiary hover:text-accent",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-4.5-4.5h6m0 0v6m0-6L10.5 15"})})}),e.jsx("button",{onClick:x,title:"Copy trace ID",className:"opacity-0 group-hover/trace:opacity-100 transition-opacity p-0.5",children:e.jsx("svg",{className:`w-3 h-3 transition-colors ${l?"text-status-success":"text-text-tertiary hover:text-accent"}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:l?e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 13l4 4L19 7"}):e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3"})})}),e.jsx("span",{className:"text-2xs text-accent",children:"Trace Details"})]})}function ce({task:t,traceUrl:a}){const l=t.completed_at?new Date(t.completed_at).getTime()-new Date(t.created_at).getTime():Date.now()-new Date(t.created_at).getTime();return e.jsxs("div",{className:"grid grid-cols-[3fr_1fr] gap-6",children:[e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(W,{status:t.status}),e.jsx(Q,{type:t.workflow_type})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-4",children:[e.jsx(_,{label:"Started",children:e.jsx(y,{date:t.created_at})}),e.jsx(_,{label:"Completed",children:t.completed_at?e.jsx(y,{date:t.completed_at}):e.jsx("span",{className:"text-text-tertiary italic text-xs",children:"In progress"})}),e.jsx(_,{label:"Duration",children:e.jsx(S,{ms:l,className:"font-mono text-sm"})})]}),t.milestones.length>0&&e.jsxs("div",{children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1.5",children:"Milestones"}),e.jsx("div",{className:"flex flex-wrap gap-1.5",children:t.milestones.map((c,x)=>e.jsxs("span",{className:"px-2 py-0.5 text-2xs font-mono bg-accent-faint/50 rounded text-text-secondary",children:[c.name,": ",String(c.value)]},x))})]})]}),e.jsxs("div",{className:"flex flex-col items-end gap-2",children:[e.jsx(D,{to:`/workflows/executions/${encodeURIComponent(t.workflow_id)}`,className:"block text-2xs text-accent hover:underline",children:"Execution Details"}),e.jsx(D,{to:`/workflows/tasks/detail/${t.id}`,className:"block text-2xs text-accent hover:underline",children:"Task Details"}),t.trace_id&&e.jsx(le,{traceId:t.trace_id,href:a?a.replace("{traceId}",t.trace_id):void 0})]})]})}function de({escalation:t}){const a=new Date(t.created_at).getTime(),l=t.claimed_at?new Date(t.claimed_at).getTime()-a:null,c=t.resolved_at?new Date(t.resolved_at).getTime()-a:null;return e.jsxs("div",{className:"grid grid-cols-[3fr_1fr] gap-6",children:[e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(W,{status:t.status}),e.jsx(Y,{role:t.role}),t.type&&e.jsxs("span",{className:"text-2xs text-text-tertiary",children:[t.type,t.subtype?` / ${t.subtype}`:""]})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-4",children:[e.jsx(_,{label:"Created",children:e.jsx(y,{date:t.created_at})}),e.jsx(_,{label:"Claimed",children:t.claimed_at?e.jsxs(e.Fragment,{children:[e.jsx(y,{date:t.claimed_at}),e.jsxs("p",{className:"text-2xs text-text-tertiary mt-0.5",children:["after ",e.jsx(S,{ms:l}),t.assigned_to&&e.jsxs(e.Fragment,{children:[" ","by"," ",e.jsx("span",{className:"text-text-secondary font-medium",children:e.jsx(Z,{userId:t.assigned_to})})]})]})]}):e.jsx("span",{className:"text-text-tertiary italic text-xs",children:"Unclaimed"})}),e.jsx(_,{label:"Resolved",children:t.resolved_at?e.jsxs(e.Fragment,{children:[e.jsx(y,{date:t.resolved_at}),e.jsxs("p",{className:"text-2xs text-text-tertiary mt-0.5",children:[e.jsx(S,{ms:c})," total"]})]}):e.jsx("span",{className:"text-text-tertiary italic text-xs",children:"Pending"})})]}),t.description&&e.jsxs("div",{children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Description"}),e.jsx("p",{className:"text-2xs text-text-secondary leading-relaxed",children:t.description})]})]}),e.jsxs("div",{className:"flex flex-col items-end gap-2",children:[t.workflow_id&&e.jsx(D,{to:`/workflows/executions/${encodeURIComponent(t.workflow_id)}`,className:"block text-2xs text-accent hover:underline",children:"Execution Details"}),e.jsx(D,{to:`/escalations/detail/${t.id}`,className:"block text-2xs text-accent hover:underline",children:"Escalation Details"})]})]})}function xe({lane:t,ticks:a,isExpanded:l,onToggle:c,anim:x,animDone:r,traceUrl:i}){var m,h;const o=t.kind==="task",k=o?t.task.status:t.escalation.status,f=se(k,t.isOpen),p=x.opacity>0;return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center border-b border-surface-border cursor-pointer hover:bg-surface-sunken/40 transition-colors",onClick:c,children:[e.jsxs("div",{className:`w-52 shrink-0 py-3 pr-4 flex items-center gap-2 ${o?"":"pl-6"}`,style:{opacity:p?1:0,transition:"opacity 0.15s ease-out"},children:[o?ae(t.task.workflow_type)?e.jsx(B,{className:`w-4 h-4 shrink-0 ${$(t.task.status)}`}):e.jsx(R,{className:`w-4 h-4 shrink-0 ${$(t.task.status)}`}):E(t.escalation)?e.jsx(O,{className:`w-4 h-4 shrink-0 ${I(t.escalation.status)}`}):e.jsx(F,{className:`w-4 h-4 shrink-0 ${I(t.escalation.status)}`}),e.jsx("p",{className:"text-xs font-mono text-text-secondary whitespace-nowrap overflow-hidden",title:te(t.kind,o?t.task.status:t.escalation.status,!o&&E(t.escalation)),children:o?A(t.label,24):A(((m=t.escalation)==null?void 0:m.role)??t.label,20)})]}),e.jsxs("div",{className:"flex-1 relative h-10",children:[a.map(s=>e.jsx("div",{className:"absolute top-0 bottom-0 w-px bg-surface-border opacity-30",style:{left:`${s.pct}%`}},s.pct)),e.jsxs("div",{className:`absolute top-2 h-6 rounded-sm ${l?`${f} ring-2 ring-accent ring-offset-1`:`${f} hover:opacity-80`}`,style:{left:`${t.startPct}%`,width:p?`${Math.max(x.width,.3)}%`:"0%",minWidth:p?"4px":"0px",opacity:x.opacity},title:`${t.label} — ${L(t.durationMs)} — ${new Date(t.startMs).toLocaleTimeString()}`,children:[x.width>8&&r&&e.jsx("span",{className:"absolute inset-0 flex items-center px-1.5 text-2xs font-mono text-text-inverse truncate",children:L(t.durationMs)}),t.claimPct!=null&&r&&e.jsx("div",{className:"absolute top-0 bottom-0 w-px border-l border-dashed border-text-inverse/70",style:{left:`${t.claimPct}%`},title:(h=t.escalation)!=null&&h.assigned_to?`Claimed by ${t.escalation.assigned_to}`:"Claimed",children:e.jsx("div",{className:"absolute -top-1 -left-[3px] w-[7px] h-[7px] rounded-full bg-text-inverse border border-status-warning"})})]})]})]}),e.jsx(V,{open:l,children:e.jsx("div",{className:"py-4 px-6 pl-52 border-b border-surface-border bg-surface-sunken/20",children:o&&t.task?e.jsx(ce,{task:t.task,traceUrl:i}):t.escalation?e.jsx(de,{escalation:t.escalation}):null})})]})}function me({tasks:t,escalations:a,traceUrl:l}){const[c,x]=b.useState(new Set),{lanes:r,timeMin:i,timeMax:o}=b.useMemo(()=>ne(t,a),[t,a]),k=o-i||1,{progress:f,animatedBar:p}=re(r.length,i,o);if(r.length===0)return e.jsx("p",{className:"text-sm text-text-tertiary py-8 text-center",children:"No events in this process."});const m=5,h=Array.from({length:m+1},(n,u)=>({pct:u/m*100,label:L(Math.round(u/m*k))})),s=n=>{x(u=>{const N=new Set(u);return N.has(n)?N.delete(n):N.add(n),N})},d=r.map(n=>n.id),j=d.length>0&&d.every(n=>c.has(n)),g=()=>{x(j?new Set:new Set(d))},v=f>=1;return e.jsxs("div",{className:"py-2",children:[e.jsx(ie,{allExpanded:j,onToggleAll:g}),e.jsx(oe,{ticks:h}),r.map(n=>e.jsx(xe,{lane:n,ticks:h,isExpanded:c.has(n.id),onToggle:()=>s(n.id),anim:p(n),animDone:v,traceUrl:l},`${n.kind}-${n.id}`))]})}function C(t){if(!t)return null;try{return JSON.parse(t)}catch{return null}}function ue(t){return t.length===0?null:[...t].sort((a,l)=>new Date(a.created_at).getTime()-new Date(l.created_at).getTime())[0]}function ye(){var j;const{originId:t}=X();J(t);const{data:a,isLoading:l}=z(t??""),{data:c}=q(),x=((j=c==null?void 0:c.telemetry)==null?void 0:j.traceUrl)??null,r=(a==null?void 0:a.tasks)??[],i=(a==null?void 0:a.escalations)??[],o=b.useMemo(()=>ue(r),[r]),k=b.useMemo(()=>C(o==null?void 0:o.envelope),[o]),f=b.useMemo(()=>{if(o!=null&&o.data)return C(o.data);const g=r.filter(v=>v.status==="completed"&&v.data).sort((v,n)=>new Date(n.completed_at).getTime()-new Date(v.completed_at).getTime());return g.length>0?C(g[0].data):null},[o,r]),p=b.useMemo(()=>r.length>0&&r.some(g=>g.status!=="completed"&&g.status!=="cancelled"),[r]),m=b.useMemo(()=>{const g=r.filter(u=>u.status==="completed").length,v=r.filter(u=>u.status==="needs_intervention").length,n=i.filter(u=>u.status==="resolved").length;return{tasks:r.length,completed:g,escalated:v,escalations:i.length,resolved:n}},[r,i]),h=b.useMemo(()=>{if(r.length===0&&i.length===0)return null;const v=[...r.map(w=>w.created_at),...i.map(w=>w.created_at)].sort()[0],n=r.every(w=>w.status==="completed"||w.status==="cancelled"),u=i.every(w=>w.status==="resolved"),N=r.length>0&&n&&u,M=N?[...r.map(w=>w.completed_at),...i.map(w=>w.resolved_at)].filter(Boolean).sort().pop()??null:null;return{startIso:v,endIso:M,isFinished:N,elapsed:G(v,M)}},[r,i]),s=b.useMemo(()=>{const g=[];return h&&g.push({label:h.isFinished?"Completed":"Running",value:h.elapsed,dotClass:h.isFinished?"bg-status-success":"bg-status-pending animate-pulse"}),g.push({label:"Tasks",value:`${m.completed}/${m.tasks}`},{label:"Escalations",value:`${m.resolved}/${m.escalations}`}),g},[h,m]);if(l&&r.length===0)return e.jsxs("div",{className:"animate-pulse space-y-4",children:[e.jsx("div",{className:"h-8 bg-surface-sunken rounded w-48"}),e.jsx("div",{className:"h-40 bg-surface-sunken rounded"})]});const d=k||f||p;return e.jsxs("div",{children:[e.jsx(K,{title:"Process Detail",docsHash:"#docs:dashboard.md:process-detail",subtitle:t,stats:s}),d&&e.jsxs("div",{className:"grid grid-cols-1 @split:grid-cols-2 gap-8 mb-10",children:[e.jsx("div",{children:k?e.jsx(P,{data:k,label:"Input",defaultMode:"json",defaultCollapsed:!0}):e.jsxs("div",{children:[e.jsx(T,{children:"Input"}),e.jsx("div",{className:"font-mono text-xs bg-surface-sunken rounded-md p-4 text-text-tertiary italic mt-2",children:"Waiting for task..."})]})}),e.jsx("div",{children:f?e.jsx(P,{data:f,label:"Output",defaultMode:"json",defaultCollapsed:!0}):p?e.jsxs("div",{children:[e.jsx(T,{children:"Output"}),e.jsxs("div",{className:"flex items-center gap-2 font-mono text-xs bg-surface-sunken rounded-md p-4 text-text-secondary mt-2",children:[e.jsx("span",{className:"w-2.5 h-2.5 rounded-full dot-ring bg-status-pending animate-pulse"}),"Processing..."]})]}):null})]}),e.jsx(T,{className:"mb-6",children:"Timeline"}),e.jsx(me,{tasks:r,escalations:i,traceUrl:x})]})}export{ye as ProcessDetailPage};
2
- //# sourceMappingURL=ProcessDetailPage-BFcFSDUv.js.map
1
+ import{a as b,j as e}from"./vendor-query-DvWWuNIB.js";import{a as z}from"./tasks-CpdopewW.js";import{D as S,f as L,C as V,b as J,c as q,d as G,J as P,S as T}from"./index-CgUcYveM.js";import{P as K}from"./PageHeaderWithStats-CSnk1p5A.js";import{S as W}from"./StatusBadge-DHVwxre2.js";import{W as Q}from"./WorkflowPill-ZepbO_ny.js";import{T as y}from"./TimestampCell-DB7r3np8.js";import{L as D,e as X}from"./vendor-react-_9U4mKFr.js";import{R as Y}from"./RolePill-BafrASDX.js";import{U as Z}from"./UserName-Pw46tO_k.js";import"./vendor-icons-B7OcUM6b.js";const ee="bg-stripes animate-pulse opacity-70";function $(t){switch(t){case"completed":return"text-status-success";case"in_progress":case"pending":return"text-status-warning";case"needs_intervention":return"text-status-error";case"cancelled":return"text-text-tertiary";default:return"text-text-tertiary"}}function I(t){switch(t){case"resolved":return"text-status-success";case"pending":return"text-status-warning";case"cancelled":return"text-text-tertiary";default:return"text-text-tertiary"}}function te(t,a,l){return`${t==="task"?"Task":l?"Notification":"Escalation"} is ${a.replace(/_/g," ")}`}function se(t,a){if(a)return ee;switch(t){case"completed":case"resolved":return"bg-status-success";case"pending":case"in_progress":case"needs_intervention":return"bg-status-warning";case"cancelled":return"bg-status-error";default:return"bg-text-tertiary"}}function ae(t){return t.startsWith("mcp")||t.startsWith("Mcp")}function E(t){return!t.workflow_type}function A(t,a){if(t.length<=a)return t;const l=Math.floor((a-1)/2);return`${t.slice(0,l)}…${t.slice(t.length-l)}`}function ne(t,a){const l=Date.now(),c=new Map,x=[];for(const s of a)s.task_id?(c.has(s.task_id)||c.set(s.task_id,[]),c.get(s.task_id).push(s)):x.push(s);const r=[...t].sort((s,d)=>new Date(s.created_at).getTime()-new Date(d.created_at).getTime()),i=[];for(const s of t)i.push(new Date(s.created_at).getTime()),s.completed_at&&i.push(new Date(s.completed_at).getTime());for(const s of a)i.push(new Date(s.created_at).getTime()),s.resolved_at&&i.push(new Date(s.resolved_at).getTime()),s.claimed_at&&i.push(new Date(s.claimed_at).getTime());if(i.length===0)return{lanes:[],timeMin:0,timeMax:1};const o=Math.min(...i),f=t.some(s=>!s.completed_at)||a.some(s=>!s.resolved_at)?Math.max(l,Math.max(...i)):Math.max(...i),p=f-o||1,m=s=>(s-o)/p*100,h=[];for(const s of r){const d=new Date(s.created_at).getTime(),j=s.completed_at?new Date(s.completed_at).getTime():l,g=!s.completed_at;h.push({kind:"task",id:s.id,label:s.workflow_type,taskId:s.id,startMs:d,endMs:j,startPct:m(d),widthPct:Math.max((j-d)/p*100,.5),durationMs:j-d,isOpen:g,task:s});const v=(c.get(s.id)||[]).sort((n,u)=>new Date(n.created_at).getTime()-new Date(u.created_at).getTime());for(const n of v){const u=new Date(n.created_at).getTime(),N=n.resolved_at?new Date(n.resolved_at).getTime():l,M=!n.resolved_at;let w=null;if(n.claimed_at){const U=new Date(n.claimed_at).getTime(),H=N-u||1;w=(U-u)/H*100}h.push({kind:"escalation",id:n.id,label:n.role,taskId:s.id,startMs:u,endMs:N,startPct:m(u),widthPct:Math.max((N-u)/p*100,.5),durationMs:N-u,isOpen:M,escalation:n,claimPct:w})}}for(const s of x){const d=new Date(s.created_at).getTime(),j=s.resolved_at?new Date(s.resolved_at).getTime():l;let g=null;if(s.claimed_at){const v=new Date(s.claimed_at).getTime(),n=j-d||1;g=(v-d)/n*100}h.push({kind:"escalation",id:s.id,label:s.role,taskId:"",startMs:d,endMs:j,startPct:m(d),widthPct:Math.max((j-d)/p*100,.5),durationMs:j-d,isOpen:!s.resolved_at,escalation:s,claimPct:g})}return{lanes:h,timeMin:o,timeMax:f}}function re(t,a,l,c=500){const[x,r]=b.useState(0),i=b.useRef(null),o=l-a||1;b.useEffect(()=>{if(t===0)return;i.current=null,r(0);let f;const p=m=>{i.current===null&&(i.current=m);const h=m-i.current,s=Math.min(h/c,1),d=1-Math.pow(1-s,3);r(d),s<1&&(f=requestAnimationFrame(p))};return f=requestAnimationFrame(p),()=>cancelAnimationFrame(f)},[t,c]);const k=b.useCallback(f=>{const p=(f.startMs-a)/o,m=(f.endMs-a)/o;if(x<p)return{width:0,opacity:0};const h=m-p||.001,s=Math.min((x-p)/h,1),d=f.widthPct*s,j=Math.min(s/.1,1);return{width:d,opacity:j}},[x,a,o]);return{progress:x,animatedBar:k}}function R({className:t}){return e.jsx("svg",{className:t,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"})})}function B({className:t}){return e.jsx("svg",{className:t,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09zM18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.455 2.456L21.75 6l-1.036.259a3.375 3.375 0 00-2.455 2.456zM16.894 20.567L16.5 21.75l-.394-1.183a2.25 2.25 0 00-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 001.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 001.423 1.423l1.183.394-1.183.394a2.25 2.25 0 00-1.423 1.423z"})})}function O({className:t}){return e.jsx("svg",{className:t,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0"})})}function F({className:t}){return e.jsx("svg",{className:t,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z"})})}function ie({allExpanded:t,onToggleAll:a}){return e.jsxs("div",{className:"flex items-center gap-4 mb-4 flex-wrap",children:[e.jsx("button",{onClick:a,className:"text-2xs text-accent hover:underline",children:t?"Collapse all":"Expand all"}),e.jsxs("div",{className:"flex items-center gap-4 ml-auto",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(R,{className:"w-3.5 h-3.5 text-text-tertiary"}),e.jsx("span",{className:"text-2xs text-text-tertiary",children:"Task"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(B,{className:"w-3.5 h-3.5 text-text-tertiary"}),e.jsx("span",{className:"text-2xs text-text-tertiary",children:"AI Task"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(F,{className:"w-3.5 h-3.5 text-text-tertiary"}),e.jsx("span",{className:"text-2xs text-text-tertiary",children:"Escalation"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(O,{className:"w-3.5 h-3.5 text-text-tertiary"}),e.jsx("span",{className:"text-2xs text-text-tertiary",children:"Notification"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{className:"w-2.5 h-2.5 rounded-full dot-ring bg-status-success"}),e.jsx("span",{className:"text-2xs text-text-tertiary",children:"Done"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{className:"w-2.5 h-2.5 rounded-full dot-ring bg-status-warning"}),e.jsx("span",{className:"text-2xs text-text-tertiary",children:"Active"})]})]})]})}function oe({ticks:t}){return e.jsxs("div",{className:"flex",children:[e.jsx("div",{className:"w-52 shrink-0"}),e.jsx("div",{className:"flex-1 relative h-6 border-b border-surface-border",children:t.map(a=>e.jsx("span",{className:"absolute text-2xs font-mono text-text-tertiary -translate-x-1/2 bottom-1 whitespace-nowrap",style:{left:`${a.pct}%`},children:a.label},a.pct))})]})}function _({label:t,children:a}){return e.jsxs("div",{children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-0.5",children:t}),e.jsx("div",{className:"text-xs text-text-primary",children:a})]})}function le({traceId:t,href:a}){const[l,c]=b.useState(!1),x=i=>{i.stopPropagation(),navigator.clipboard.writeText(t),c(!0),setTimeout(()=>c(!1),1500)},r=i=>{i.stopPropagation(),a&&window.open(a,"_blank","noopener,noreferrer")};return e.jsxs("span",{className:"group/trace inline-flex items-center gap-1.5",children:[a&&e.jsx("button",{onClick:r,title:"Open trace",className:"opacity-0 group-hover/trace:opacity-100 transition-opacity p-0.5",children:e.jsx("svg",{className:"w-3 h-3 text-text-tertiary hover:text-accent",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-4.5-4.5h6m0 0v6m0-6L10.5 15"})})}),e.jsx("button",{onClick:x,title:"Copy trace ID",className:"opacity-0 group-hover/trace:opacity-100 transition-opacity p-0.5",children:e.jsx("svg",{className:`w-3 h-3 transition-colors ${l?"text-status-success":"text-text-tertiary hover:text-accent"}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:l?e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 13l4 4L19 7"}):e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3"})})}),e.jsx("span",{className:"text-2xs text-accent",children:"Trace Details"})]})}function ce({task:t,traceUrl:a}){const l=t.completed_at?new Date(t.completed_at).getTime()-new Date(t.created_at).getTime():Date.now()-new Date(t.created_at).getTime();return e.jsxs("div",{className:"grid grid-cols-[3fr_1fr] gap-6",children:[e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(W,{status:t.status}),e.jsx(Q,{type:t.workflow_type})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-4",children:[e.jsx(_,{label:"Started",children:e.jsx(y,{date:t.created_at})}),e.jsx(_,{label:"Completed",children:t.completed_at?e.jsx(y,{date:t.completed_at}):e.jsx("span",{className:"text-text-tertiary italic text-xs",children:"In progress"})}),e.jsx(_,{label:"Duration",children:e.jsx(S,{ms:l,className:"font-mono text-sm"})})]}),t.milestones.length>0&&e.jsxs("div",{children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1.5",children:"Milestones"}),e.jsx("div",{className:"flex flex-wrap gap-1.5",children:t.milestones.map((c,x)=>e.jsxs("span",{className:"px-2 py-0.5 text-2xs font-mono bg-accent-faint/50 rounded text-text-secondary",children:[c.name,": ",String(c.value)]},x))})]})]}),e.jsxs("div",{className:"flex flex-col items-end gap-2",children:[e.jsx(D,{to:`/workflows/executions/${encodeURIComponent(t.workflow_id)}`,className:"block text-2xs text-accent hover:underline",children:"Execution Details"}),e.jsx(D,{to:`/workflows/tasks/detail/${t.id}`,className:"block text-2xs text-accent hover:underline",children:"Task Details"}),t.trace_id&&e.jsx(le,{traceId:t.trace_id,href:a?a.replace("{traceId}",t.trace_id):void 0})]})]})}function de({escalation:t}){const a=new Date(t.created_at).getTime(),l=t.claimed_at?new Date(t.claimed_at).getTime()-a:null,c=t.resolved_at?new Date(t.resolved_at).getTime()-a:null;return e.jsxs("div",{className:"grid grid-cols-[3fr_1fr] gap-6",children:[e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(W,{status:t.status}),e.jsx(Y,{role:t.role}),t.type&&e.jsxs("span",{className:"text-2xs text-text-tertiary",children:[t.type,t.subtype?` / ${t.subtype}`:""]})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-4",children:[e.jsx(_,{label:"Created",children:e.jsx(y,{date:t.created_at})}),e.jsx(_,{label:"Claimed",children:t.claimed_at?e.jsxs(e.Fragment,{children:[e.jsx(y,{date:t.claimed_at}),e.jsxs("p",{className:"text-2xs text-text-tertiary mt-0.5",children:["after ",e.jsx(S,{ms:l}),t.assigned_to&&e.jsxs(e.Fragment,{children:[" ","by"," ",e.jsx("span",{className:"text-text-secondary font-medium",children:e.jsx(Z,{userId:t.assigned_to})})]})]})]}):e.jsx("span",{className:"text-text-tertiary italic text-xs",children:"Unclaimed"})}),e.jsx(_,{label:"Resolved",children:t.resolved_at?e.jsxs(e.Fragment,{children:[e.jsx(y,{date:t.resolved_at}),e.jsxs("p",{className:"text-2xs text-text-tertiary mt-0.5",children:[e.jsx(S,{ms:c})," total"]})]}):e.jsx("span",{className:"text-text-tertiary italic text-xs",children:"Pending"})})]}),t.description&&e.jsxs("div",{children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Description"}),e.jsx("p",{className:"text-2xs text-text-secondary leading-relaxed",children:t.description})]})]}),e.jsxs("div",{className:"flex flex-col items-end gap-2",children:[t.workflow_id&&e.jsx(D,{to:`/workflows/executions/${encodeURIComponent(t.workflow_id)}`,className:"block text-2xs text-accent hover:underline",children:"Execution Details"}),e.jsx(D,{to:`/escalations/detail/${t.id}`,className:"block text-2xs text-accent hover:underline",children:"Escalation Details"})]})]})}function xe({lane:t,ticks:a,isExpanded:l,onToggle:c,anim:x,animDone:r,traceUrl:i}){var m,h;const o=t.kind==="task",k=o?t.task.status:t.escalation.status,f=se(k,t.isOpen),p=x.opacity>0;return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center border-b border-surface-border cursor-pointer hover:bg-surface-sunken/40 transition-colors",onClick:c,children:[e.jsxs("div",{className:`w-52 shrink-0 py-3 pr-4 flex items-center gap-2 ${o?"":"pl-6"}`,style:{opacity:p?1:0,transition:"opacity 0.15s ease-out"},children:[o?ae(t.task.workflow_type)?e.jsx(B,{className:`w-4 h-4 shrink-0 ${$(t.task.status)}`}):e.jsx(R,{className:`w-4 h-4 shrink-0 ${$(t.task.status)}`}):E(t.escalation)?e.jsx(O,{className:`w-4 h-4 shrink-0 ${I(t.escalation.status)}`}):e.jsx(F,{className:`w-4 h-4 shrink-0 ${I(t.escalation.status)}`}),e.jsx("p",{className:"text-xs font-mono text-text-secondary whitespace-nowrap overflow-hidden",title:te(t.kind,o?t.task.status:t.escalation.status,!o&&E(t.escalation)),children:o?A(t.label,24):A(((m=t.escalation)==null?void 0:m.role)??t.label,20)})]}),e.jsxs("div",{className:"flex-1 relative h-10",children:[a.map(s=>e.jsx("div",{className:"absolute top-0 bottom-0 w-px bg-surface-border opacity-30",style:{left:`${s.pct}%`}},s.pct)),e.jsxs("div",{className:`absolute top-2 h-6 rounded-sm ${l?`${f} ring-2 ring-accent ring-offset-1`:`${f} hover:opacity-80`}`,style:{left:`${t.startPct}%`,width:p?`${Math.max(x.width,.3)}%`:"0%",minWidth:p?"4px":"0px",opacity:x.opacity},title:`${t.label} — ${L(t.durationMs)} — ${new Date(t.startMs).toLocaleTimeString()}`,children:[x.width>8&&r&&e.jsx("span",{className:"absolute inset-0 flex items-center px-1.5 text-2xs font-mono text-text-inverse truncate",children:L(t.durationMs)}),t.claimPct!=null&&r&&e.jsx("div",{className:"absolute top-0 bottom-0 w-px border-l border-dashed border-text-inverse/70",style:{left:`${t.claimPct}%`},title:(h=t.escalation)!=null&&h.assigned_to?`Claimed by ${t.escalation.assigned_to}`:"Claimed",children:e.jsx("div",{className:"absolute -top-1 -left-[3px] w-[7px] h-[7px] rounded-full bg-text-inverse border border-status-warning"})})]})]})]}),e.jsx(V,{open:l,children:e.jsx("div",{className:"py-4 px-6 pl-52 border-b border-surface-border bg-surface-sunken/20",children:o&&t.task?e.jsx(ce,{task:t.task,traceUrl:i}):t.escalation?e.jsx(de,{escalation:t.escalation}):null})})]})}function me({tasks:t,escalations:a,traceUrl:l}){const[c,x]=b.useState(new Set),{lanes:r,timeMin:i,timeMax:o}=b.useMemo(()=>ne(t,a),[t,a]),k=o-i||1,{progress:f,animatedBar:p}=re(r.length,i,o);if(r.length===0)return e.jsx("p",{className:"text-sm text-text-tertiary py-8 text-center",children:"No events in this process."});const m=5,h=Array.from({length:m+1},(n,u)=>({pct:u/m*100,label:L(Math.round(u/m*k))})),s=n=>{x(u=>{const N=new Set(u);return N.has(n)?N.delete(n):N.add(n),N})},d=r.map(n=>n.id),j=d.length>0&&d.every(n=>c.has(n)),g=()=>{x(j?new Set:new Set(d))},v=f>=1;return e.jsxs("div",{className:"py-2",children:[e.jsx(ie,{allExpanded:j,onToggleAll:g}),e.jsx(oe,{ticks:h}),r.map(n=>e.jsx(xe,{lane:n,ticks:h,isExpanded:c.has(n.id),onToggle:()=>s(n.id),anim:p(n),animDone:v,traceUrl:l},`${n.kind}-${n.id}`))]})}function C(t){if(!t)return null;try{return JSON.parse(t)}catch{return null}}function ue(t){return t.length===0?null:[...t].sort((a,l)=>new Date(a.created_at).getTime()-new Date(l.created_at).getTime())[0]}function ye(){var j;const{originId:t}=X();J(t);const{data:a,isLoading:l}=z(t??""),{data:c}=q(),x=((j=c==null?void 0:c.telemetry)==null?void 0:j.traceUrl)??null,r=(a==null?void 0:a.tasks)??[],i=(a==null?void 0:a.escalations)??[],o=b.useMemo(()=>ue(r),[r]),k=b.useMemo(()=>C(o==null?void 0:o.envelope),[o]),f=b.useMemo(()=>{if(o!=null&&o.data)return C(o.data);const g=r.filter(v=>v.status==="completed"&&v.data).sort((v,n)=>new Date(n.completed_at).getTime()-new Date(v.completed_at).getTime());return g.length>0?C(g[0].data):null},[o,r]),p=b.useMemo(()=>r.length>0&&r.some(g=>g.status!=="completed"&&g.status!=="cancelled"),[r]),m=b.useMemo(()=>{const g=r.filter(u=>u.status==="completed").length,v=r.filter(u=>u.status==="needs_intervention").length,n=i.filter(u=>u.status==="resolved").length;return{tasks:r.length,completed:g,escalated:v,escalations:i.length,resolved:n}},[r,i]),h=b.useMemo(()=>{if(r.length===0&&i.length===0)return null;const v=[...r.map(w=>w.created_at),...i.map(w=>w.created_at)].sort()[0],n=r.every(w=>w.status==="completed"||w.status==="cancelled"),u=i.every(w=>w.status==="resolved"),N=r.length>0&&n&&u,M=N?[...r.map(w=>w.completed_at),...i.map(w=>w.resolved_at)].filter(Boolean).sort().pop()??null:null;return{startIso:v,endIso:M,isFinished:N,elapsed:G(v,M)}},[r,i]),s=b.useMemo(()=>{const g=[];return h&&g.push({label:h.isFinished?"Completed":"Running",value:h.elapsed,dotClass:h.isFinished?"bg-status-success":"bg-status-pending animate-pulse"}),g.push({label:"Tasks",value:`${m.completed}/${m.tasks}`},{label:"Escalations",value:`${m.resolved}/${m.escalations}`}),g},[h,m]);if(l&&r.length===0)return e.jsxs("div",{className:"animate-pulse space-y-4",children:[e.jsx("div",{className:"h-8 bg-surface-sunken rounded w-48"}),e.jsx("div",{className:"h-40 bg-surface-sunken rounded"})]});const d=k||f||p;return e.jsxs("div",{children:[e.jsx(K,{title:"Process Detail",docsHash:"#docs:dashboard.md:process-detail",subtitle:t,stats:s}),d&&e.jsxs("div",{className:"grid grid-cols-1 @split:grid-cols-2 gap-8 mb-10",children:[e.jsx("div",{children:k?e.jsx(P,{data:k,label:"Input",defaultMode:"json",defaultCollapsed:!0}):e.jsxs("div",{children:[e.jsx(T,{children:"Input"}),e.jsx("div",{className:"font-mono text-xs bg-surface-sunken rounded-md p-4 text-text-tertiary italic mt-2",children:"Waiting for task..."})]})}),e.jsx("div",{children:f?e.jsx(P,{data:f,label:"Output",defaultMode:"json",defaultCollapsed:!0}):p?e.jsxs("div",{children:[e.jsx(T,{children:"Output"}),e.jsxs("div",{className:"flex items-center gap-2 font-mono text-xs bg-surface-sunken rounded-md p-4 text-text-secondary mt-2",children:[e.jsx("span",{className:"w-2.5 h-2.5 rounded-full dot-ring bg-status-pending animate-pulse"}),"Processing..."]})]}):null})]}),e.jsx(T,{className:"mb-6",children:"Timeline"}),e.jsx(me,{tasks:r,escalations:i,traceUrl:x})]})}export{ye as ProcessDetailPage};
2
+ //# sourceMappingURL=ProcessDetailPage-BT0eiBWY.js.map