@hotmeshio/long-tail 0.8.4 → 0.9.0

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 (257) hide show
  1. package/build/api/escalations/index.d.ts +1 -1
  2. package/build/api/escalations/index.js +2 -1
  3. package/build/api/escalations/resolve.d.ts +28 -0
  4. package/build/api/escalations/resolve.js +98 -0
  5. package/build/api/roles.d.ts +21 -0
  6. package/build/api/roles.js +50 -0
  7. package/build/lib/db/index.js +12 -1
  8. package/build/lib/db/migrate.js +27 -0
  9. package/build/lib/db/schemas/021_role_list_schema.sql +27 -0
  10. package/build/modules/defaults.d.ts +2 -0
  11. package/build/modules/defaults.js +3 -1
  12. package/build/routes/escalations/resolve.js +18 -0
  13. package/build/routes/roles.js +20 -0
  14. package/build/sdk/index.d.ts +8 -0
  15. package/build/sdk/index.js +1 -0
  16. package/build/services/escalation/crud.d.ts +36 -0
  17. package/build/services/escalation/crud.js +53 -0
  18. package/build/services/maintenance/index.js +22 -0
  19. package/build/services/role/index.d.ts +13 -1
  20. package/build/services/role/index.js +27 -0
  21. package/build/services/role/sql.d.ts +14 -2
  22. package/build/services/role/sql.js +51 -3
  23. package/build/services/role/types.d.ts +27 -0
  24. package/build/types/maintenance.d.ts +6 -1
  25. package/dashboard/dist/assets/{AdminDashboard-B-JptT54.js → AdminDashboard-5bWcBxyS.js} +2 -2
  26. package/dashboard/dist/assets/{AdminDashboard-B-JptT54.js.map → AdminDashboard-5bWcBxyS.js.map} +1 -1
  27. package/dashboard/dist/assets/{AgentConfigPage-B1Jc6iJk.js → AgentConfigPage-CVg_tFbf.js} +6 -6
  28. package/dashboard/dist/assets/{AgentConfigPage-B1Jc6iJk.js.map → AgentConfigPage-CVg_tFbf.js.map} +1 -1
  29. package/dashboard/dist/assets/{AgentDetailPage-CWpclCOY.js → AgentDetailPage-CLlkIoRQ.js} +4 -4
  30. package/dashboard/dist/assets/{AgentDetailPage-CWpclCOY.js.map → AgentDetailPage-CLlkIoRQ.js.map} +1 -1
  31. package/dashboard/dist/assets/{AgentsPage-DyAf5GA2.js → AgentsPage-CjruF_ek.js} +2 -2
  32. package/dashboard/dist/assets/{AgentsPage-DyAf5GA2.js.map → AgentsPage-CjruF_ek.js.map} +1 -1
  33. package/dashboard/dist/assets/AvailableEscalationsPage-h6awiuVk.js +2 -0
  34. package/dashboard/dist/assets/AvailableEscalationsPage-h6awiuVk.js.map +1 -0
  35. package/dashboard/dist/assets/{BotPicker-B1RdaNuY.js → BotPicker-CGEFHHDE.js} +2 -2
  36. package/dashboard/dist/assets/{BotPicker-B1RdaNuY.js.map → BotPicker-CGEFHHDE.js.map} +1 -1
  37. package/dashboard/dist/assets/{CapabilitiesPage-CxHDnyjX.js → CapabilitiesPage-BI1tNYun.js} +2 -2
  38. package/dashboard/dist/assets/{CapabilitiesPage-CxHDnyjX.js.map → CapabilitiesPage-BI1tNYun.js.map} +1 -1
  39. package/dashboard/dist/assets/{CollapsibleSection-Ds0e8cCO.js → CollapsibleSection-B9f52Z2K.js} +2 -2
  40. package/dashboard/dist/assets/{CollapsibleSection-Ds0e8cCO.js.map → CollapsibleSection-B9f52Z2K.js.map} +1 -1
  41. package/dashboard/dist/assets/{CopyableId-blg-gZvT.js → CopyableId-uot2mE_g.js} +2 -2
  42. package/dashboard/dist/assets/{CopyableId-blg-gZvT.js.map → CopyableId-uot2mE_g.js.map} +1 -1
  43. package/dashboard/dist/assets/CountdownTimer-C71erQ67.js +2 -0
  44. package/dashboard/dist/assets/CountdownTimer-C71erQ67.js.map +1 -0
  45. package/dashboard/dist/assets/{CredentialsPage-D8UVO-3A.js → CredentialsPage-smk5H_mP.js} +2 -2
  46. package/dashboard/dist/assets/{CredentialsPage-D8UVO-3A.js.map → CredentialsPage-smk5H_mP.js.map} +1 -1
  47. package/dashboard/dist/assets/{CronLabel-ZesYXxCH.js → CronLabel-CCJLmkIq.js} +2 -2
  48. package/dashboard/dist/assets/{CronLabel-ZesYXxCH.js.map → CronLabel-CCJLmkIq.js.map} +1 -1
  49. package/dashboard/dist/assets/CustomDurationPicker-DQ28g5GB.js +2 -0
  50. package/dashboard/dist/assets/CustomDurationPicker-DQ28g5GB.js.map +1 -0
  51. package/dashboard/dist/assets/DataTable-Byn3oyT9.js +2 -0
  52. package/dashboard/dist/assets/DataTable-Byn3oyT9.js.map +1 -0
  53. package/dashboard/dist/assets/{DropZone-SgiK1WOl.js → DropZone-C_Mc4UrO.js} +2 -2
  54. package/dashboard/dist/assets/{DropZone-SgiK1WOl.js.map → DropZone-C_Mc4UrO.js.map} +1 -1
  55. package/dashboard/dist/assets/{ElapsedCell-CO8S6vdb.js → ElapsedCell-Cw1uvJKx.js} +2 -2
  56. package/dashboard/dist/assets/{ElapsedCell-CO8S6vdb.js.map → ElapsedCell-Cw1uvJKx.js.map} +1 -1
  57. package/dashboard/dist/assets/EscalationListSchemaPage-3v2tiCnq.js +20 -0
  58. package/dashboard/dist/assets/EscalationListSchemaPage-3v2tiCnq.js.map +1 -0
  59. package/dashboard/dist/assets/EscalationSchemaPage-DIq2pMED.js +9 -0
  60. package/dashboard/dist/assets/EscalationSchemaPage-DIq2pMED.js.map +1 -0
  61. package/dashboard/dist/assets/{EscalationsOverview-DMpRvVql.js → EscalationsOverview-BqOZ1v8w.js} +2 -2
  62. package/dashboard/dist/assets/{EscalationsOverview-DMpRvVql.js.map → EscalationsOverview-BqOZ1v8w.js.map} +1 -1
  63. package/dashboard/dist/assets/EventTable-CyfHfOWj.js +2 -0
  64. package/dashboard/dist/assets/EventTable-CyfHfOWj.js.map +1 -0
  65. package/dashboard/dist/assets/{FilterBar-B4Mk2PvT.js → FilterBar-DDIn8TOs.js} +2 -2
  66. package/dashboard/dist/assets/{FilterBar-B4Mk2PvT.js.map → FilterBar-DDIn8TOs.js.map} +1 -1
  67. package/dashboard/dist/assets/{GraphInvokePage-CTuul-av.js → GraphInvokePage-DbNUaWhH.js} +2 -2
  68. package/dashboard/dist/assets/{GraphInvokePage-CTuul-av.js.map → GraphInvokePage-DbNUaWhH.js.map} +1 -1
  69. package/dashboard/dist/assets/{HomePage-BKFpOaHX.js → HomePage-Cj9sLt4Z.js} +2 -2
  70. package/dashboard/dist/assets/{HomePage-BKFpOaHX.js.map → HomePage-Cj9sLt4Z.js.map} +1 -1
  71. package/dashboard/dist/assets/{ListToolbar-Dz2_neVF.js → ListToolbar-D7PoQOZC.js} +2 -2
  72. package/dashboard/dist/assets/{ListToolbar-Dz2_neVF.js.map → ListToolbar-D7PoQOZC.js.map} +1 -1
  73. package/dashboard/dist/assets/{McpOverview-Do-vaEqV.js → McpOverview-D9g1iJyn.js} +2 -2
  74. package/dashboard/dist/assets/{McpOverview-Do-vaEqV.js.map → McpOverview-D9g1iJyn.js.map} +1 -1
  75. package/dashboard/dist/assets/{McpQueryDetailPage-HwDGNSbN.js → McpQueryDetailPage-DwS1pXdT.js} +2 -2
  76. package/dashboard/dist/assets/{McpQueryDetailPage-HwDGNSbN.js.map → McpQueryDetailPage-DwS1pXdT.js.map} +1 -1
  77. package/dashboard/dist/assets/{McpQueryPage-DxMUpQ7R.js → McpQueryPage-DZQ1z6-H.js} +2 -2
  78. package/dashboard/dist/assets/{McpQueryPage-DxMUpQ7R.js.map → McpQueryPage-DZQ1z6-H.js.map} +1 -1
  79. package/dashboard/dist/assets/McpRunDetailPage-Bx6w39lr.js +2 -0
  80. package/dashboard/dist/assets/{McpRunDetailPage-BzzZIXIk.js.map → McpRunDetailPage-Bx6w39lr.js.map} +1 -1
  81. package/dashboard/dist/assets/{McpRunsPage-D3J42d2i.js → McpRunsPage-C-oS_tTh.js} +2 -2
  82. package/dashboard/dist/assets/{McpRunsPage-D3J42d2i.js.map → McpRunsPage-C-oS_tTh.js.map} +1 -1
  83. package/dashboard/dist/assets/{NamespacePill-SErKwgkb.js → NamespacePill-DhgC3EUO.js} +2 -2
  84. package/dashboard/dist/assets/{NamespacePill-SErKwgkb.js.map → NamespacePill-DhgC3EUO.js.map} +1 -1
  85. package/dashboard/dist/assets/OperationsPage-CQzX6jM1.js +2 -0
  86. package/dashboard/dist/assets/OperationsPage-CQzX6jM1.js.map +1 -0
  87. package/dashboard/dist/assets/OperatorDashboard-Cqf87ojd.js +2 -0
  88. package/dashboard/dist/assets/{OperatorDashboard-BqJn8wEZ.js.map → OperatorDashboard-Cqf87ojd.js.map} +1 -1
  89. package/dashboard/dist/assets/PageHeader-sGNTmSXX.js +2 -0
  90. package/dashboard/dist/assets/PageHeader-sGNTmSXX.js.map +1 -0
  91. package/dashboard/dist/assets/{PageHeaderWithStats-W3akV6nB.js → PageHeaderWithStats-87STTAJX.js} +2 -2
  92. package/dashboard/dist/assets/{PageHeaderWithStats-W3akV6nB.js.map → PageHeaderWithStats-87STTAJX.js.map} +1 -1
  93. package/dashboard/dist/assets/{ProcessDetailPage-C8sT2xuE.js → ProcessDetailPage-CplnDXkz.js} +2 -2
  94. package/dashboard/dist/assets/{ProcessDetailPage-C8sT2xuE.js.map → ProcessDetailPage-CplnDXkz.js.map} +1 -1
  95. package/dashboard/dist/assets/{ProcessesListPage-eA8buUgd.js → ProcessesListPage-DFOJC27f.js} +2 -2
  96. package/dashboard/dist/assets/{ProcessesListPage-eA8buUgd.js.map → ProcessesListPage-DFOJC27f.js.map} +1 -1
  97. package/dashboard/dist/assets/RoleDetailPage-VrWOaPlg.js +8 -0
  98. package/dashboard/dist/assets/RoleDetailPage-VrWOaPlg.js.map +1 -0
  99. package/dashboard/dist/assets/{RolePill-DHWixsQR.js → RolePill-C91qbDOW.js} +2 -2
  100. package/dashboard/dist/assets/{RolePill-DHWixsQR.js.map → RolePill-C91qbDOW.js.map} +1 -1
  101. package/dashboard/dist/assets/{RolesPage-BQNQxsMY.js → RolesPage-DdI1rVAP.js} +2 -2
  102. package/dashboard/dist/assets/{RolesPage-BQNQxsMY.js.map → RolesPage-DdI1rVAP.js.map} +1 -1
  103. package/dashboard/dist/assets/{RunAsSelector-mhusrlYE.js → RunAsSelector-C6EozzKV.js} +2 -2
  104. package/dashboard/dist/assets/{RunAsSelector-mhusrlYE.js.map → RunAsSelector-C6EozzKV.js.map} +1 -1
  105. package/dashboard/dist/assets/SlidePanel-BpWveV1T.js +2 -0
  106. package/dashboard/dist/assets/SlidePanel-BpWveV1T.js.map +1 -0
  107. package/dashboard/dist/assets/{StatusBadge-DZ9137bI.js → StatusBadge-CEQMRmSQ.js} +2 -2
  108. package/dashboard/dist/assets/StatusBadge-CEQMRmSQ.js.map +1 -0
  109. package/dashboard/dist/assets/{StickyPagination-CqT9Q1I6.js → StickyPagination-BEgkYJ0-.js} +2 -2
  110. package/dashboard/dist/assets/{StickyPagination-CqT9Q1I6.js.map → StickyPagination-BEgkYJ0-.js.map} +1 -1
  111. package/dashboard/dist/assets/{StreamMessageDetail-jOJaoupp.js → StreamMessageDetail-DWVPtzj7.js} +2 -2
  112. package/dashboard/dist/assets/{StreamMessageDetail-jOJaoupp.js.map → StreamMessageDetail-DWVPtzj7.js.map} +1 -1
  113. package/dashboard/dist/assets/{SwimlaneTimeline-BrfmWgAj.js → SwimlaneTimeline-4NrDJNYc.js} +2 -2
  114. package/dashboard/dist/assets/{SwimlaneTimeline-BrfmWgAj.js.map → SwimlaneTimeline-4NrDJNYc.js.map} +1 -1
  115. package/dashboard/dist/assets/{TagInput-CGGC3DTR.js → TagInput-Csm36_pS.js} +2 -2
  116. package/dashboard/dist/assets/{TagInput-CGGC3DTR.js.map → TagInput-Csm36_pS.js.map} +1 -1
  117. package/dashboard/dist/assets/{TaskDetailPage-Cus_JHIC.js → TaskDetailPage-BvdaAUtF.js} +2 -2
  118. package/dashboard/dist/assets/{TaskDetailPage-Cus_JHIC.js.map → TaskDetailPage-BvdaAUtF.js.map} +1 -1
  119. package/dashboard/dist/assets/{TaskQueuePill-D6omQJNY.js → TaskQueuePill-5XdNaqwM.js} +2 -2
  120. package/dashboard/dist/assets/{TaskQueuePill-D6omQJNY.js.map → TaskQueuePill-5XdNaqwM.js.map} +1 -1
  121. package/dashboard/dist/assets/{TasksListPage-B7GK8AoX.js → TasksListPage-BxA161LH.js} +2 -2
  122. package/dashboard/dist/assets/{TasksListPage-B7GK8AoX.js.map → TasksListPage-BxA161LH.js.map} +1 -1
  123. package/dashboard/dist/assets/{TimeAgo-C606LzT3.js → TimeAgo-ChwJ4fjZ.js} +2 -2
  124. package/dashboard/dist/assets/{TimeAgo-C606LzT3.js.map → TimeAgo-ChwJ4fjZ.js.map} +1 -1
  125. package/dashboard/dist/assets/{TimestampCell-hfh6zvH-.js → TimestampCell-C7KzmvyC.js} +2 -2
  126. package/dashboard/dist/assets/{TimestampCell-hfh6zvH-.js.map → TimestampCell-C7KzmvyC.js.map} +1 -1
  127. package/dashboard/dist/assets/{ToolPill-BW0iRwZu.js → ToolPill-CAwj7EPw.js} +2 -2
  128. package/dashboard/dist/assets/{ToolPill-BW0iRwZu.js.map → ToolPill-CAwj7EPw.js.map} +1 -1
  129. package/dashboard/dist/assets/{ToolTestPanel-CsPsyvQq.js → ToolTestPanel-ISkuXtkT.js} +2 -2
  130. package/dashboard/dist/assets/{ToolTestPanel-CsPsyvQq.js.map → ToolTestPanel-ISkuXtkT.js.map} +1 -1
  131. package/dashboard/dist/assets/{TopicDetailPage-Diz6r7zr.js → TopicDetailPage-D8uZ8Wbs.js} +3 -3
  132. package/dashboard/dist/assets/{TopicDetailPage-Diz6r7zr.js.map → TopicDetailPage-D8uZ8Wbs.js.map} +1 -1
  133. package/dashboard/dist/assets/TopicsPage-rj88vA_1.js +2 -0
  134. package/dashboard/dist/assets/{TopicsPage-B6fn7fFh.js.map → TopicsPage-rj88vA_1.js.map} +1 -1
  135. package/dashboard/dist/assets/{UserName-Cc-5QH5q.js → UserName-D03Lh6Aj.js} +2 -2
  136. package/dashboard/dist/assets/{UserName-Cc-5QH5q.js.map → UserName-D03Lh6Aj.js.map} +1 -1
  137. package/dashboard/dist/assets/WorkflowExecutionPage-LD9WzPee.js +2 -0
  138. package/dashboard/dist/assets/WorkflowExecutionPage-LD9WzPee.js.map +1 -0
  139. package/dashboard/dist/assets/{WorkflowPill-BtNBSplz.js → WorkflowPill-fodIWnT3.js} +2 -2
  140. package/dashboard/dist/assets/{WorkflowPill-BtNBSplz.js.map → WorkflowPill-fodIWnT3.js.map} +1 -1
  141. package/dashboard/dist/assets/{WorkflowsDashboard-CHCM6hUa.js → WorkflowsDashboard-DH0jitAb.js} +2 -2
  142. package/dashboard/dist/assets/{WorkflowsDashboard-CHCM6hUa.js.map → WorkflowsDashboard-DH0jitAb.js.map} +1 -1
  143. package/dashboard/dist/assets/{WorkflowsOverview-WeOvl8-_.js → WorkflowsOverview-D6BVaH9e.js} +2 -2
  144. package/dashboard/dist/assets/{WorkflowsOverview-WeOvl8-_.js.map → WorkflowsOverview-D6BVaH9e.js.map} +1 -1
  145. package/dashboard/dist/assets/{YamlWorkflowDetailPage-6GfhVDpv.js → YamlWorkflowDetailPage-D_CfNEqW.js} +2 -2
  146. package/dashboard/dist/assets/{YamlWorkflowDetailPage-6GfhVDpv.js.map → YamlWorkflowDetailPage-D_CfNEqW.js.map} +1 -1
  147. package/dashboard/dist/assets/{YamlWorkflowsPage-DqcY3ocP.js → YamlWorkflowsPage-BMJgtcAq.js} +2 -2
  148. package/dashboard/dist/assets/{YamlWorkflowsPage-DqcY3ocP.js.map → YamlWorkflowsPage-BMJgtcAq.js.map} +1 -1
  149. package/dashboard/dist/assets/{agents-DlzvjNxE.js → agents-Ci0tZDO3.js} +2 -2
  150. package/dashboard/dist/assets/{agents-DlzvjNxE.js.map → agents-Ci0tZDO3.js.map} +1 -1
  151. package/dashboard/dist/assets/{bots-CWMN-KUI.js → bots-DZyt1oO4.js} +2 -2
  152. package/dashboard/dist/assets/{bots-CWMN-KUI.js.map → bots-DZyt1oO4.js.map} +1 -1
  153. package/dashboard/dist/assets/{capabilities-_WSZ7cxO.js → capabilities-DzVKeWyC.js} +2 -2
  154. package/dashboard/dist/assets/{capabilities-_WSZ7cxO.js.map → capabilities-DzVKeWyC.js.map} +1 -1
  155. package/dashboard/dist/assets/{controlplane-_k9nWZy3.js → controlplane-CQzrn-rD.js} +2 -2
  156. package/dashboard/dist/assets/{controlplane-_k9nWZy3.js.map → controlplane-CQzrn-rD.js.map} +1 -1
  157. package/dashboard/dist/assets/escalation-columns-s29Q4mrF.js +2 -0
  158. package/dashboard/dist/assets/{escalation-columns-Dyrf6Tdp.js.map → escalation-columns-s29Q4mrF.js.map} +1 -1
  159. package/dashboard/dist/assets/{index-kKufOPLo.js → index-3SrgIA7w.js} +2 -2
  160. package/dashboard/dist/assets/{index-kKufOPLo.js.map → index-3SrgIA7w.js.map} +1 -1
  161. package/dashboard/dist/assets/{index-Dd4Si1Rl.js → index-B2dB90aC.js} +2 -2
  162. package/dashboard/dist/assets/{index-Dd4Si1Rl.js.map → index-B2dB90aC.js.map} +1 -1
  163. package/dashboard/dist/assets/index-BSOcWfeR.js +5 -0
  164. package/dashboard/dist/assets/index-BSOcWfeR.js.map +1 -0
  165. package/dashboard/dist/assets/{index-uUYXmvFf.js → index-BWy4UvaT.js} +2 -2
  166. package/dashboard/dist/assets/{index-uUYXmvFf.js.map → index-BWy4UvaT.js.map} +1 -1
  167. package/dashboard/dist/assets/{index-C3h0qGzG.js → index-BqKxJ2fB.js} +2 -2
  168. package/dashboard/dist/assets/{index-C3h0qGzG.js.map → index-BqKxJ2fB.js.map} +1 -1
  169. package/dashboard/dist/assets/{index-DwWP-Z_c.js → index-C9moIiIq.js} +5 -5
  170. package/dashboard/dist/assets/{index-DwWP-Z_c.js.map → index-C9moIiIq.js.map} +1 -1
  171. package/dashboard/dist/assets/{index-Dc-Ye2wk.js → index-CcKXMU-s.js} +2 -2
  172. package/dashboard/dist/assets/{index-Dc-Ye2wk.js.map → index-CcKXMU-s.js.map} +1 -1
  173. package/dashboard/dist/assets/index-DIPe82gq.css +1 -0
  174. package/dashboard/dist/assets/{index-D8GcHxNJ.js → index-DOHGHMP7.js} +2 -2
  175. package/dashboard/dist/assets/{index-D8GcHxNJ.js.map → index-DOHGHMP7.js.map} +1 -1
  176. package/dashboard/dist/assets/{index-C5Yc3TT7.js → index-DTn4XzYN.js} +2 -2
  177. package/dashboard/dist/assets/{index-C5Yc3TT7.js.map → index-DTn4XzYN.js.map} +1 -1
  178. package/dashboard/dist/assets/index-Dv8mzG9B.js +2 -0
  179. package/dashboard/dist/assets/index-Dv8mzG9B.js.map +1 -0
  180. package/dashboard/dist/assets/{index-Ex5tEte8.js → index-LwodswlU.js} +2 -2
  181. package/dashboard/dist/assets/{index-Ex5tEte8.js.map → index-LwodswlU.js.map} +1 -1
  182. package/dashboard/dist/assets/{index-C7VXLKJs.js → index-kPipMHZx.js} +2 -2
  183. package/dashboard/dist/assets/{index-C7VXLKJs.js.map → index-kPipMHZx.js.map} +1 -1
  184. package/dashboard/dist/assets/{index-BiApvBEz.js → index-sdc9ecdW.js} +2 -2
  185. package/dashboard/dist/assets/{index-BiApvBEz.js.map → index-sdc9ecdW.js.map} +1 -1
  186. package/dashboard/dist/assets/{knowledge-fYoEF4Lx.js → knowledge-fi5z5YLq.js} +2 -2
  187. package/dashboard/dist/assets/{knowledge-fYoEF4Lx.js.map → knowledge-fi5z5YLq.js.map} +1 -1
  188. package/dashboard/dist/assets/{mcp-1lzlgtS8.js → mcp-CH8Tj9Pw.js} +2 -2
  189. package/dashboard/dist/assets/{mcp-1lzlgtS8.js.map → mcp-CH8Tj9Pw.js.map} +1 -1
  190. package/dashboard/dist/assets/{mcp-query-nlrAz7m_.js → mcp-query-6alwNh7K.js} +2 -2
  191. package/dashboard/dist/assets/{mcp-query-nlrAz7m_.js.map → mcp-query-6alwNh7K.js.map} +1 -1
  192. package/dashboard/dist/assets/{pipelines-Ihi7EKXi.js → pipelines-Dqh9PLUw.js} +2 -2
  193. package/dashboard/dist/assets/{pipelines-Ihi7EKXi.js.map → pipelines-Dqh9PLUw.js.map} +1 -1
  194. package/dashboard/dist/assets/roles-dJKBZUBh.js +2 -0
  195. package/dashboard/dist/assets/roles-dJKBZUBh.js.map +1 -0
  196. package/dashboard/dist/assets/{tasks-Crk9Y3C4.js → tasks-BYz490un.js} +2 -2
  197. package/dashboard/dist/assets/{tasks-Crk9Y3C4.js.map → tasks-BYz490un.js.map} +1 -1
  198. package/dashboard/dist/assets/{topics-CtfcCyw9.js → topics-Dt975EWi.js} +2 -2
  199. package/dashboard/dist/assets/{topics-CtfcCyw9.js.map → topics-Dt975EWi.js.map} +1 -1
  200. package/dashboard/dist/assets/{useEventHooks-Dn_vN2xE.js → useEventHooks-ZT6RV2Gj.js} +2 -2
  201. package/dashboard/dist/assets/{useEventHooks-Dn_vN2xE.js.map → useEventHooks-ZT6RV2Gj.js.map} +1 -1
  202. package/dashboard/dist/assets/{useNamespace-Cfs3vKWk.js → useNamespace-B_G1iE9i.js} +2 -2
  203. package/dashboard/dist/assets/{useNamespace-Cfs3vKWk.js.map → useNamespace-B_G1iE9i.js.map} +1 -1
  204. package/dashboard/dist/assets/{useYamlActivityEvents-ymobxH47.js → useYamlActivityEvents-DGkvIadL.js} +2 -2
  205. package/dashboard/dist/assets/{useYamlActivityEvents-ymobxH47.js.map → useYamlActivityEvents-DGkvIadL.js.map} +1 -1
  206. package/dashboard/dist/assets/{users-DngGIiC_.js → users-C2jopvM1.js} +2 -2
  207. package/dashboard/dist/assets/{users-DngGIiC_.js.map → users-C2jopvM1.js.map} +1 -1
  208. package/dashboard/dist/assets/{vendor-icons-DOIDKgo6.js → vendor-icons-BXhWQC7l.js} +161 -121
  209. package/dashboard/dist/assets/vendor-icons-BXhWQC7l.js.map +1 -0
  210. package/dashboard/dist/assets/{workflows-DuUspMAl.js → workflows-By8Wgvig.js} +2 -2
  211. package/dashboard/dist/assets/{workflows-DuUspMAl.js.map → workflows-By8Wgvig.js.map} +1 -1
  212. package/dashboard/dist/assets/{yaml-workflows-DXQCiOsP.js → yaml-workflows-Cq_vp41d.js} +2 -2
  213. package/dashboard/dist/assets/{yaml-workflows-DXQCiOsP.js.map → yaml-workflows-Cq_vp41d.js.map} +1 -1
  214. package/dashboard/dist/index.html +3 -3
  215. package/docs/api/http/escalations.md +20 -0
  216. package/docs/api/sdk/escalations.md +37 -2
  217. package/docs/dashboard.md +16 -3
  218. package/docs/data.md +1 -1
  219. package/docs/hitl-guide.md +240 -21
  220. package/docs/maintenance.md +6 -3
  221. package/docs/oauth-and-delegation.md +1 -1
  222. package/package.json +3 -3
  223. package/dashboard/dist/assets/AvailableEscalationsPage-DDwAgklw.js +0 -2
  224. package/dashboard/dist/assets/AvailableEscalationsPage-DDwAgklw.js.map +0 -1
  225. package/dashboard/dist/assets/CustomDurationPicker-OKlwH5a_.js +0 -2
  226. package/dashboard/dist/assets/CustomDurationPicker-OKlwH5a_.js.map +0 -1
  227. package/dashboard/dist/assets/DataTable-ZWgVQg7F.js +0 -2
  228. package/dashboard/dist/assets/DataTable-ZWgVQg7F.js.map +0 -1
  229. package/dashboard/dist/assets/EscalationSchemaPage-Br5sD8-N.js +0 -9
  230. package/dashboard/dist/assets/EscalationSchemaPage-Br5sD8-N.js.map +0 -1
  231. package/dashboard/dist/assets/EventTable-BARJeiS2.js +0 -2
  232. package/dashboard/dist/assets/EventTable-BARJeiS2.js.map +0 -1
  233. package/dashboard/dist/assets/McpRunDetailPage-BzzZIXIk.js +0 -2
  234. package/dashboard/dist/assets/OperationsPage-BaM-QDhy.js +0 -2
  235. package/dashboard/dist/assets/OperationsPage-BaM-QDhy.js.map +0 -1
  236. package/dashboard/dist/assets/OperatorDashboard-BqJn8wEZ.js +0 -2
  237. package/dashboard/dist/assets/PageHeader-DJo7yMUR.js +0 -2
  238. package/dashboard/dist/assets/PageHeader-DJo7yMUR.js.map +0 -1
  239. package/dashboard/dist/assets/RoleDetailPage-aR-ror5v.js +0 -11
  240. package/dashboard/dist/assets/RoleDetailPage-aR-ror5v.js.map +0 -1
  241. package/dashboard/dist/assets/StatusBadge-DZ9137bI.js.map +0 -1
  242. package/dashboard/dist/assets/TopicsPage-B6fn7fFh.js +0 -2
  243. package/dashboard/dist/assets/WorkflowExecutionPage-BFq7UdhA.js +0 -2
  244. package/dashboard/dist/assets/WorkflowExecutionPage-BFq7UdhA.js.map +0 -1
  245. package/dashboard/dist/assets/escalation-CK8ElYzD.js +0 -2
  246. package/dashboard/dist/assets/escalation-CK8ElYzD.js.map +0 -1
  247. package/dashboard/dist/assets/escalation-columns-Dyrf6Tdp.js +0 -2
  248. package/dashboard/dist/assets/index-BdqKh0UK.css +0 -1
  249. package/dashboard/dist/assets/index-OV1JoB_P.js +0 -6
  250. package/dashboard/dist/assets/index-OV1JoB_P.js.map +0 -1
  251. package/dashboard/dist/assets/index-ZBj6Xgim.js +0 -2
  252. package/dashboard/dist/assets/index-ZBj6Xgim.js.map +0 -1
  253. package/dashboard/dist/assets/roles-D4Wn7kE9.js +0 -2
  254. package/dashboard/dist/assets/roles-D4Wn7kE9.js.map +0 -1
  255. package/dashboard/dist/assets/useCollapsedSections-BU5HULGs.js +0 -2
  256. package/dashboard/dist/assets/useCollapsedSections-BU5HULGs.js.map +0 -1
  257. package/dashboard/dist/assets/vendor-icons-DOIDKgo6.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"AvailableEscalationsPage-DDwAgklw.js","sources":["../../src/lib/facet-url.ts","../../src/pages/operator/FacetedFilterPanel.tsx","../../src/components/common/modal/BulkActionBar.tsx","../../src/components/common/modal/BulkAssignModal.tsx","../../src/components/common/modal/BulkTriageModal.tsx","../../src/pages/operator/helpers.ts","../../src/pages/operator/ClaimModal.tsx","../../src/pages/operator/AvailableEscalationsPage.tsx"],"sourcesContent":["import type { FacetFilters } from '../api/escalations';\n\n// The faceted query is DEEP-LINKED: every element lives in the URL as a JSON-encoded\n// search param (the same names the API/route use), so a shared link reproduces the\n// exact query and back/forward navigation restores it.\n\nconst parse = (v: string | null): any => {\n if (!v) return undefined;\n try { return JSON.parse(v); } catch { return undefined; }\n};\n\nconst isEmpty = (v: unknown): boolean =>\n v == null ||\n (Array.isArray(v) && v.length === 0) ||\n (typeof v === 'object' && !Array.isArray(v) && Object.keys(v as object).length === 0);\n\n/** Read the faceted query from URL search params. */\nexport function parseFacetParams(sp: URLSearchParams): FacetFilters {\n const f: FacetFilters = {};\n const facets = parse(sp.get('facets')); if (!isEmpty(facets)) f.facets = facets;\n const block = parse(sp.get('block')); if (!isEmpty(block)) f.block = block;\n const range = parse(sp.get('range')); if (!isEmpty(range)) f.range = range;\n const exists = parse(sp.get('exists')); if (!isEmpty(exists)) f.exists = exists;\n const roles = parse(sp.get('roles')); if (!isEmpty(roles)) f.roles = roles;\n const orderBy = parse(sp.get('orderBy')); if (!isEmpty(orderBy)) f.orderBy = orderBy;\n if (sp.get('available') != null) f.available = sp.get('available') === 'true';\n return f;\n}\n\n/** Write the faceted query onto URL search params (deleting empty elements). */\nexport function writeFacetParams(p: URLSearchParams, f: FacetFilters): void {\n const set = (k: string, v: unknown) => (isEmpty(v) ? p.delete(k) : p.set(k, JSON.stringify(v)));\n set('facets', f.facets);\n set('block', f.block);\n set('range', f.range);\n set('exists', f.exists);\n set('roles', f.roles);\n set('orderBy', f.orderBy);\n if (f.available == null) p.delete('available'); else p.set('available', String(f.available));\n}\n\n/** Count of active facet conditions (for the trigger badge). */\nexport function facetCount(f: FacetFilters): number {\n return (\n Object.keys(f.facets ?? {}).length +\n (f.block?.length ?? 0) +\n (f.range?.length ?? 0) +\n (f.exists?.length ?? 0) +\n (f.orderBy?.length ?? 0) +\n (f.available != null ? 1 : 0)\n );\n}\n","import type { FacetFilters, FacetRange, FacetOrder } from '../../api/escalations';\n\nconst RANGE_OPS: FacetRange['op'][] = ['<', '<=', '>', '>=', '='];\nconst SORT_COLUMNS = ['priority', 'created_at', 'updated_at', 'status', 'role'];\n\nconst inputCls =\n 'h-7 rounded border border-surface-border bg-surface px-2 text-xs text-text-primary focus:border-accent focus:outline-none';\nconst xBtn = 'text-text-tertiary hover:text-text-primary transition-colors';\n\n/** A facet value is JSONB-containment-sensitive: 0.65 (number) ≠ \"0.65\" (string). */\nfunction coerce(v: string): unknown {\n if (v === 'true') return true;\n if (v === 'false') return false;\n if (v.trim() !== '' && !Number.isNaN(Number(v))) return Number(v);\n return v;\n}\n\ntype KV = { key: string; value: string };\nconst recordRows = (rec?: Record<string, unknown>): KV[] =>\n Object.entries(rec ?? {}).map(([key, value]) => ({ key, value: String(value) }));\nconst blockRows = (arr?: Record<string, unknown>[]): KV[] =>\n (arr ?? []).map((o) => {\n const [key, value] = Object.entries(o)[0] ?? ['', ''];\n return { key, value: String(value) };\n });\n\nfunction Section({ title, hint, children }: { title: string; hint?: string; children: React.ReactNode }) {\n return (\n <div className=\"border-t border-surface-border/50 py-3 first:border-t-0 first:pt-1\">\n <div className=\"mb-1.5 flex items-baseline justify-between\">\n <span className=\"text-[11px] font-medium uppercase tracking-wide text-text-tertiary\">{title}</span>\n {hint && <span className=\"text-[10px] font-mono text-text-tertiary/70\">{hint}</span>}\n </div>\n {children}\n </div>\n );\n}\n\nfunction KeyInput({ value, onChange, placeholder }: {\n value: string; onChange: (v: string) => void; placeholder: string;\n}) {\n return (\n <input\n list=\"lt-facet-keys\" className={`${inputCls} w-40`} placeholder={placeholder}\n value={value} onChange={(e) => onChange(e.target.value)}\n />\n );\n}\n\n/**\n * Faceted query editor — the advanced operations surface (rendered inside the\n * slide-out drawer). Controlled: edits a FacetFilters value. `facetKeys` are the\n * metadata keys that actually exist in the caller's rows (from listFacetKeys), so\n * the UI never offers a non-existent facet.\n */\nexport function FacetedFilterPanel({ value, onChange, facetKeys = [], search = '', onSearchChange }: {\n value: FacetFilters;\n onChange: (next: FacetFilters) => void;\n facetKeys?: string[];\n /** Correlation-id term — exact match on escalation id / workflow id / origin id, composed\n * with the facets in the same SQL query. Not a substring search; for values inside metadata\n * use a facet. */\n search?: string;\n onSearchChange?: (next: string) => void;\n}) {\n const facets = recordRows(value.facets);\n const exclude = blockRows(value.block);\n const ranges = value.range ?? [];\n const exists = value.exists ?? [];\n const sorts = value.orderBy ?? [];\n\n const setFacets = (rows: KV[]) => {\n const rec: Record<string, unknown> = {};\n for (const r of rows) if (r.key) rec[r.key] = coerce(r.value);\n onChange({ ...value, facets: Object.keys(rec).length ? rec : undefined });\n };\n const setBlock = (rows: KV[]) => {\n const arr = rows.filter((r) => r.key).map((r) => ({ [r.key]: coerce(r.value) }));\n onChange({ ...value, block: arr.length ? arr : undefined });\n };\n const setRange = (r: FacetRange[]) => onChange({ ...value, range: r.length ? r : undefined });\n const setExists = (e: string[]) => onChange({ ...value, exists: e.length ? e : undefined });\n const setSorts = (o: FacetOrder[]) => onChange({ ...value, orderBy: o.length ? o : undefined });\n\n return (\n <div className=\"text-xs\">\n {/* Autocomplete sources rendered once (shared by all rows). */}\n <datalist id=\"lt-facet-keys\">\n {facetKeys.map((k) => <option key={k} value={k} />)}\n </datalist>\n <datalist id=\"lt-sort-fields\">\n {SORT_COLUMNS.map((c) => <option key={c} value={c} />)}\n {facetKeys.map((k) => <option key={k} value={`metadata.${k}`} />)}\n </datalist>\n\n {onSearchChange && (\n <Section title=\"Match id\" hint=\"id · workflow · origin\">\n <input\n className={`${inputCls} w-full`}\n placeholder=\"Exact escalation, workflow, or origin id…\"\n value={search}\n onChange={(e) => onSearchChange(e.target.value)}\n />\n </Section>\n )}\n\n <Section title=\"Has facet\" hint=\"metadata @>\">\n {[...facets, { key: '', value: '' }].map((row, i) => (\n <div key={i} className=\"mb-1 flex items-center gap-1\">\n <KeyInput value={row.key} placeholder=\"key\"\n onChange={(k) => { const next = [...facets]; next[i] = { ...row, key: k }; setFacets(next); }} />\n <span className=\"text-text-tertiary\">=</span>\n <input className={`${inputCls} w-40`} placeholder=\"value\" value={row.value}\n onChange={(e) => { const next = [...facets]; next[i] = { ...row, value: e.target.value }; setFacets(next); }} />\n {i < facets.length && (\n <button className={xBtn} onClick={() => setFacets(facets.filter((_, j) => j !== i))}>×</button>\n )}\n </div>\n ))}\n </Section>\n\n <Section title=\"Range\" hint=\"numeric\">\n {[...ranges, { facet: '', op: '<=' as const, value: 0 }].map((r, i) => (\n <div key={i} className=\"mb-1 flex items-center gap-1\">\n <KeyInput value={r.facet} placeholder=\"numeric facet\"\n onChange={(f) => { const next = [...ranges]; next[i] = { ...r, facet: f }; setRange(next.filter((x) => x.facet)); }} />\n <select className={inputCls} value={r.op}\n onChange={(e) => { const next = [...ranges]; next[i] = { ...r, op: e.target.value as FacetRange['op'] }; setRange(next.filter((x) => x.facet)); }}>\n {RANGE_OPS.map((o) => <option key={o} value={o}>{o}</option>)}\n </select>\n <input type=\"number\" className={`${inputCls} w-24`} value={r.value}\n onChange={(e) => { const next = [...ranges]; next[i] = { ...r, value: Number(e.target.value) }; setRange(next.filter((x) => x.facet)); }} />\n {i < ranges.length && (\n <button className={xBtn} onClick={() => setRange(ranges.filter((_, j) => j !== i))}>×</button>\n )}\n </div>\n ))}\n </Section>\n\n <Section title=\"Has key\" hint=\"metadata ? key\">\n <div className=\"flex flex-wrap items-center gap-1\">\n {exists.map((k) => (\n <span key={k} className=\"flex items-center gap-1 rounded bg-accent/15 px-1.5 py-0.5 text-accent\">\n {k}<button className=\"text-accent/70 hover:text-accent\" onClick={() => setExists(exists.filter((x) => x !== k))}>×</button>\n </span>\n ))}\n <KeyInput value=\"\" placeholder=\"+ key\"\n onChange={(k) => { if (k && !exists.includes(k)) setExists([...exists, k]); }} />\n </div>\n </Section>\n\n <Section title=\"Exclude\" hint=\"NOT @>\">\n {[...exclude, { key: '', value: '' }].map((row, i) => (\n <div key={i} className=\"mb-1 flex items-center gap-1\">\n <KeyInput value={row.key} placeholder=\"key\"\n onChange={(k) => { const next = [...exclude]; next[i] = { ...row, key: k }; setBlock(next); }} />\n <span className=\"text-text-tertiary\">=</span>\n <input className={`${inputCls} w-40`} placeholder=\"value\" value={row.value}\n onChange={(e) => { const next = [...exclude]; next[i] = { ...row, value: e.target.value }; setBlock(next); }} />\n {i < exclude.length && (\n <button className={xBtn} onClick={() => setBlock(exclude.filter((_, j) => j !== i))}>×</button>\n )}\n </div>\n ))}\n </Section>\n\n <Section title=\"Sort by\">\n {[...sorts, { field: '', direction: 'asc' as const }].map((s, i) => (\n <div key={i} className=\"mb-1 flex items-center gap-1\">\n <input list=\"lt-sort-fields\" className={`${inputCls} w-44`} placeholder=\"column or metadata.key\"\n value={s.field}\n onChange={(e) => { const next = [...sorts]; next[i] = { ...s, field: e.target.value }; setSorts(next.filter((x) => x.field)); }} />\n <select className={inputCls} value={s.direction ?? 'asc'}\n onChange={(e) => { const next = [...sorts]; next[i] = { ...s, direction: e.target.value as 'asc' | 'desc' }; setSorts(next.filter((x) => x.field)); }}>\n <option value=\"asc\">asc</option><option value=\"desc\">desc</option>\n </select>\n <label className=\"flex items-center gap-1 text-text-tertiary\">\n <input type=\"checkbox\" checked={!!s.numeric}\n onChange={(e) => { const next = [...sorts]; next[i] = { ...s, numeric: e.target.checked }; setSorts(next.filter((x) => x.field)); }} />\n num\n </label>\n {i < sorts.length && (\n <button className={xBtn} onClick={() => setSorts(sorts.filter((_, j) => j !== i))}>×</button>\n )}\n </div>\n ))}\n </Section>\n </div>\n );\n}\n","import { PRIORITY_OPTIONS } from '../../../lib/constants';\nimport { useClaimDurations } from '../../../hooks/useClaimDurations';\nimport { useSettings } from '../../../api/settings';\n\ninterface BulkActionBarProps {\n selectedCount: number;\n onClearSelection: () => void;\n onSetPriority: (priority: 1 | 2 | 3 | 4) => void;\n onClaim: (durationMinutes: number) => void;\n onAssign: () => void;\n onEscalate: (targetRole: string) => void;\n onTriage: () => void;\n onCancel: () => void;\n isPriorityPending: boolean;\n isClaimPending: boolean;\n isAssignPending: boolean;\n isEscalatePending: boolean;\n isTriagePending: boolean;\n isCancelPending: boolean;\n availableRoles: string[];\n}\n\nconst anyPending = (props: BulkActionBarProps) =>\n props.isPriorityPending || props.isClaimPending || props.isAssignPending || props.isEscalatePending || props.isTriagePending || props.isCancelPending;\n\n// One control chrome for the whole bar — white pill-free buttons on the band,\n// hairline border, a barely-there 3px radius (square reads timeless, not dated),\n// definition on hover. Selects share it so the toolbar is one cohesive set.\nconst CTRL =\n 'inline-flex items-center h-7 px-2.5 text-[11px] font-medium text-text-secondary bg-surface border border-surface-border rounded-[4px] hover:border-accent/50 hover:text-text-primary transition-colors disabled:opacity-50 disabled:hover:border-surface-border';\nconst SELECT = `${CTRL} appearance-none cursor-pointer`;\nconst DANGER =\n 'inline-flex items-center h-7 px-2.5 text-[11px] font-medium text-status-error bg-surface border border-status-error/30 rounded-[4px] hover:border-status-error hover:bg-status-error/5 transition-colors disabled:opacity-50';\n\nexport function BulkActionBar(props: BulkActionBarProps) {\n const disabled = anyPending(props);\n const claimDurations = useClaimDurations();\n // Triage is an LLM action. `useSettings().ai.enabled` is the single source of\n // truth — it merges the server /settings flag with the persisted localStorage\n // override (lt_ai_override). Hide the button entirely when AI is off.\n const { data: settings } = useSettings();\n const aiEnabled = settings?.ai?.enabled === true;\n const open = props.selectedCount > 0;\n\n return (\n // Animated reveal — grows and opacity-fades in/out with ease-in-out as the\n // selection changes. Always mounted so it can animate on exit, not just enter.\n <div\n className={`grid transition-all duration-200 ease-in-out ${\n open ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0 pointer-events-none'\n }`}\n >\n <div className=\"overflow-hidden\">\n {/* Contextual band: neutral fill + a 2px accent left rule anchors it as a\n distinct \"selection mode\" surface without a rounded card. */}\n <div className=\"flex flex-wrap items-center gap-2 py-2.5 pl-3 pr-2 mt-4 mb-3 bg-surface-sunken/60 border-l-2 border-l-accent\">\n <span className=\"text-[11px] font-semibold uppercase tracking-wider text-accent tabular-nums\">\n {props.selectedCount} selected\n </span>\n\n <div className=\"mx-1 h-4 w-px bg-surface-border\" />\n\n {/* Priority */}\n <select\n onChange={(e) => {\n if (!e.target.value) return;\n props.onSetPriority(parseInt(e.target.value) as 1 | 2 | 3 | 4);\n e.target.value = '';\n }}\n disabled={disabled}\n className={SELECT}\n defaultValue=\"\"\n >\n <option value=\"\" disabled>Priority…</option>\n {PRIORITY_OPTIONS.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n\n {/* Claim */}\n <select\n onChange={(e) => {\n if (!e.target.value) return;\n props.onClaim(parseInt(e.target.value));\n e.target.value = '';\n }}\n disabled={disabled}\n className={SELECT}\n defaultValue=\"\"\n >\n <option value=\"\" disabled>Claim for…</option>\n {claimDurations.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n\n {/* Assign */}\n <button onClick={props.onAssign} disabled={disabled} className={CTRL}>\n {props.isAssignPending ? 'Assigning…' : 'Assign to…'}\n </button>\n\n {/* Escalate */}\n {props.availableRoles.length > 0 && (\n <select\n onChange={(e) => {\n if (!e.target.value) return;\n props.onEscalate(e.target.value);\n e.target.value = '';\n }}\n disabled={disabled}\n className={SELECT}\n defaultValue=\"\"\n >\n <option value=\"\" disabled>Escalate to…</option>\n {props.availableRoles.map((role) => (\n <option key={role} value={role}>{role}</option>\n ))}\n </select>\n )}\n\n {/* Triage — LLM-powered, shown only when AI is enabled */}\n {aiEnabled && (\n <button onClick={props.onTriage} disabled={disabled} className={CTRL}>\n {props.isTriagePending ? 'Triaging…' : 'Triage'}\n </button>\n )}\n\n {/* Cancel */}\n <button onClick={props.onCancel} disabled={disabled} className={DANGER}>\n {props.isCancelPending ? 'Cancelling…' : 'Cancel'}\n </button>\n\n <div className=\"flex-1\" />\n\n {disabled && (\n <span className=\"text-[11px] text-text-tertiary animate-pulse\">Processing…</span>\n )}\n\n {/* Clear */}\n <button\n onClick={props.onClearSelection}\n className=\"px-1 text-[11px] font-medium text-text-tertiary hover:text-text-primary transition-colors\"\n >\n Clear\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import { useState, useCallback } from 'react';\nimport { Modal } from './Modal';\nimport { CustomDurationPicker } from '../form/CustomDurationPicker';\nimport { useUsers } from '../../../api/users';\nimport { useAuth } from '../../../hooks/useAuth';\nimport { useClaimDurations } from '../../../hooks/useClaimDurations';\nimport { useDebouncedValue } from '../../../hooks/useDebouncedValue';\nimport type { LTUserRecord } from '../../../api/types';\n\ninterface BulkAssignModalProps {\n open: boolean;\n onClose: () => void;\n selectedCount: number;\n /** Distinct roles of the selected escalations; scopes user list for admins */\n selectedRoles: string[];\n onSubmit: (targetUserId: string, durationMinutes: number) => void;\n isPending: boolean;\n}\n\nexport function BulkAssignModal({\n open,\n onClose,\n selectedCount,\n selectedRoles,\n onSubmit,\n isPending,\n}: BulkAssignModalProps) {\n const { isSuperAdmin } = useAuth();\n const claimDurations = useClaimDurations();\n const [step, setStep] = useState<'user' | 'duration'>('user');\n const [selectedUser, setSelectedUser] = useState<LTUserRecord | null>(null);\n const [search, setSearch] = useState('');\n const [duration, setDuration] = useState('30');\n const [customMinutes, setCustomMinutes] = useState(0);\n const onCustomChange = useCallback((m: number) => setCustomMinutes(m), []);\n\n // Admins with a single role: scope to that role. Otherwise show all active users.\n const roleFilter =\n !isSuperAdmin && selectedRoles.length === 1 ? selectedRoles[0] : undefined;\n\n // Search is resolved server-side (ILIKE on name/email/external_id) so it matches\n // every user, not just a fetched slice — no client-side filtering over a cap.\n const debouncedSearch = useDebouncedValue(search, 250);\n const { data: usersData, isLoading: usersLoading } = useUsers({\n role: roleFilter,\n status: 'active',\n search: debouncedSearch.trim() || undefined,\n limit: 200,\n });\n\n const users = usersData?.users ?? [];\n\n const handleClose = () => {\n setStep('user');\n setSelectedUser(null);\n setSearch('');\n setDuration('30');\n setCustomMinutes(0);\n onClose();\n };\n\n const handleSelectUser = (user: LTUserRecord) => {\n setSelectedUser(user);\n setStep('duration');\n };\n\n const handleBack = () => {\n setStep('user');\n };\n\n const handleSubmit = () => {\n if (!selectedUser) return;\n const minutes = duration === 'custom' ? customMinutes : parseInt(duration);\n if (!minutes || minutes <= 0) return;\n onSubmit(selectedUser.id, minutes);\n };\n\n return (\n <Modal open={open} onClose={handleClose} title=\"Assign Escalations\">\n <div className=\"space-y-4\">\n {step === 'user' && (\n <>\n <p className=\"text-sm text-text-secondary\">\n Select a user to assign{' '}\n <span className=\"font-medium text-text-primary\">\n {selectedCount}\n </span>{' '}\n escalation(s) to:\n </p>\n\n <input\n type=\"text\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search by name or email...\"\n className=\"input text-xs w-full\"\n autoFocus\n />\n\n <div className=\"max-h-60 overflow-y-auto border border-surface-border rounded-lg divide-y divide-surface-border\">\n {usersLoading && (\n <p className=\"text-xs text-text-tertiary p-3\">\n Loading users...\n </p>\n )}\n {!usersLoading && users.length === 0 && (\n <p className=\"text-xs text-text-tertiary p-3\">\n No users found\n </p>\n )}\n {users.map((user) => (\n <button\n key={user.id}\n onClick={() => handleSelectUser(user)}\n className=\"w-full text-left px-3 py-2 hover:bg-surface-hover transition-colors\"\n >\n <p className=\"text-xs font-medium text-text-primary\">\n {user.display_name || user.external_id}\n </p>\n {user.email && (\n <p className=\"text-[10px] text-text-tertiary\">\n {user.email}\n </p>\n )}\n </button>\n ))}\n </div>\n\n <div className=\"flex justify-end pt-2\">\n <button onClick={handleClose} className=\"btn-secondary text-xs\">\n Cancel\n </button>\n </div>\n </>\n )}\n\n {step === 'duration' && selectedUser && (\n <>\n <p className=\"text-sm text-text-secondary\">\n Assign to{' '}\n <span className=\"font-medium text-text-primary\">\n {selectedUser.display_name || selectedUser.external_id}\n </span>{' '}\n for:\n </p>\n\n <select\n value={duration}\n onChange={(e) => { setDuration(e.target.value); setCustomMinutes(0); }}\n className=\"select w-full text-sm\"\n >\n {claimDurations.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n <option value=\"custom\">Other...</option>\n </select>\n {duration === 'custom' && (\n <CustomDurationPicker onChange={onCustomChange} autoFocus />\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={handleBack} className=\"btn-secondary text-xs\">\n Back\n </button>\n <button\n onClick={handleSubmit}\n disabled={isPending}\n className=\"btn-primary text-xs\"\n >\n {isPending ? 'Assigning...' : 'Assign'}\n </button>\n </div>\n </>\n )}\n </div>\n </Modal>\n );\n}\n","import { useState } from 'react';\nimport { Modal } from './Modal';\n\ninterface BulkTriageModalProps {\n open: boolean;\n onClose: () => void;\n selectedCount: number;\n onSubmit: (hint?: string) => void;\n isPending: boolean;\n}\n\nexport function BulkTriageModal({\n open,\n onClose,\n selectedCount,\n onSubmit,\n isPending,\n}: BulkTriageModalProps) {\n const [hint, setHint] = useState('');\n\n const handleSubmit = () => {\n onSubmit(hint || undefined);\n };\n\n return (\n <Modal open={open} onClose={onClose} title=\"Submit for AI Triage\">\n <div className=\"space-y-4\">\n <p className=\"text-sm text-text-secondary\">\n Submit <span className=\"font-medium text-text-primary\">{selectedCount}</span> escalation(s)\n for AI triage? The triage orchestrator will take over resolution.\n </p>\n\n <div>\n <label className=\"text-xs font-medium text-text-secondary block mb-1\">\n Triage hint <span className=\"text-text-tertiary\">(optional)</span>\n </label>\n <input\n type=\"text\"\n value={hint}\n onChange={(e) => setHint(e.target.value)}\n placeholder=\"e.g., image_orientation\"\n className=\"input text-xs font-mono w-full\"\n />\n <p className=\"text-[10px] text-text-tertiary mt-1\">\n Guides the triage workflow on what remediation to apply\n </p>\n </div>\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={onClose} className=\"btn-secondary text-xs\">\n Cancel\n </button>\n <button\n onClick={handleSubmit}\n disabled={isPending}\n className=\"btn-primary text-xs\"\n >\n {isPending ? 'Submitting...' : 'Submit for Triage'}\n </button>\n </div>\n </div>\n </Modal>\n );\n}\n","import type { UseMutationResult } from '@tanstack/react-query';\n\n/**\n * Create a bulk-action handler that calls a mutation and clears selection on success.\n */\nfunction bulkHandler<TData, TVariables>(\n mutation: UseMutationResult<TData, Error, TVariables>,\n clearSelection: () => void,\n afterSuccess?: () => void,\n) {\n return (variables: TVariables) => {\n mutation.mutate(variables, {\n onSuccess: () => {\n clearSelection();\n afterSuccess?.();\n },\n });\n };\n}\n\nexport function createBulkHandlers(deps: {\n selectedIds: Set<string>;\n clearSelection: () => void;\n setPriority: UseMutationResult<{ updated: number }, Error, { ids: string[]; priority: 1 | 2 | 3 | 4 }>;\n bulkClaim: UseMutationResult<{ claimed: number; skipped: number }, Error, { ids: string[]; durationMinutes: number }>;\n bulkEscalate: UseMutationResult<{ updated: number }, Error, { ids: string[]; targetRole: string }>;\n bulkTriage: UseMutationResult<{ triaged: number }, Error, { ids: string[]; hint?: string }>;\n bulkAssign: UseMutationResult<{ assigned: number; skipped: number }, Error, { ids: string[]; targetUserId: string; durationMinutes: number }>;\n bulkCancel: UseMutationResult<{ cancelled: number; skipped: number }, Error, { ids: string[] }>;\n closeTriageModal: () => void;\n closeAssignModal: () => void;\n closeCancelModal: () => void;\n}) {\n const ids = () => [...deps.selectedIds];\n\n const handleSetPriority = (priority: 1 | 2 | 3 | 4) => {\n bulkHandler(\n deps.setPriority,\n deps.clearSelection,\n )({ ids: ids(), priority });\n };\n\n const handleBulkClaim = (durationMinutes: number) => {\n bulkHandler(\n deps.bulkClaim,\n deps.clearSelection,\n )({ ids: ids(), durationMinutes });\n };\n\n const handleBulkEscalate = (targetRole: string) => {\n bulkHandler(\n deps.bulkEscalate,\n deps.clearSelection,\n )({ ids: ids(), targetRole });\n };\n\n const handleBulkTriage = (hint?: string) => {\n bulkHandler(\n deps.bulkTriage,\n deps.clearSelection,\n deps.closeTriageModal,\n )({ ids: ids(), hint });\n };\n\n const handleBulkAssign = (targetUserId: string, durationMinutes: number) => {\n bulkHandler(\n deps.bulkAssign,\n deps.clearSelection,\n deps.closeAssignModal,\n )({ ids: ids(), targetUserId, durationMinutes });\n };\n\n const handleBulkCancel = () => {\n bulkHandler(\n deps.bulkCancel,\n deps.clearSelection,\n deps.closeCancelModal,\n )({ ids: ids() });\n };\n\n return { handleSetPriority, handleBulkClaim, handleBulkEscalate, handleBulkTriage, handleBulkAssign, handleBulkCancel };\n}\n","import { Modal } from '../../components/common/modal/Modal';\nimport { CustomDurationPicker } from '../../components/common/form/CustomDurationPicker';\nimport type { LTEscalationRecord } from '../../api/types';\n\ninterface ClaimModalProps {\n claimTarget: LTEscalationRecord | null;\n onClose: () => void;\n claimDuration: string;\n onDurationChange: (value: string) => void;\n claimDurations: Array<{ value: string; label: string }>;\n customClaimMinutes: number;\n onCustomClaimChange: (minutes: number) => void;\n onClaim: () => void;\n isPending: boolean;\n}\n\nexport function ClaimModal({\n claimTarget,\n onClose,\n claimDuration,\n onDurationChange,\n claimDurations,\n onCustomClaimChange,\n onClaim,\n isPending,\n}: ClaimModalProps) {\n return (\n <Modal\n open={!!claimTarget}\n onClose={onClose}\n title=\"Claim Escalation\"\n >\n <div className=\"space-y-4\">\n <p className=\"text-sm text-text-secondary\">\n Claim <span className=\"font-medium text-text-primary\">{claimTarget?.type}</span> for:\n </p>\n <select\n value={claimDuration}\n onChange={(e) => { onDurationChange(e.target.value); }}\n className=\"select w-full text-sm\"\n >\n {claimDurations.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n <option value=\"custom\">Other...</option>\n </select>\n {claimDuration === 'custom' && (\n <CustomDurationPicker onChange={onCustomClaimChange} autoFocus />\n )}\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={onClose} className=\"btn-secondary text-xs\">\n Cancel\n </button>\n <button\n onClick={onClaim}\n className=\"btn-primary text-xs\"\n disabled={isPending}\n >\n {isPending ? 'Claiming...' : 'Claim'}\n </button>\n </div>\n </div>\n </Modal>\n );\n}\n","import { useState, useEffect, useMemo, useCallback } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useNavigate, useSearchParams } from 'react-router-dom';\nimport { parseFacetParams, writeFacetParams, facetCount } from '../../lib/facet-url';\nimport { useAccess } from '../../hooks/useAccess';\nimport { useEscalationListEvents } from '../../hooks/useEventHooks';\nimport {\n useEscalations,\n useAvailableEscalations,\n useEscalationTypes,\n useFacetKeys,\n useClaimEscalation,\n useSetEscalationPriority,\n useBulkClaimEscalations,\n useBulkAssignEscalations,\n useBulkEscalateToRole,\n useBulkTriageEscalations,\n useBulkCancelEscalations,\n type FacetFilters,\n} from '../../api/escalations';\nimport { FacetedFilterPanel } from './FacetedFilterPanel';\nimport { ConfirmCancelModal } from '../../components/common/modal/ConfirmCancelModal';\nimport { useRoles } from '../../api/roles';\nimport { useFilterParams } from '../../hooks/useFilterParams';\nimport { useDebouncedValue } from '../../hooks/useDebouncedValue';\nimport { buildApiPath } from '../../lib/api-path';\nimport { DataTable, type Column } from '../../components/common/data/DataTable';\nimport { StickyPagination } from '../../components/common/data/StickyPagination';\nimport { PageHeader } from '../../components/common/layout/PageHeader';\nimport { BulkActionBar } from '../../components/common/modal/BulkActionBar';\nimport { BulkAssignModal } from '../../components/common/modal/BulkAssignModal';\nimport { BulkTriageModal } from '../../components/common/modal/BulkTriageModal';\nimport { useClaimDurations } from '../../hooks/useClaimDurations';\nimport { Lock, SlidersHorizontal, X } from 'lucide-react';\nimport { ESCALATION_COLUMNS, EscalationFilterBar } from './escalation-columns';\nimport { RowAction, RowActionGroup } from '../../components/common/layout/RowActions';\nimport { ListToolbar } from '../../components/common/data/ListToolbar';\nimport { createBulkHandlers } from './helpers';\nimport { ClaimModal } from './ClaimModal';\nimport type { LTEscalationRecord } from '../../api/types';\n\nexport function AvailableEscalationsPage() {\n useEscalationListEvents();\n const navigate = useNavigate();\n const { filters, setFilter, pagination, sort, setSort } = useFilterParams({\n filters: { role: '', type: '', priority: '', status: 'available', search: '' },\n });\n // Debounce so server-side search fires once the user pauses, not per keystroke.\n const debouncedSearch = useDebouncedValue(filters.search, 300);\n const claimDurations = useClaimDurations();\n const [claimTarget, setClaimTarget] = useState<LTEscalationRecord | null>(null);\n const [claimDuration, setClaimDuration] = useState('30');\n const [customClaimMinutes, setCustomClaimMinutes] = useState(0);\n const onCustomClaimChange = useCallback((m: number) => setCustomClaimMinutes(m), []);\n const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());\n // Faceted query — DEEP-LINKED in the URL (a shared link reproduces the exact query).\n // The drawer is the editor surface; fetched keys feed the autocomplete.\n const [facetDrawerOpen, setFacetDrawerOpen] = useState(false);\n const [searchParams, setSearchParams] = useSearchParams();\n const facetFilters = useMemo<FacetFilters>(() => parseFacetParams(searchParams), [searchParams]);\n const setFacetFilters = useCallback((next: FacetFilters) => {\n setSearchParams((prev) => {\n const p = new URLSearchParams(prev);\n writeFacetParams(p, next);\n p.delete('page');\n return p;\n }, { replace: true });\n }, [setSearchParams]);\n const { data: facetKeysData } = useFacetKeys(facetDrawerOpen);\n // The free-text term now lives in the drawer alongside the facets, so it counts\n // toward the active-query badge and is cleared by the drawer's Clear.\n const activeFacetCount = facetCount(facetFilters) + (filters.search ? 1 : 0);\n const [triageModalOpen, setTriageModalOpen] = useState(false);\n const [assignModalOpen, setAssignModalOpen] = useState(false);\n const [cancelModalOpen, setCancelModalOpen] = useState(false);\n\n const claim = useClaimEscalation();\n const setPriority = useSetEscalationPriority();\n const bulkClaim = useBulkClaimEscalations();\n const bulkAssign = useBulkAssignEscalations();\n const bulkEscalate = useBulkEscalateToRole();\n const bulkTriage = useBulkTriageEscalations();\n const bulkCancel = useBulkCancelEscalations();\n const { data: rolesData } = useRoles();\n const { data: typesData } = useEscalationTypes();\n\n // Clear selections on filter/page changes\n useEffect(() => {\n setSelectedIds(new Set());\n }, [filters.role, filters.type, filters.priority, filters.status, debouncedSearch, pagination.page, pagination.pageSize]);\n\n const statusFilter = filters.status || '';\n const isAvailable = statusFilter === 'available';\n const isClaimed = statusFilter === 'claimed';\n // `all` and `available` both send no status filter. `available` additionally routes\n // through the available-only query (pending + unclaimed); `all` spans every status so\n // a metadata facet search returns an order's escalations regardless of where they are.\n const apiStatus = isClaimed ? 'pending'\n : statusFilter === 'resolved' ? 'resolved'\n : statusFilter === 'cancelled' ? 'cancelled'\n : statusFilter === 'expired' ? 'expired'\n : isAvailable ? undefined\n : undefined;\n\n const sharedFilters = {\n role: filters.role || undefined,\n type: filters.type || undefined,\n priority: filters.priority ? parseInt(filters.priority) : undefined,\n limit: pagination.pageSize,\n offset: pagination.offset,\n sort_by: sort.sort_by || 'created_at',\n order: sort.order || 'desc',\n search: debouncedSearch || undefined,\n // Faceted metadata query (composes with role-scope + the basic filters in SQL).\n ...facetFilters,\n };\n\n const availableQuery = useAvailableEscalations({\n ...sharedFilters,\n enabled: isAvailable,\n });\n\n const escalationsQuery = useEscalations({\n status: apiStatus,\n claimed: isClaimed || undefined,\n ...sharedFilters,\n enabled: !isAvailable,\n });\n\n const activeQuery = isAvailable ? availableQuery : escalationsQuery;\n const { data, isLoading, error: queryError, refetch, isFetching } = activeQuery;\n\n // Copy-URL/curl path built from the SAME params the active query sends, so the\n // generated command always reproduces the real request (filters + search + sort).\n const apiPath = buildApiPath(`/escalations${isAvailable ? '/available' : ''}`, {\n status: apiStatus,\n claimed: isClaimed || undefined,\n role: filters.role || undefined,\n type: filters.type || undefined,\n priority: filters.priority || undefined,\n search: debouncedSearch || undefined,\n sort_by: sort.sort_by || 'created_at',\n order: sort.order || 'desc',\n limit: pagination.pageSize,\n offset: pagination.offset,\n // Faceted query — JSON-encoded so the copy-URL/curl reproduces the exact query.\n facets: facetFilters.facets && Object.keys(facetFilters.facets).length ? JSON.stringify(facetFilters.facets) : undefined,\n block: facetFilters.block?.length ? JSON.stringify(facetFilters.block) : undefined,\n range: facetFilters.range?.length ? JSON.stringify(facetFilters.range) : undefined,\n exists: facetFilters.exists?.length ? JSON.stringify(facetFilters.exists) : undefined,\n roles: facetFilters.roles?.length ? JSON.stringify(facetFilters.roles) : undefined,\n orderBy: facetFilters.orderBy?.length ? JSON.stringify(facetFilters.orderBy) : undefined,\n available: facetFilters.available != null ? String(facetFilters.available) : undefined,\n });\n\n // Search is server-side (full result set), so results and total come straight\n // from the query — no client-side filtering of the current page.\n const escalations = data?.escalations ?? [];\n const total = data?.total ?? 0;\n const { canBulk: canBulkManage } = useAccess();\n\n const selectedRoles = useMemo(() => {\n const roles = new Set<string>();\n for (const esc of escalations) {\n if (selectedIds.has(esc.id)) roles.add(esc.role);\n }\n return [...roles];\n }, [escalations, selectedIds]);\n\n const clearSelection = useCallback(() => setSelectedIds(new Set()), []);\n\n const handleClaim = () => {\n if (!claimTarget) return;\n const minutes = claimDuration === 'custom' ? customClaimMinutes : parseInt(claimDuration);\n if (!minutes || minutes <= 0) return;\n claim.mutate(\n { id: claimTarget.id, durationMinutes: minutes },\n {\n onSuccess: () => {\n setClaimTarget(null);\n navigate(`/escalations/detail/${claimTarget.id}`);\n },\n },\n );\n };\n\n const {\n handleSetPriority,\n handleBulkClaim,\n handleBulkEscalate,\n handleBulkTriage,\n handleBulkAssign,\n handleBulkCancel,\n } = createBulkHandlers({\n selectedIds,\n clearSelection,\n setPriority,\n bulkClaim,\n bulkEscalate,\n bulkTriage,\n bulkAssign,\n bulkCancel,\n closeTriageModal: () => setTriageModalOpen(false),\n closeAssignModal: () => setAssignModalOpen(false),\n closeCancelModal: () => setCancelModalOpen(false),\n });\n\n const toggleSelect = (id: string) => {\n const next = new Set(selectedIds);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n setSelectedIds(next);\n };\n\n const toggleAll = () => {\n if (selectedIds.size === escalations.length) {\n setSelectedIds(new Set());\n } else {\n setSelectedIds(new Set(escalations.map((e) => e.id)));\n }\n };\n\n const columns: Column<LTEscalationRecord>[] = [\n canBulkManage ? {\n key: 'select',\n label: (\n <input\n type=\"checkbox\"\n checked={escalations.length > 0 && selectedIds.size === escalations.length}\n onChange={toggleAll}\n className=\"rounded\"\n />\n ) as any,\n render: (row: LTEscalationRecord) => (\n <input\n type=\"checkbox\"\n checked={selectedIds.has(row.id)}\n onChange={(e) => {\n e.stopPropagation();\n toggleSelect(row.id);\n }}\n onClick={(e) => e.stopPropagation()}\n className=\"rounded\"\n />\n ),\n className: 'w-10',\n } : {\n key: 'spacer',\n label: '',\n render: () => null,\n className: 'w-10',\n },\n ...ESCALATION_COLUMNS,\n {\n key: 'actions',\n label: '',\n render: (row) => (\n <RowActionGroup>\n <RowAction\n icon={Lock}\n title=\"Claim escalation\"\n onClick={() => setClaimTarget(row)}\n colorClass=\"text-accent/75 hover:text-accent\"\n size=\"sm\"\n />\n </RowActionGroup>\n ),\n className: 'w-10 text-right',\n },\n ];\n\n return (\n <div>\n <PageHeader title=\"All Escalations\" docsHash=\"#docs:dashboard.md:all-escalations\" />\n\n <EscalationFilterBar\n filters={filters}\n setFilter={setFilter}\n roles={rolesData?.roles ?? []}\n types={typesData?.types ?? []}\n showStatus\n showSearch={false}\n actions={\n <>\n <ListToolbar\n onRefresh={() => refetch()}\n isFetching={isFetching}\n apiPath={apiPath}\n />\n <button\n onClick={() => setFacetDrawerOpen((v) => !v)}\n className=\"relative ml-2 inline-flex h-7 w-7 items-center justify-center rounded text-text-tertiary hover:bg-surface-hover hover:text-text-primary transition-colors\"\n title=\"Faceted query\"\n >\n <SlidersHorizontal className=\"w-4 h-4\" />\n {activeFacetCount > 0 && (\n <span className=\"absolute -right-1 -top-1 flex h-3.5 min-w-[14px] items-center justify-center rounded-full bg-accent px-0.5 text-[9px] font-medium text-white\">\n {activeFacetCount}\n </span>\n )}\n </button>\n </>\n }\n />\n\n {/* Faceted query — slide-out drawer (deep-linked state), portaled so fixed positioning\n works. Always mounted so it slides open/closed with a subtle transition. */}\n {createPortal(\n <div\n className={`fixed right-0 bottom-0 w-[420px] z-40 border-l border-surface-border bg-surface overflow-y-auto shadow-lg transition-transform duration-200 ease-out ${facetDrawerOpen ? 'translate-x-0' : 'pointer-events-none translate-x-full'}`}\n style={{ top: '3.5rem' }}\n aria-hidden={!facetDrawerOpen}\n >\n <div className=\"sticky top-0 z-10 flex items-center justify-between px-4 py-3 bg-surface border-b border-surface-border/50\">\n <span className=\"text-xs font-medium text-text-primary\">Faceted query</span>\n <div className=\"flex items-center gap-2\">\n {activeFacetCount > 0 && (\n <button\n onClick={() => { setFacetFilters({}); setFilter('search', ''); }}\n className=\"text-[11px] text-text-tertiary hover:text-text-primary transition-colors\"\n >\n Clear\n </button>\n )}\n <button\n onClick={() => setFacetDrawerOpen(false)}\n className=\"p-1 rounded hover:bg-surface-hover text-text-tertiary hover:text-text-primary transition-colors\"\n title=\"Close\"\n >\n <X className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n <div className=\"px-4 py-2\">\n <p className=\"mb-2 text-[11px] leading-snug text-text-tertiary\">\n Precise metadata facets plus exact correlation-id lookup — they compose in one\n SQL query. Facet keys are the ones that actually exist in your visible escalations.\n Set status to <span className=\"font-medium\">All</span> to find an order across every\n status; the whole query is shareable via the URL.\n </p>\n <FacetedFilterPanel\n value={facetFilters}\n onChange={setFacetFilters}\n facetKeys={facetKeysData?.keys ?? []}\n search={filters.search ?? ''}\n onSearchChange={(v) => setFilter('search', v)}\n />\n </div>\n </div>,\n document.body,\n )}\n\n {/* Always mounted so the bar can animate in AND out as the selection changes. */}\n <BulkActionBar\n selectedCount={selectedIds.size}\n onClearSelection={() => setSelectedIds(new Set())}\n onSetPriority={handleSetPriority}\n onClaim={handleBulkClaim}\n onAssign={() => setAssignModalOpen(true)}\n onEscalate={handleBulkEscalate}\n onTriage={() => setTriageModalOpen(true)}\n onCancel={() => setCancelModalOpen(true)}\n isPriorityPending={setPriority.isPending}\n isClaimPending={bulkClaim.isPending}\n isAssignPending={bulkAssign.isPending}\n isEscalatePending={bulkEscalate.isPending}\n isTriagePending={bulkTriage.isPending}\n isCancelPending={bulkCancel.isPending}\n availableRoles={rolesData?.roles ?? []}\n />\n\n {queryError && (\n <div className=\"mb-4 px-4 py-3 rounded-md bg-status-error/10 border border-status-error/20 text-xs text-status-error\">\n {(queryError as Error).message === 'Session expired'\n ? 'Your session has expired. Please log in again.'\n : `Failed to load escalations: ${(queryError as Error).message}`}\n </div>\n )}\n\n <DataTable\n columns={columns}\n data={escalations}\n keyFn={(row) => row.id}\n onRowClick={(row) => navigate(`/escalations/detail/${row.id}`, { state: { from: '/escalations/available' } })}\n isLoading={isLoading}\n emptyMessage={queryError ? 'Unable to load data' : 'No escalations'}\n sort={sort}\n onSort={setSort}\n />\n\n <StickyPagination\n page={pagination.page}\n totalPages={pagination.totalPages(total)}\n onPageChange={pagination.setPage}\n total={total}\n pageSize={pagination.pageSize}\n onPageSizeChange={pagination.setPageSize}\n />\n\n <ClaimModal\n claimTarget={claimTarget}\n onClose={() => setClaimTarget(null)}\n claimDuration={claimDuration}\n onDurationChange={(v) => { setClaimDuration(v); setCustomClaimMinutes(0); }}\n claimDurations={claimDurations}\n customClaimMinutes={customClaimMinutes}\n onCustomClaimChange={onCustomClaimChange}\n onClaim={handleClaim}\n isPending={claim.isPending}\n />\n\n <BulkTriageModal\n open={triageModalOpen}\n onClose={() => setTriageModalOpen(false)}\n selectedCount={selectedIds.size}\n onSubmit={handleBulkTriage}\n isPending={bulkTriage.isPending}\n />\n\n <BulkAssignModal\n open={assignModalOpen}\n onClose={() => setAssignModalOpen(false)}\n selectedCount={selectedIds.size}\n selectedRoles={selectedRoles}\n onSubmit={handleBulkAssign}\n isPending={bulkAssign.isPending}\n />\n\n <ConfirmCancelModal\n open={cancelModalOpen}\n onClose={() => setCancelModalOpen(false)}\n onConfirm={handleBulkCancel}\n selectedCount={selectedIds.size}\n isPending={bulkCancel.isPending}\n error={bulkCancel.error as Error | null}\n />\n </div>\n );\n}\n"],"names":["parse","v","isEmpty","parseFacetParams","sp","f","facets","block","range","exists","roles","orderBy","writeFacetParams","p","set","k","facetCount","_a","_b","_c","_d","RANGE_OPS","SORT_COLUMNS","inputCls","xBtn","coerce","recordRows","rec","key","value","blockRows","arr","o","Section","title","hint","children","jsxs","jsx","KeyInput","onChange","placeholder","e","FacetedFilterPanel","facetKeys","search","onSearchChange","exclude","ranges","sorts","setFacets","rows","r","setBlock","setRange","setExists","setSorts","c","row","next","_","j","x","s","anyPending","props","CTRL","SELECT","DANGER","BulkActionBar","disabled","claimDurations","useClaimDurations","settings","useSettings","aiEnabled","open","PRIORITY_OPTIONS","opt","role","BulkAssignModal","onClose","selectedCount","selectedRoles","onSubmit","isPending","isSuperAdmin","useAuth","step","setStep","useState","selectedUser","setSelectedUser","setSearch","duration","setDuration","customMinutes","setCustomMinutes","onCustomChange","useCallback","roleFilter","debouncedSearch","useDebouncedValue","usersData","usersLoading","useUsers","users","handleClose","handleSelectUser","user","handleBack","handleSubmit","minutes","Modal","Fragment","CustomDurationPicker","BulkTriageModal","setHint","bulkHandler","mutation","clearSelection","afterSuccess","variables","createBulkHandlers","deps","ids","priority","durationMinutes","targetRole","targetUserId","ClaimModal","claimTarget","claimDuration","onDurationChange","onCustomClaimChange","onClaim","AvailableEscalationsPage","useEscalationListEvents","navigate","useNavigate","filters","setFilter","pagination","sort","setSort","useFilterParams","setClaimTarget","setClaimDuration","customClaimMinutes","setCustomClaimMinutes","m","selectedIds","setSelectedIds","facetDrawerOpen","setFacetDrawerOpen","searchParams","setSearchParams","useSearchParams","facetFilters","useMemo","setFacetFilters","prev","facetKeysData","useFacetKeys","activeFacetCount","triageModalOpen","setTriageModalOpen","assignModalOpen","setAssignModalOpen","cancelModalOpen","setCancelModalOpen","claim","useClaimEscalation","setPriority","useSetEscalationPriority","bulkClaim","useBulkClaimEscalations","bulkAssign","useBulkAssignEscalations","bulkEscalate","useBulkEscalateToRole","bulkTriage","useBulkTriageEscalations","bulkCancel","useBulkCancelEscalations","rolesData","useRoles","typesData","useEscalationTypes","useEffect","statusFilter","isAvailable","isClaimed","apiStatus","sharedFilters","availableQuery","useAvailableEscalations","escalationsQuery","useEscalations","activeQuery","data","isLoading","queryError","refetch","isFetching","apiPath","buildApiPath","_e","escalations","total","canBulkManage","useAccess","esc","handleClaim","handleSetPriority","handleBulkClaim","handleBulkEscalate","handleBulkTriage","handleBulkAssign","handleBulkCancel","toggleSelect","id","toggleAll","columns","ESCALATION_COLUMNS","RowActionGroup","RowAction","Lock","PageHeader","EscalationFilterBar","ListToolbar","SlidersHorizontal","createPortal","X","DataTable","StickyPagination","ConfirmCancelModal"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{j as a,a as o}from"./vendor-query-B2UbickB.js";import{M as d}from"./Modal-CSrxpXeM.js";import{u as p}from"./index-DwWP-Z_c.js";import{D as h,f as y}from"./constants-BHkpVaqx.js";function N({open:s,onClose:l,onConfirm:c,selectedCount:t,isPending:n,error:r}){const i=t&&t>1?`Cancel ${t} escalations`:"Cancel escalation";return a.jsx(d,{open:s,onClose:l,title:i,children:a.jsxs("div",{className:"space-y-4",children:[a.jsx("p",{className:"text-sm text-text-secondary",children:t&&t>1?`This will permanently cancel ${t} escalations. Any waiting workflows will be unblocked and receive a cancellation signal.`:"This will permanently cancel this escalation. Any waiting workflow will be unblocked and receive a cancellation signal."}),a.jsx("p",{className:"text-xs text-text-tertiary",children:"This action cannot be undone."}),r&&a.jsx("p",{className:"text-xs text-status-error",children:r.message}),a.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[a.jsx("button",{onClick:l,disabled:n,className:"btn-secondary text-xs",children:"Keep"}),a.jsx("button",{onClick:c,disabled:n,className:"bg-status-error text-white px-3 py-1.5 rounded-md text-xs hover:opacity-90 transition-opacity disabled:opacity-50",children:n?"Cancelling...":"Yes, Cancel"})]})]})})}function g(){const{data:s}=p();return o.useMemo(()=>{var c;return(((c=s==null?void 0:s.escalation)==null?void 0:c.claimDurations)??h).map(t=>({value:String(t),label:y(t)}))},[s])}const b=[{value:1,label:"minutes"},{value:60,label:"hours"}];function C({onChange:s,compact:l,autoFocus:c,"data-testid":t="custom-duration-input"}){const[n,r]=o.useState(""),[i,m]=o.useState(1);o.useEffect(()=>{const e=parseInt(n);s(e>0?e*i:0)},[n,i,s]);const u=l?"text-xs":"text-sm",x=l?"w-16":"w-20";return a.jsxs("div",{className:"flex items-center gap-2","data-testid":t,children:[a.jsx("input",{type:"number",min:1,max:i===60?24:1440,value:n,onChange:e=>r(e.target.value),placeholder:i===60?"hrs":"min",className:`input ${u} ${x} text-center`,autoFocus:c,"data-testid":`${t}-quantity`}),a.jsx("select",{value:i,onChange:e=>m(parseInt(e.target.value)),className:`select ${u} py-1`,"data-testid":`${t}-unit`,children:b.map(e=>a.jsx("option",{value:e.value,children:e.label},e.value))})]})}export{C,N as a,g as u};
2
- //# sourceMappingURL=CustomDurationPicker-OKlwH5a_.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CustomDurationPicker-OKlwH5a_.js","sources":["../../src/components/common/modal/ConfirmCancelModal.tsx","../../src/hooks/useClaimDurations.ts","../../src/components/common/form/CustomDurationPicker.tsx"],"sourcesContent":["import { Modal } from './Modal';\n\ninterface ConfirmCancelModalProps {\n open: boolean;\n onClose: () => void;\n onConfirm: () => void;\n selectedCount?: number;\n isPending?: boolean;\n error?: Error | null;\n}\n\nexport function ConfirmCancelModal({\n open,\n onClose,\n onConfirm,\n selectedCount,\n isPending,\n error,\n}: ConfirmCancelModalProps) {\n const title = selectedCount && selectedCount > 1\n ? `Cancel ${selectedCount} escalations`\n : 'Cancel escalation';\n\n return (\n <Modal open={open} onClose={onClose} title={title}>\n <div className=\"space-y-4\">\n <p className=\"text-sm text-text-secondary\">\n {selectedCount && selectedCount > 1\n ? `This will permanently cancel ${selectedCount} escalations. Any waiting workflows will be unblocked and receive a cancellation signal.`\n : 'This will permanently cancel this escalation. Any waiting workflow will be unblocked and receive a cancellation signal.'}\n </p>\n <p className=\"text-xs text-text-tertiary\">This action cannot be undone.</p>\n {error && <p className=\"text-xs text-status-error\">{error.message}</p>}\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={onClose} disabled={isPending} className=\"btn-secondary text-xs\">\n Keep\n </button>\n <button\n onClick={onConfirm}\n disabled={isPending}\n className=\"bg-status-error text-white px-3 py-1.5 rounded-md text-xs hover:opacity-90 transition-opacity disabled:opacity-50\"\n >\n {isPending ? 'Cancelling...' : 'Yes, Cancel'}\n </button>\n </div>\n </div>\n </Modal>\n );\n}\n","import { useMemo } from 'react';\nimport { useSettings } from '../api/settings';\nimport { DEFAULT_CLAIM_DURATIONS, formatClaimDuration } from '../lib/constants';\n\nexport interface ClaimDurationOption {\n value: string;\n label: string;\n}\n\n/**\n * Returns claim duration presets from server settings (with fallback).\n * Options are formatted for use in selects and tab rows.\n */\nexport function useClaimDurations(): ClaimDurationOption[] {\n const { data: settings } = useSettings();\n\n return useMemo(() => {\n const minutes = settings?.escalation?.claimDurations ?? DEFAULT_CLAIM_DURATIONS;\n return minutes.map((m) => ({\n value: String(m),\n label: formatClaimDuration(m),\n }));\n }, [settings]);\n}\n","import { useState, useEffect } from 'react';\n\nconst UNITS = [\n { value: 1, label: 'minutes' },\n { value: 60, label: 'hours' },\n] as const;\n\ninterface CustomDurationPickerProps {\n /** Called with the computed duration in minutes whenever quantity or unit changes */\n onChange: (minutes: number) => void;\n /** Compact variant for inline use (e.g. action bars) */\n compact?: boolean;\n /** Auto-focus the quantity input */\n autoFocus?: boolean;\n 'data-testid'?: string;\n}\n\nexport function CustomDurationPicker({\n onChange,\n compact,\n autoFocus,\n 'data-testid': testId = 'custom-duration-input',\n}: CustomDurationPickerProps) {\n const [quantity, setQuantity] = useState('');\n const [multiplier, setMultiplier] = useState(1);\n\n useEffect(() => {\n const q = parseInt(quantity);\n onChange(q > 0 ? q * multiplier : 0);\n }, [quantity, multiplier, onChange]);\n\n const textSize = compact ? 'text-xs' : 'text-sm';\n const inputWidth = compact ? 'w-16' : 'w-20';\n\n return (\n <div className=\"flex items-center gap-2\" data-testid={testId}>\n <input\n type=\"number\"\n min={1}\n max={multiplier === 60 ? 24 : 1440}\n value={quantity}\n onChange={(e) => setQuantity(e.target.value)}\n placeholder={multiplier === 60 ? 'hrs' : 'min'}\n className={`input ${textSize} ${inputWidth} text-center`}\n autoFocus={autoFocus}\n data-testid={`${testId}-quantity`}\n />\n <select\n value={multiplier}\n onChange={(e) => setMultiplier(parseInt(e.target.value))}\n className={`select ${textSize} py-1`}\n data-testid={`${testId}-unit`}\n >\n {UNITS.map((u) => (\n <option key={u.value} value={u.value}>{u.label}</option>\n ))}\n </select>\n </div>\n );\n}\n"],"names":["ConfirmCancelModal","open","onClose","onConfirm","selectedCount","isPending","error","title","jsx","Modal","jsxs","useClaimDurations","settings","useSettings","useMemo","_a","DEFAULT_CLAIM_DURATIONS","m","formatClaimDuration","UNITS","CustomDurationPicker","onChange","compact","autoFocus","testId","quantity","setQuantity","useState","multiplier","setMultiplier","useEffect","q","textSize","inputWidth","u"],"mappings":"yLAWO,SAASA,EAAmB,CACjC,KAAAC,EACA,QAAAC,EACA,UAAAC,EACA,cAAAC,EACA,UAAAC,EACA,MAAAC,CACF,EAA4B,CAC1B,MAAMC,EAAQH,GAAiBA,EAAgB,EAC3C,UAAUA,CAAa,eACvB,oBAEJ,OACEI,EAAAA,IAACC,GAAM,KAAAR,EAAY,QAAAC,EAAkB,MAAAK,EACnC,SAAAG,EAAAA,KAAC,MAAA,CAAI,UAAU,YACb,SAAA,CAAAF,EAAAA,IAAC,IAAA,CAAE,UAAU,8BACV,SAAAJ,GAAiBA,EAAgB,EAC9B,gCAAgCA,CAAa,2FAC7C,yHAAA,CACN,EACAI,EAAAA,IAAC,IAAA,CAAE,UAAU,6BAA6B,SAAA,gCAA6B,EACtEF,GAASE,EAAAA,IAAC,IAAA,CAAE,UAAU,4BAA6B,WAAM,QAAQ,EAClEE,EAAAA,KAAC,MAAA,CAAI,UAAU,8BACb,SAAA,CAAAF,EAAAA,IAAC,UAAO,QAASN,EAAS,SAAUG,EAAW,UAAU,wBAAwB,SAAA,MAAA,CAEjF,EACAG,EAAAA,IAAC,SAAA,CACC,QAASL,EACT,SAAUE,EACV,UAAU,oHAET,WAAY,gBAAkB,aAAA,CAAA,CACjC,CAAA,CACF,CAAA,CAAA,CACF,CAAA,CACF,CAEJ,CCnCO,SAASM,GAA2C,CACzD,KAAM,CAAE,KAAMC,CAAA,EAAaC,EAAA,EAE3B,OAAOC,EAAAA,QAAQ,IAAM,OAEnB,SADgBC,EAAAH,GAAA,YAAAA,EAAU,aAAV,YAAAG,EAAsB,iBAAkBC,GACzC,IAAKC,IAAO,CACzB,MAAO,OAAOA,CAAC,EACf,MAAOC,EAAoBD,CAAC,CAAA,EAC5B,CACJ,EAAG,CAACL,CAAQ,CAAC,CACf,CCrBA,MAAMO,EAAQ,CACZ,CAAE,MAAO,EAAG,MAAO,SAAA,EACnB,CAAE,MAAO,GAAI,MAAO,OAAA,CACtB,EAYO,SAASC,EAAqB,CACnC,SAAAC,EACA,QAAAC,EACA,UAAAC,EACA,cAAeC,EAAS,uBAC1B,EAA8B,CAC5B,KAAM,CAACC,EAAUC,CAAW,EAAIC,EAAAA,SAAS,EAAE,EACrC,CAACC,EAAYC,CAAa,EAAIF,EAAAA,SAAS,CAAC,EAE9CG,EAAAA,UAAU,IAAM,CACd,MAAMC,EAAI,SAASN,CAAQ,EAC3BJ,EAASU,EAAI,EAAIA,EAAIH,EAAa,CAAC,CACrC,EAAG,CAACH,EAAUG,EAAYP,CAAQ,CAAC,EAEnC,MAAMW,EAAWV,EAAU,UAAY,UACjCW,EAAaX,EAAU,OAAS,OAEtC,OACEZ,EAAAA,KAAC,MAAA,CAAI,UAAU,0BAA0B,cAAac,EACpD,SAAA,CAAAhB,EAAAA,IAAC,QAAA,CACC,KAAK,SACL,IAAK,EACL,IAAKoB,IAAe,GAAK,GAAK,KAC9B,MAAOH,EACP,SAAW,GAAMC,EAAY,EAAE,OAAO,KAAK,EAC3C,YAAaE,IAAe,GAAK,MAAQ,MACzC,UAAW,SAASI,CAAQ,IAAIC,CAAU,eAC1C,UAAAV,EACA,cAAa,GAAGC,CAAM,WAAA,CAAA,EAExBhB,EAAAA,IAAC,SAAA,CACC,MAAOoB,EACP,SAAW,GAAMC,EAAc,SAAS,EAAE,OAAO,KAAK,CAAC,EACvD,UAAW,UAAUG,CAAQ,QAC7B,cAAa,GAAGR,CAAM,QAErB,SAAAL,EAAM,IAAKe,GACV1B,EAAAA,IAAC,SAAA,CAAqB,MAAO0B,EAAE,MAAQ,SAAAA,EAAE,KAAA,EAA5BA,EAAE,KAAgC,CAChD,CAAA,CAAA,CACH,EACF,CAEJ"}
@@ -1,2 +0,0 @@
1
- import{j as e}from"./vendor-query-B2UbickB.js";import{E as b}from"./EmptyState-BcsfPq9T.js";function j({active:s,direction:a}){return e.jsx("svg",{className:`w-3 h-3 shrink-0 transition-all duration-150 ${s?"text-accent opacity-100":"opacity-0 group-hover/sorthead:opacity-40 text-text-tertiary"} ${s&&a==="asc"?"rotate-180":""}`,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2.5,children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"})})}function N({columns:s,data:a,keyFn:l,onRowClick:o,activeRowKey:d,rowClassName:x,isLoading:h,emptyMessage:p="No records found",sort:n,onSort:u,inline:m}){return h?e.jsx("div",{className:"animate-pulse space-y-0",children:Array.from({length:5}).map((r,t)=>e.jsx("div",{className:"h-14 border-b last:border-b-0 px-6 flex items-center",children:e.jsx("div",{className:"h-3 bg-surface-sunken rounded w-full"})},t))}):a.length?e.jsxs("table",{className:"w-full",children:[e.jsx("thead",{children:e.jsx("tr",{className:"border-b",children:s.map(r=>{const t=r.sortable&&u,i=(n==null?void 0:n.sort_by)===r.key;return e.jsx("th",{onClick:t?()=>u(r.key):void 0,className:`${m?"":"sticky top-[60px] z-10 "}bg-surface px-6 py-3 text-left text-[10px] font-semibold uppercase tracking-widest text-text-tertiary whitespace-nowrap ${r.className??""} ${t?"cursor-pointer select-none group/sorthead hover:text-text-secondary transition-colors":""}`,children:e.jsxs("span",{className:"inline-flex items-center gap-1",children:[r.label,t&&e.jsx(j,{active:i,direction:i?n.order:"desc"})]})},r.key)})})}),e.jsx("tbody",{children:a.map((r,t)=>{const i=d!=null&&l(r)===d;return e.jsx("tr",{onClick:o?()=>o(r):void 0,className:`group/row border-b last:border-b-0 transition-colors duration-100 ${o?"cursor-pointer row-hover":""} ${i?"border-l-2 border-l-accent":""} ${x?x(r):""}`,children:s.map(c=>e.jsx("td",{className:`px-6 py-2.5 text-sm ${c.className??""}`,children:c.render(r,t)},c.key))},l(r))})})]}):p?e.jsx(b,{title:p}):null}export{N as D};
2
- //# sourceMappingURL=DataTable-ZWgVQg7F.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DataTable-ZWgVQg7F.js","sources":["../../src/components/common/data/DataTable.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { EmptyState } from '../display/EmptyState';\nimport type { SortState } from '../../../hooks/useFilterParams';\n\nexport interface Column<T> {\n key: string;\n label: string | ReactNode;\n render: (row: T, index: number) => ReactNode;\n className?: string;\n /** If true, this column header is clickable and triggers onSort. */\n sortable?: boolean;\n}\n\ninterface DataTableProps<T> {\n columns: Column<T>[];\n data: T[];\n keyFn: (row: T) => string;\n onRowClick?: (row: T) => void;\n /** Highlight the row whose keyFn matches this value. */\n activeRowKey?: string | null;\n /** Optional per-row class name for custom styling (e.g., engine vs worker tint). */\n rowClassName?: (row: T) => string;\n isLoading?: boolean;\n emptyMessage?: string;\n /** Current sort state — pass to show active sort indicator. */\n sort?: SortState;\n /** Called when a sortable column header is clicked. */\n onSort?: (column: string) => void;\n /** Disable the sticky header (useful when nested inside collapsible sections). */\n inline?: boolean;\n}\n\nfunction SortIcon({ active, direction }: { active: boolean; direction: 'asc' | 'desc' }) {\n return (\n <svg\n className={`w-3 h-3 shrink-0 transition-all duration-150 ${\n active ? 'text-accent opacity-100' : 'opacity-0 group-hover/sorthead:opacity-40 text-text-tertiary'\n } ${active && direction === 'asc' ? 'rotate-180' : ''}`}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2.5}\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n );\n}\n\nexport function DataTable<T>({\n columns,\n data,\n keyFn,\n onRowClick,\n activeRowKey,\n rowClassName,\n isLoading,\n emptyMessage = 'No records found',\n sort,\n onSort,\n inline,\n}: DataTableProps<T>) {\n if (isLoading) {\n return (\n <div className=\"animate-pulse space-y-0\">\n {Array.from({ length: 5 }).map((_, i) => (\n <div key={i} className=\"h-14 border-b last:border-b-0 px-6 flex items-center\">\n <div className=\"h-3 bg-surface-sunken rounded w-full\" />\n </div>\n ))}\n </div>\n );\n }\n\n if (!data.length) {\n return emptyMessage ? <EmptyState title={emptyMessage} /> : null;\n }\n\n return (\n <table className=\"w-full\">\n <thead>\n <tr className=\"border-b\">\n {columns.map((col) => {\n const isSortable = col.sortable && onSort;\n const isActive = sort?.sort_by === col.key;\n\n return (\n <th\n key={col.key}\n onClick={isSortable ? () => onSort(col.key) : undefined}\n className={`${inline ? '' : 'sticky top-[60px] z-10 '}bg-surface px-6 py-3 text-left text-[10px] font-semibold uppercase tracking-widest text-text-tertiary whitespace-nowrap ${col.className ?? ''} ${\n isSortable ? 'cursor-pointer select-none group/sorthead hover:text-text-secondary transition-colors' : ''\n }`}\n >\n <span className=\"inline-flex items-center gap-1\">\n {col.label}\n {isSortable && (\n <SortIcon active={isActive} direction={isActive ? sort.order : 'desc'} />\n )}\n </span>\n </th>\n );\n })}\n </tr>\n </thead>\n <tbody>\n {data.map((row, index) => {\n const isActive = activeRowKey != null && keyFn(row) === activeRowKey;\n return (\n <tr\n key={keyFn(row)}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n className={`group/row border-b last:border-b-0 transition-colors duration-100 ${\n onRowClick ? 'cursor-pointer row-hover' : ''\n } ${isActive ? 'border-l-2 border-l-accent' : ''} ${rowClassName ? rowClassName(row) : ''}`}\n >\n {columns.map((col) => (\n <td\n key={col.key}\n className={`px-6 py-2.5 text-sm ${col.className ?? ''}`}\n >\n {col.render(row, index)}\n </td>\n ))}\n </tr>\n );\n })}\n </tbody>\n </table>\n );\n}\n"],"names":["SortIcon","active","direction","jsx","DataTable","columns","data","keyFn","onRowClick","activeRowKey","rowClassName","isLoading","emptyMessage","sort","onSort","inline","_","i","jsxs","col","isSortable","isActive","row","index","EmptyState"],"mappings":"4FAgCA,SAASA,EAAS,CAAE,OAAAC,EAAQ,UAAAC,GAA6D,CACvF,OACEC,EAAAA,IAAC,MAAA,CACC,UAAW,gDACTF,EAAS,0BAA4B,8DACvC,IAAIA,GAAUC,IAAc,MAAQ,aAAe,EAAE,GACrD,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAa,IAEb,eAAC,OAAA,CAAK,cAAc,QAAQ,eAAe,QAAQ,EAAE,gBAAA,CAAiB,CAAA,CAAA,CAG5E,CAEO,SAASE,EAAa,CAC3B,QAAAC,EACA,KAAAC,EACA,MAAAC,EACA,WAAAC,EACA,aAAAC,EACA,aAAAC,EACA,UAAAC,EACA,aAAAC,EAAe,mBACf,KAAAC,EACA,OAAAC,EACA,OAAAC,CACF,EAAsB,CACpB,OAAIJ,EAEAR,EAAAA,IAAC,MAAA,CAAI,UAAU,0BACZ,SAAA,MAAM,KAAK,CAAE,OAAQ,CAAA,CAAG,EAAE,IAAI,CAACa,EAAGC,IACjCd,EAAAA,IAAC,MAAA,CAAY,UAAU,uDACrB,SAAAA,EAAAA,IAAC,MAAA,CAAI,UAAU,sCAAA,CAAuC,CAAA,EAD9Cc,CAEV,CACD,CAAA,CACH,EAICX,EAAK,OAKRY,EAAAA,KAAC,QAAA,CAAM,UAAU,SACf,SAAA,CAAAf,EAAAA,IAAC,QAAA,CACC,eAAC,KAAA,CAAG,UAAU,WACX,SAAAE,EAAQ,IAAKc,GAAQ,CACpB,MAAMC,EAAaD,EAAI,UAAYL,EAC7BO,GAAWR,GAAA,YAAAA,EAAM,WAAYM,EAAI,IAEvC,OACEhB,EAAAA,IAAC,KAAA,CAEC,QAASiB,EAAa,IAAMN,EAAOK,EAAI,GAAG,EAAI,OAC9C,UAAW,GAAGJ,EAAS,GAAK,yBAAyB,2HAA2HI,EAAI,WAAa,EAAE,IACjMC,EAAa,wFAA0F,EACzG,GAEA,SAAAF,EAAAA,KAAC,OAAA,CAAK,UAAU,iCACb,SAAA,CAAAC,EAAI,MACJC,SACEpB,EAAA,CAAS,OAAQqB,EAAU,UAAWA,EAAWR,EAAK,MAAQ,MAAA,CAAQ,CAAA,CAAA,CAE3E,CAAA,EAXKM,EAAI,GAAA,CAcf,CAAC,EACH,EACF,QACC,QAAA,CACE,SAAAb,EAAK,IAAI,CAACgB,EAAKC,IAAU,CACxB,MAAMF,EAAWZ,GAAgB,MAAQF,EAAMe,CAAG,IAAMb,EACxD,OACAN,EAAAA,IAAC,KAAA,CAEC,QAASK,EAAa,IAAMA,EAAWc,CAAG,EAAI,OAC9C,UAAW,qEACTd,EAAa,2BAA6B,EAC5C,IAAIa,EAAW,6BAA+B,EAAE,IAAIX,EAAeA,EAAaY,CAAG,EAAI,EAAE,GAExF,SAAAjB,EAAQ,IAAKc,GACZhB,EAAAA,IAAC,KAAA,CAEC,UAAW,uBAAuBgB,EAAI,WAAa,EAAE,GAEpD,SAAAA,EAAI,OAAOG,EAAKC,CAAK,CAAA,EAHjBJ,EAAI,GAAA,CAKZ,CAAA,EAbIZ,EAAMe,CAAG,CAAA,CAgBlB,CAAC,CAAA,CACH,CAAA,EACF,EArDOV,EAAeT,EAAAA,IAACqB,EAAA,CAAW,MAAOZ,EAAc,EAAK,IAuDhE"}
@@ -1,9 +0,0 @@
1
- import{a as l,j as e}from"./vendor-query-B2UbickB.js";import{c as S,e as w,i as _,j as E}from"./roles-D4Wn7kE9.js";import{J as C}from"./index-DwWP-Z_c.js";import{g as j,B as O,V as R,ah as q}from"./vendor-icons-DOIDKgo6.js";import{e as V}from"./vendor-react-CXumBFUA.js";const J=`{
2
- "type": "object",
3
- "properties": {
4
- "approved": { "type": "boolean", "title": "Approve?" },
5
- "notes": { "type": "string", "title": "Notes" }
6
- },
7
- "required": ["approved"]
8
- }`;function v(o){const t=o.trim();if(!t)return{ok:!0,value:null};try{const r=JSON.parse(t);return typeof r!="object"||Array.isArray(r)||r===null?{ok:!1}:{ok:!0,value:r}}catch{return{ok:!1}}}function F(){const{role:o}=V(),{data:t,isLoading:r}=S(),n=w(),s=((t==null?void 0:t.roles)??[]).find(a=>a.role===o),[c,i]=l.useState(""),[h,u]=l.useState(""),[N,d]=l.useState(!1),[g,x]=l.useState(!1),[p,m]=l.useState(!1),f=l.useRef(null);l.useEffect(()=>{!s||f.current===s.role||(f.current=s.role,i(s.form_schema?JSON.stringify(s.form_schema,null,2):""),u(""),d(!1),m(!1))},[s]);const y=a=>{i(a),d(!0),x(!1),m(!v(a).ok)},b=()=>{const a=v(c);if(!a.ok||!s){m(!a.ok);return}n.mutate({role:s.role,form_schema:a.value??null,change_summary:h.trim()||void 0},{onSuccess:()=>{d(!1),x(!0),u(""),window.setTimeout(()=>x(!1),2500)}})},k=a=>{i(a?JSON.stringify(a,null,2):""),d(!0),x(!1),m(!1)};return r?e.jsxs("div",{className:"animate-pulse space-y-4",children:[e.jsx("div",{className:"h-8 bg-surface-sunken rounded w-64"}),e.jsx("div",{className:"h-96 bg-surface-sunken rounded"})]}):s?e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-start justify-between mb-10",children:[e.jsx("div",{children:e.jsxs("div",{className:"flex items-center gap-3 mb-1",children:[e.jsx(j,{className:"w-5 h-5 text-accent",strokeWidth:1.5}),e.jsx("h1",{className:"text-lg font-medium text-text-primary",children:"Escalation Schema"}),e.jsx("button",{onClick:()=>{window.location.hash="#docs:dashboard.md:escalation-schema"},className:"text-text-quaternary hover:text-accent transition-colors",title:"Open docs for this page",children:e.jsx(O,{className:"w-4 h-4",strokeWidth:1.5})}),e.jsx("span",{className:"font-mono text-sm text-text-tertiary",children:s.role}),s.current_schema_version!=null&&e.jsxs("span",{className:"text-[10px] font-mono text-text-quaternary",children:["v",s.current_schema_version," in use"]})]})}),e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[g&&e.jsxs("span",{className:"flex items-center gap-1 text-xs text-status-success animate-page-enter",children:[e.jsx(R,{className:"w-3 h-3"})," Saved"]}),n.error&&e.jsx("span",{className:"text-xs text-status-error max-w-[220px] truncate",children:n.error.message}),e.jsx("button",{onClick:b,disabled:!N||p||n.isPending,className:"px-3 py-1.5 text-xs rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed",children:n.isPending?"Saving…":"Save Version"})]})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-16 items-start",children:[e.jsxs("div",{className:"col-span-2 space-y-6",children:[e.jsx("textarea",{value:c,onChange:a=>y(a.target.value),rows:28,spellCheck:!1,className:"input text-xs font-mono w-full resize-y leading-relaxed",placeholder:J}),p&&e.jsx("p",{className:"text-[10px] text-status-error -mt-4",children:"Invalid JSON"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1.5",children:"Change Summary"}),e.jsx("input",{type:"text",value:h,onChange:a=>u(a.target.value),placeholder:"e.g., Added lotNumber field for shoe orders",className:"input text-sm w-full"}),e.jsx("p",{className:"text-[10px] text-text-quaternary mt-1.5",children:"Recorded on the version this save creates."})]})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3 pb-2 border-b border-surface-border",children:[e.jsx(q,{className:"w-4 h-4 text-text-quaternary",strokeWidth:1.5}),e.jsx("h2",{className:"section-h2",children:"Versions"})]}),e.jsx(L,{role:s.role,onLoad:k})]})]})]}):e.jsxs("div",{className:"flex flex-col items-center justify-center py-20 text-center",children:[e.jsx(j,{className:"w-12 h-12 text-text-quaternary mb-4",strokeWidth:1}),e.jsx("h2",{className:"text-lg font-medium text-text-primary mb-2",children:"Role not found"})]})}function L({role:o,onLoad:t}){const{data:r}=_(o),n=(r==null?void 0:r.versions)??[];return n.length===0?e.jsx("p",{className:"text-[11px] text-text-tertiary leading-relaxed",children:"Versions appear here after the first save. Each schema change adds one; earlier versions stay viewable and loadable as an editing base."}):e.jsx("div",{className:"divide-y divide-surface-border/40",children:n.map(s=>e.jsx(P,{role:o,summary:s,onLoad:t},s.version))})}function P({role:o,summary:t,onLoad:r}){const[n,s]=l.useState(!1),c=E(o,t.version,n);return e.jsxs("div",{className:"py-2",children:[e.jsxs("button",{onClick:()=>s(i=>!i),className:"w-full text-left group",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("span",{className:"text-xs font-mono text-text-secondary",children:["v",t.version]}),t.is_current&&e.jsx("span",{className:"text-[9px] font-bold uppercase tracking-wider text-accent",children:"current"}),e.jsx("span",{className:"flex-1"}),e.jsx("span",{className:"text-[10px] text-text-quaternary shrink-0",children:new Date(t.created_at).toLocaleDateString()})]}),t.change_summary&&e.jsx("p",{className:"mt-0.5 text-[10px] text-text-tertiary truncate",children:t.change_summary})]}),n&&e.jsx("div",{className:"mt-2 space-y-2",children:c.data?e.jsxs(e.Fragment,{children:[c.data.form_schema?e.jsx(C,{data:c.data.form_schema,defaultCollapsed:!0}):e.jsx("p",{className:"text-[10px] text-text-quaternary",children:"This version carries no form schema."}),e.jsx("button",{onClick:()=>r(c.data.form_schema??null),className:"text-[10px] text-accent hover:underline",children:"Load into editor"})]}):e.jsx("p",{className:"text-[10px] text-text-quaternary",children:"Loading…"})})]})}export{F as EscalationSchemaPage};
9
- //# sourceMappingURL=EscalationSchemaPage-Br5sD8-N.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"EscalationSchemaPage-Br5sD8-N.js","sources":["../../src/pages/admin/roles/EscalationSchemaPage.tsx"],"sourcesContent":["import { useState, useEffect, useRef } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { Braces, Check, History, BookOpen } from 'lucide-react';\nimport {\n useRoleDetails,\n useRoleSchema,\n useRoleSchemaVersions,\n useUpdateRole,\n type RoleSchemaVersionSummary,\n} from '../../../api/roles';\nimport { JsonViewer } from '../../../components/common/data/JsonViewer';\n\n/**\n * The escalation form schema, on its own page (/admin/roles/:role/schema).\n * This is the form a person completes to resolve the role's escalations —\n * versioned, pinnable by workflows (conditionLT schemaVersion), and worth a\n * full editing surface. Saving here writes ONLY the schema: one PATCH with\n * form_schema (+ optional change summary); every actual change appends the\n * next immutable version.\n */\n\nconst PLACEHOLDER = `{\n \"type\": \"object\",\n \"properties\": {\n \"approved\": { \"type\": \"boolean\", \"title\": \"Approve?\" },\n \"notes\": { \"type\": \"string\", \"title\": \"Notes\" }\n },\n \"required\": [\"approved\"]\n}`;\n\nfunction safeParseObject(text: string): { ok: boolean; value?: Record<string, unknown> | null } {\n const trimmed = text.trim();\n if (!trimmed) return { ok: true, value: null };\n try {\n const parsed = JSON.parse(trimmed);\n if (typeof parsed !== 'object' || Array.isArray(parsed) || parsed === null) return { ok: false };\n return { ok: true, value: parsed };\n } catch {\n return { ok: false };\n }\n}\n\nexport function EscalationSchemaPage() {\n const { role: roleKey } = useParams<{ role: string }>();\n const { data, isLoading } = useRoleDetails();\n const updateRole = useUpdateRole();\n\n const role = (data?.roles ?? []).find((r) => r.role === roleKey);\n\n const [text, setText] = useState('');\n const [summary, setSummary] = useState('');\n const [dirty, setDirty] = useState(false);\n const [savedOk, setSavedOk] = useState(false);\n const [jsonError, setJsonError] = useState(false);\n\n // Seed the editor from the live schema exactly once per role — refetches\n // (cache invalidations, saves) must not clobber in-progress edits.\n const seededFor = useRef<string | null>(null);\n useEffect(() => {\n if (!role || seededFor.current === role.role) return;\n seededFor.current = role.role;\n setText(role.form_schema ? JSON.stringify(role.form_schema, null, 2) : '');\n setSummary('');\n setDirty(false);\n setJsonError(false);\n }, [role]);\n\n const handleEdit = (value: string) => {\n setText(value);\n setDirty(true);\n setSavedOk(false);\n setJsonError(!safeParseObject(value).ok);\n };\n\n const handleSave = () => {\n const parsed = safeParseObject(text);\n if (!parsed.ok || !role) { setJsonError(!parsed.ok); return; }\n // Saving just the schema — nothing else rides this PATCH.\n updateRole.mutate(\n { role: role.role, form_schema: parsed.value ?? null, change_summary: summary.trim() || undefined },\n {\n onSuccess: () => {\n setDirty(false);\n setSavedOk(true);\n setSummary('');\n window.setTimeout(() => setSavedOk(false), 2500);\n },\n },\n );\n };\n\n const loadIntoEditor = (schema: Record<string, unknown> | null) => {\n setText(schema ? JSON.stringify(schema, null, 2) : '');\n setDirty(true);\n setSavedOk(false);\n setJsonError(false);\n };\n\n if (isLoading) {\n return (\n <div className=\"animate-pulse space-y-4\">\n <div className=\"h-8 bg-surface-sunken rounded w-64\" />\n <div className=\"h-96 bg-surface-sunken rounded\" />\n </div>\n );\n }\n\n if (!role) {\n return (\n <div className=\"flex flex-col items-center justify-center py-20 text-center\">\n <Braces className=\"w-12 h-12 text-text-quaternary mb-4\" strokeWidth={1} />\n <h2 className=\"text-lg font-medium text-text-primary mb-2\">Role not found</h2>\n </div>\n );\n }\n\n return (\n <div>\n {/* ── Header ── */}\n <div className=\"flex items-start justify-between mb-10\">\n <div>\n <div className=\"flex items-center gap-3 mb-1\">\n <Braces className=\"w-5 h-5 text-accent\" strokeWidth={1.5} />\n <h1 className=\"text-lg font-medium text-text-primary\">Escalation Schema</h1>\n <button\n onClick={() => { window.location.hash = '#docs:dashboard.md:escalation-schema'; }}\n className=\"text-text-quaternary hover:text-accent transition-colors\"\n title=\"Open docs for this page\"\n >\n <BookOpen className=\"w-4 h-4\" strokeWidth={1.5} />\n </button>\n <span className=\"font-mono text-sm text-text-tertiary\">{role.role}</span>\n {role.current_schema_version != null && (\n <span className=\"text-[10px] font-mono text-text-quaternary\">\n v{role.current_schema_version} in use\n </span>\n )}\n </div>\n </div>\n\n <div className=\"flex items-center gap-2 shrink-0\">\n {savedOk && (\n <span className=\"flex items-center gap-1 text-xs text-status-success animate-page-enter\">\n <Check className=\"w-3 h-3\" /> Saved\n </span>\n )}\n {updateRole.error && (\n <span className=\"text-xs text-status-error max-w-[220px] truncate\">\n {(updateRole.error as Error).message}\n </span>\n )}\n <button\n onClick={handleSave}\n disabled={!dirty || jsonError || updateRole.isPending}\n className=\"px-3 py-1.5 text-xs rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {updateRole.isPending ? 'Saving…' : 'Save Version'}\n </button>\n </div>\n </div>\n\n {/* ── Editor + version rail ── */}\n <div className=\"grid grid-cols-3 gap-16 items-start\">\n <div className=\"col-span-2 space-y-6\">\n <textarea\n value={text}\n onChange={(e) => handleEdit(e.target.value)}\n rows={28}\n spellCheck={false}\n className=\"input text-xs font-mono w-full resize-y leading-relaxed\"\n placeholder={PLACEHOLDER}\n />\n {jsonError && <p className=\"text-[10px] text-status-error -mt-4\">Invalid JSON</p>}\n\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1.5\">\n Change Summary\n </label>\n <input\n type=\"text\"\n value={summary}\n onChange={(e) => setSummary(e.target.value)}\n placeholder=\"e.g., Added lotNumber field for shoe orders\"\n className=\"input text-sm w-full\"\n />\n <p className=\"text-[10px] text-text-quaternary mt-1.5\">\n Recorded on the version this save creates.\n </p>\n </div>\n </div>\n\n {/* Version history — view any snapshot, load one as the editing base */}\n <div>\n <div className=\"flex items-center gap-2 mb-3 pb-2 border-b border-surface-border\">\n <History className=\"w-4 h-4 text-text-quaternary\" strokeWidth={1.5} />\n <h2 className=\"section-h2\">Versions</h2>\n </div>\n <VersionRail role={role.role} onLoad={loadIntoEditor} />\n </div>\n </div>\n </div>\n );\n}\n\nfunction VersionRail({\n role,\n onLoad,\n}: {\n role: string;\n onLoad: (schema: Record<string, unknown> | null) => void;\n}) {\n const { data } = useRoleSchemaVersions(role);\n const versions = data?.versions ?? [];\n\n if (versions.length === 0) {\n return (\n <p className=\"text-[11px] text-text-tertiary leading-relaxed\">\n Versions appear here after the first save. Each schema change adds one;\n earlier versions stay viewable and loadable as an editing base.\n </p>\n );\n }\n\n return (\n <div className=\"divide-y divide-surface-border/40\">\n {versions.map((v) => (\n <VersionEntry key={v.version} role={role} summary={v} onLoad={onLoad} />\n ))}\n </div>\n );\n}\n\nfunction VersionEntry({\n role,\n summary,\n onLoad,\n}: {\n role: string;\n summary: RoleSchemaVersionSummary;\n onLoad: (schema: Record<string, unknown> | null) => void;\n}) {\n const [open, setOpen] = useState(false);\n // Snapshot fetch is lazy — only when the entry is expanded.\n const snapshot = useRoleSchema(role, summary.version, open);\n\n return (\n <div className=\"py-2\">\n <button onClick={() => setOpen((o) => !o)} className=\"w-full text-left group\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs font-mono text-text-secondary\">v{summary.version}</span>\n {summary.is_current && (\n <span className=\"text-[9px] font-bold uppercase tracking-wider text-accent\">current</span>\n )}\n <span className=\"flex-1\" />\n <span className=\"text-[10px] text-text-quaternary shrink-0\">\n {new Date(summary.created_at).toLocaleDateString()}\n </span>\n </div>\n {summary.change_summary && (\n <p className=\"mt-0.5 text-[10px] text-text-tertiary truncate\">{summary.change_summary}</p>\n )}\n </button>\n {open && (\n <div className=\"mt-2 space-y-2\">\n {snapshot.data ? (\n <>\n {snapshot.data.form_schema\n ? <JsonViewer data={snapshot.data.form_schema} defaultCollapsed />\n : <p className=\"text-[10px] text-text-quaternary\">This version carries no form schema.</p>}\n <button\n onClick={() => onLoad((snapshot.data!.form_schema ?? null) as Record<string, unknown> | null)}\n className=\"text-[10px] text-accent hover:underline\"\n >\n Load into editor\n </button>\n </>\n ) : (\n <p className=\"text-[10px] text-text-quaternary\">Loading…</p>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"names":["PLACEHOLDER","safeParseObject","text","trimmed","parsed","EscalationSchemaPage","roleKey","useParams","data","isLoading","useRoleDetails","updateRole","useUpdateRole","role","r","setText","useState","summary","setSummary","dirty","setDirty","savedOk","setSavedOk","jsonError","setJsonError","seededFor","useRef","useEffect","handleEdit","value","handleSave","loadIntoEditor","schema","jsxs","jsx","Braces","BookOpen","Check","e","History","VersionRail","onLoad","useRoleSchemaVersions","versions","v","VersionEntry","open","setOpen","snapshot","useRoleSchema","o","Fragment","JsonViewer"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{a as o,j as t}from"./vendor-query-B2UbickB.js";import{F as T,b as _}from"./FilterBar-B4Mk2PvT.js";import{f as F,C as D}from"./index-DwWP-Z_c.js";import{E as P}from"./SwimlaneTimeline-BrfmWgAj.js";const O=new Set(["activity_task_scheduled","timer_started","child_workflow_execution_started","signal_wait_started"]),L=new Set(["activity_task_completed","activity_task_failed","timer_fired","child_workflow_execution_completed","child_workflow_execution_failed","workflow_execution_signaled"]);function A(i){const a=new Set;for(const l of i)L.has(l.event_type)&&l.attributes.timeline_key&&a.add(l.attributes.timeline_key);return a}function M({events:i,childTasks:a,jid:l,appId:h}){const[c,y]=o.useState(""),[d,g]=o.useState(""),[u,b]=o.useState("asc"),[p,x]=o.useState(new Set),w=[...new Set(i.map(e=>e.category))].sort(),v=[...new Set(i.map(e=>e.event_type))].sort(),j=A(i),k=e=>{if(e.duration_ms!==null||!O.has(e.event_type))return!1;const s=e.attributes.timeline_key;return!(s&&j.has(s))};let n=i;c&&(n=n.filter(e=>e.category===c)),d&&(n=n.filter(e=>e.event_type===d)),n=[...n].sort((e,s)=>u==="asc"?e.event_id-s.event_id:s.event_id-e.event_id);const N=e=>{switch(e){case"activity":return"bg-status-active";case"signal":return"bg-status-success";case"timer":return"bg-status-warning";case"child_workflow":return"bg-accent";default:return"bg-text-tertiary"}},E=e=>{const s=e.event_type;if(e.attributes.activity_type)return`${s} — ${e.attributes.activity_type}`;if(e.attributes.signal_name)return`${s} — ${e.attributes.signal_name}`;if(e.attributes.child_workflow_id){const r=e.attributes.child_workflow_id,$=r.length>24?`${r.slice(0,24)}...`:r;return`${s} — ${$}`}return s},S=e=>{if(!(a!=null&&a.length))return;const s=e.attributes.activity_type;if(s)return a.find(r=>r.workflow_type===s)},m=e=>{x(s=>{const r=new Set(s);return r.has(e)?r.delete(e):r.add(e),r})},f=n.length>0&&n.every(e=>p.has(e.event_id)),C=()=>{x(f?new Set:new Set(n.map(e=>e.event_id)))};return t.jsxs("div",{children:[t.jsxs("div",{className:"px-6 py-4 border-b border-surface-border flex items-center justify-between flex-wrap gap-3",children:[t.jsxs("div",{className:"flex items-center gap-4",children:[t.jsxs("p",{className:"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary",children:["Events (",n.length,")"]}),n.length>0&&t.jsx("button",{onClick:C,className:"text-[10px] text-accent hover:underline",children:f?"Collapse all":"Expand all"})]}),t.jsxs(T,{children:[t.jsx(_,{label:"Category",value:c,onChange:y,options:w.map(e=>({value:e,label:e}))}),t.jsx(_,{label:"Type",value:d,onChange:g,options:v.map(e=>({value:e,label:e}))}),t.jsx("button",{onClick:()=>b(e=>e==="asc"?"desc":"asc"),className:"btn-ghost text-xs",children:u==="asc"?"Oldest first":"Newest first"})]})]}),t.jsx("div",{children:n.length===0?t.jsx("div",{className:"px-6 py-8 text-center",children:t.jsx("p",{className:"text-sm text-text-tertiary",children:"No events match the current filters"})}):n.map(e=>{const s=p.has(e.event_id),r=k(e);return t.jsxs("div",{className:"border-b border-surface-border last:border-b-0",children:[t.jsxs("div",{className:"px-6 py-3 flex items-center gap-4 cursor-pointer hover:bg-surface-hover transition-colors duration-200",onClick:()=>m(e.event_id),children:[t.jsx("span",{className:`text-[10px] text-text-tertiary transition-transform duration-300 ${s?"rotate-90":""}`,children:"▶"}),t.jsx("span",{className:"text-xs font-mono text-text-tertiary w-8 shrink-0",children:e.event_id}),t.jsx("span",{className:`w-2 h-2 rounded-full dot-ring shrink-0 ${N(e.category)}`}),t.jsx("span",{className:"text-sm text-text-primary flex-1 truncate",children:E(e)}),t.jsx("span",{className:"text-xs font-mono text-text-tertiary shrink-0",children:r?t.jsxs("span",{className:"inline-flex items-center gap-1 text-status-warning",children:[t.jsx("span",{className:"w-1.5 h-1.5 rounded-full dot-ring bg-status-warning animate-pulse"}),"Pending"]}):e.duration_ms!==null?F(e.duration_ms):"--"}),t.jsx("time",{className:"text-[10px] font-mono text-text-tertiary shrink-0",children:new Date(e.event_time).toLocaleTimeString()})]}),t.jsx(D,{open:s&&!!e.attributes,children:t.jsx("div",{className:"px-6 pb-4 pl-16",children:t.jsx(P,{event:e,childTask:S(e),pending:r,jid:l,appId:h,onClose:()=>m(e.event_id)})})})]},e.event_id)})})]})}export{M as E};
2
- //# sourceMappingURL=EventTable-BARJeiS2.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"EventTable-BARJeiS2.js","sources":["../../src/pages/workflows/workflow-execution/EventTable.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { FilterBar, FilterSelect } from '../../../components/common/data/FilterBar';\nimport { Collapsible } from '../../../components/common/layout/Collapsible';\nimport type { WorkflowExecutionEvent, LTTaskRecord } from '../../../api/types';\nimport { EventDetailPanel } from './EventDetailPanel';\nimport { formatDuration } from './utils';\n\ninterface EventTableProps {\n events: WorkflowExecutionEvent[];\n childTasks?: LTTaskRecord[];\n /** Job id (workflowId) — enables the per-activity raw-stream drill-down. */\n jid?: string;\n /** HotMesh namespace / DB schema for the raw-stream lookup (default: durable). */\n appId?: string;\n}\n\n/** Event types that represent the \"start\" phase of a paired operation */\nconst STARTED_TYPES = new Set([\n 'activity_task_scheduled',\n 'timer_started',\n 'child_workflow_execution_started',\n 'signal_wait_started',\n]);\n\n/** Completion event types that close a paired operation */\nconst COMPLETED_TYPES = new Set([\n 'activity_task_completed',\n 'activity_task_failed',\n 'timer_fired',\n 'child_workflow_execution_completed',\n 'child_workflow_execution_failed',\n 'workflow_execution_signaled',\n]);\n\n/**\n * Build a set of timeline_keys that have a matching completion event.\n * A \"scheduled\" event is only truly pending if no completion exists.\n */\nfunction buildCompletedKeys(events: WorkflowExecutionEvent[]): Set<string> {\n const keys = new Set<string>();\n for (const e of events) {\n if (COMPLETED_TYPES.has(e.event_type) && e.attributes.timeline_key) {\n keys.add(e.attributes.timeline_key);\n }\n }\n return keys;\n}\n\nexport function EventTable({ events, childTasks, jid, appId }: EventTableProps) {\n const [categoryFilter, setCategoryFilter] = useState('');\n const [typeFilter, setTypeFilter] = useState('');\n const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc');\n const [expandedEvents, setExpandedEvents] = useState<Set<number>>(new Set());\n\n const categories = [...new Set(events.map((e) => e.category))].sort();\n const eventTypes = [...new Set(events.map((e) => e.event_type))].sort();\n const completedKeys = buildCompletedKeys(events);\n\n /** True only when a \"started/scheduled\" event has no matching completion */\n const isPending = (evt: WorkflowExecutionEvent): boolean => {\n if (evt.duration_ms !== null) return false;\n if (!STARTED_TYPES.has(evt.event_type)) return false;\n const tlk = evt.attributes.timeline_key;\n if (tlk && completedKeys.has(tlk)) return false;\n return true;\n };\n\n let filtered = events;\n if (categoryFilter) filtered = filtered.filter((e) => e.category === categoryFilter);\n if (typeFilter) filtered = filtered.filter((e) => e.event_type === typeFilter);\n\n filtered = [...filtered].sort((a, b) =>\n sortOrder === 'asc' ? a.event_id - b.event_id : b.event_id - a.event_id,\n );\n\n const categoryDot = (category: string) => {\n switch (category) {\n case 'activity':\n return 'bg-status-active';\n case 'signal':\n return 'bg-status-success';\n case 'timer':\n return 'bg-status-warning';\n case 'child_workflow':\n return 'bg-accent';\n default:\n return 'bg-text-tertiary';\n }\n };\n\n /** Build a descriptive label for an event row */\n const eventLabel = (evt: WorkflowExecutionEvent): string => {\n const base = evt.event_type;\n if (evt.attributes.activity_type) {\n return `${base} — ${evt.attributes.activity_type}`;\n }\n if (evt.attributes.signal_name) {\n return `${base} — ${evt.attributes.signal_name}`;\n }\n if (evt.attributes.child_workflow_id) {\n const id = evt.attributes.child_workflow_id;\n const truncated = id.length > 24 ? `${id.slice(0, 24)}...` : id;\n return `${base} — ${truncated}`;\n }\n return base;\n };\n\n /** Find a matching child task for an event's activity_type */\n const findChildTask = (evt: WorkflowExecutionEvent): LTTaskRecord | undefined => {\n if (!childTasks?.length) return undefined;\n const activityType = evt.attributes.activity_type;\n if (!activityType) return undefined;\n return childTasks.find((t) => t.workflow_type === activityType);\n };\n\n const toggleEvent = (id: number) => {\n setExpandedEvents((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n };\n\n const allExpanded = filtered.length > 0 && filtered.every((e) => expandedEvents.has(e.event_id));\n\n const toggleAll = () => {\n if (allExpanded) {\n setExpandedEvents(new Set());\n } else {\n setExpandedEvents(new Set(filtered.map((e) => e.event_id)));\n }\n };\n\n return (\n <div>\n <div className=\"px-6 py-4 border-b border-surface-border flex items-center justify-between flex-wrap gap-3\">\n <div className=\"flex items-center gap-4\">\n <p className=\"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary\">\n Events ({filtered.length})\n </p>\n {filtered.length > 0 && (\n <button onClick={toggleAll} className=\"text-[10px] text-accent hover:underline\">\n {allExpanded ? 'Collapse all' : 'Expand all'}\n </button>\n )}\n </div>\n <FilterBar>\n <FilterSelect\n label=\"Category\"\n value={categoryFilter}\n onChange={setCategoryFilter}\n options={categories.map((c) => ({ value: c, label: c }))}\n />\n <FilterSelect\n label=\"Type\"\n value={typeFilter}\n onChange={setTypeFilter}\n options={eventTypes.map((t) => ({ value: t, label: t }))}\n />\n <button\n onClick={() => setSortOrder((s) => (s === 'asc' ? 'desc' : 'asc'))}\n className=\"btn-ghost text-xs\"\n >\n {sortOrder === 'asc' ? 'Oldest first' : 'Newest first'}\n </button>\n </FilterBar>\n </div>\n\n <div>\n {filtered.length === 0 ? (\n <div className=\"px-6 py-8 text-center\">\n <p className=\"text-sm text-text-tertiary\">No events match the current filters</p>\n </div>\n ) : (\n filtered.map((evt) => {\n const isExpanded = expandedEvents.has(evt.event_id);\n const pending = isPending(evt);\n\n return (\n <div\n key={evt.event_id}\n className=\"border-b border-surface-border last:border-b-0\"\n >\n {/* Row header */}\n <div\n className=\"px-6 py-3 flex items-center gap-4 cursor-pointer hover:bg-surface-hover transition-colors duration-200\"\n onClick={() => toggleEvent(evt.event_id)}\n >\n {/* Expand chevron */}\n <span\n className={`text-[10px] text-text-tertiary transition-transform duration-300 ${isExpanded ? 'rotate-90' : ''}`}\n >\n &#9654;\n </span>\n\n <span className=\"text-xs font-mono text-text-tertiary w-8 shrink-0\">\n {evt.event_id}\n </span>\n <span\n className={`w-2 h-2 rounded-full dot-ring shrink-0 ${categoryDot(evt.category)}`}\n />\n <span className=\"text-sm text-text-primary flex-1 truncate\">\n {eventLabel(evt)}\n </span>\n <span className=\"text-xs font-mono text-text-tertiary shrink-0\">\n {pending ? (\n <span className=\"inline-flex items-center gap-1 text-status-warning\">\n <span className=\"w-1.5 h-1.5 rounded-full dot-ring bg-status-warning animate-pulse\" />\n Pending\n </span>\n ) : evt.duration_ms !== null ? (\n formatDuration(evt.duration_ms)\n ) : (\n '--'\n )}\n </span>\n <time className=\"text-[10px] font-mono text-text-tertiary shrink-0\">\n {new Date(evt.event_time).toLocaleTimeString()}\n </time>\n </div>\n\n {/* Inline detail panel — directly below the clicked row */}\n <Collapsible open={isExpanded && !!evt.attributes}>\n <div className=\"px-6 pb-4 pl-16\">\n <EventDetailPanel\n event={evt}\n childTask={findChildTask(evt)}\n pending={pending}\n jid={jid}\n appId={appId}\n onClose={() => toggleEvent(evt.event_id)}\n />\n </div>\n </Collapsible>\n </div>\n );\n })\n )}\n </div>\n </div>\n );\n}\n"],"names":["STARTED_TYPES","COMPLETED_TYPES","buildCompletedKeys","events","keys","e","EventTable","childTasks","jid","appId","categoryFilter","setCategoryFilter","useState","typeFilter","setTypeFilter","sortOrder","setSortOrder","expandedEvents","setExpandedEvents","categories","eventTypes","completedKeys","isPending","evt","tlk","filtered","a","b","categoryDot","category","eventLabel","base","id","truncated","findChildTask","activityType","t","toggleEvent","prev","next","allExpanded","toggleAll","jsxs","jsx","FilterBar","FilterSelect","c","s","isExpanded","pending","formatDuration","Collapsible","EventDetailPanel"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{b as R,a as m,j as e}from"./vendor-query-B2UbickB.js";import{b as D,c as L}from"./pipelines-Ihi7EKXi.js";import{u as J,c as K,D as M,b as S,J as _,N as U}from"./index-DwWP-Z_c.js";import{S as $}from"./StatusBadge-DZ9137bI.js";import{P as E}from"./PageHeader-DJo7yMUR.js";import{C as A}from"./CopyableId-blg-gZvT.js";import{C as b}from"./CollapsibleSection-Ds0e8cCO.js";import{u as V}from"./useCollapsedSections-BU5HULGs.js";import{L as q}from"./ListToolbar-Dz2_neVF.js";import{S as B}from"./SwimlaneTimeline-BrfmWgAj.js";import{E as F}from"./EventTable-BARJeiS2.js";import{e as H,f as Q}from"./vendor-react-CXumBFUA.js";import"./vendor-icons-DOIDKgo6.js";import"./StreamMessageDetail-jOJaoupp.js";import"./FilterBar-B4Mk2PvT.js";const z={running:"in_progress",completed:"completed",failed:"failed"};function O({isRunning:a,onTerminate:l}){const[s,n]=m.useState(!1),t=m.useRef(null);return m.useEffect(()=>{if(!s)return;const o=i=>{t.current&&!t.current.contains(i.target)&&n(!1)};return document.addEventListener("mousedown",o),()=>document.removeEventListener("mousedown",o)},[s]),a?e.jsxs("div",{className:"relative",ref:t,children:[e.jsx("button",{onClick:()=>n(!s),className:"btn-primary text-xs",children:"Actions"}),s&&e.jsx("div",{className:"absolute right-0 mt-1 w-44 bg-surface-raised border border-surface-border rounded-md shadow-lg z-10",children:e.jsx("button",{onClick:()=>{l(),n(!1)},className:"block w-full text-left px-4 py-2 text-xs text-status-error hover:bg-surface-hover",children:"Terminate"})})]}):null}function de(){var N,w;const{jobId:a}=H(),[l]=Q(),s=l.get("namespace")||"",n=R(),{data:t,isLoading:o,error:i,refetch:v,isFetching:T}=D(a,s),C=L(),{data:u}=J(),{isCollapsed:p,toggle:f}=V("mcp-run-detail"),g=((N=u==null?void 0:u.telemetry)==null?void 0:N.traceUrl)??null,I=m.useCallback(x=>{!a||x.workflowId!==a||n.invalidateQueries({queryKey:["mcpRunExecution",a]})},[a,n]);if(K(`${U}.system.>`,I),o)return e.jsxs("div",{className:"animate-pulse space-y-4",children:[e.jsx("div",{className:"h-8 bg-surface-sunken rounded w-64"}),e.jsx("div",{className:"h-60 bg-surface-sunken rounded"})]});if(i||!t)return e.jsxs("div",{children:[e.jsx(E,{title:"Pipeline Execution"}),e.jsxs("div",{className:"mt-4 text-center py-8",children:[e.jsx("p",{className:"text-sm text-text-primary mb-1",children:(w=i==null?void 0:i.message)!=null&&w.includes("expired")?"Execution data is no longer available":"Unable to load execution"}),e.jsx("p",{className:"text-xs text-text-tertiary",children:(i==null?void 0:i.message)??"The run could not be resolved."})]})]});const{events:j,summary:r}=t,h=j.find(x=>{var k;return x.category==="activity"&&((k=x.attributes.kind)==null?void 0:k.includes("completed"))}),P=(h==null?void 0:h.attributes.result)??null,d=t.result,y=(d==null?void 0:d.data)??d??null;return e.jsxs("div",{children:[e.jsx(E,{title:"Pipeline Execution",actions:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(q,{onRefresh:()=>v(),isFetching:T,apiPath:`/pipelines/${a}/execution?app_id=${s}`}),e.jsx(O,{isRunning:t.status==="running",onTerminate:()=>{confirm("Interrupt this pipeline execution? This cannot be undone.")&&C.mutate({jobId:t.workflow_id,topic:t.workflow_type,appId:s},{onSuccess:()=>v()})}})]})}),e.jsxs("div",{className:"bg-surface-sunken/50 rounded-md p-5 mb-8",children:[e.jsxs("div",{className:"flex items-center gap-4 mb-4",children:[e.jsx("h2",{className:"text-sm font-mono text-text-primary truncate flex-1",children:t.workflow_id}),e.jsxs("div",{className:"flex items-center gap-4 shrink-0",children:[e.jsx(c,{label:"Tools",value:r.activities.user}),e.jsx(c,{label:"System",value:r.activities.system,muted:!0}),r.child_workflows.total>0&&e.jsx(c,{label:"Children",value:r.child_workflows.total}),r.timers>0&&e.jsx(c,{label:"Timers",value:r.timers}),r.signals>0&&e.jsx(c,{label:"Signals",value:r.signals}),e.jsx($,{status:z[t.status]??t.status})]})]}),e.jsxs("div",{className:"grid grid-cols-6 gap-x-6",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-0.5",children:"Server"}),e.jsx("p",{className:"text-xs font-mono text-text-primary truncate",children:s})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-0.5",children:"Tool"}),e.jsx("p",{className:"text-xs font-mono text-text-primary truncate",children:t.workflow_type||"—"})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-0.5",children:"Duration"}),e.jsx(M,{ms:t.duration_ms,className:"font-mono text-text-primary"})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-0.5",children:"Started"}),t.start_time?e.jsx(S,{date:t.start_time,format:"datetime",className:"font-mono text-text-primary"}):e.jsx("span",{className:"text-xs text-text-tertiary",children:"--"})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-0.5",children:"Completed"}),t.close_time?e.jsx(S,{date:t.close_time,format:"datetime",className:"font-mono text-text-primary"}):e.jsx("span",{className:"text-xs text-text-tertiary",children:"--"})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-0.5",children:"Trace"}),t.trace_id?e.jsx(A,{label:"",value:t.trace_id,href:g?g.replace("{traceId}",t.trace_id):void 0,external:!0}):e.jsx("span",{className:"text-xs text-text-tertiary",children:"—"})]})]})]}),e.jsxs("div",{className:"space-y-6",children:[e.jsx(b,{title:"Details",sectionKey:"details",isCollapsed:p("details"),onToggle:f,children:e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4 mb-6",children:[e.jsx("div",{children:e.jsx(_,{data:P??{},label:"Input"})}),y!==null&&e.jsx("div",{children:e.jsx(_,{data:y,label:"Result"})})]})}),e.jsx(b,{title:"Execution Timeline",sectionKey:"timeline",isCollapsed:p("timeline"),onToggle:f,children:e.jsx(B,{events:j,outline:!0,jid:a,appId:s||"durable"})}),e.jsx(b,{title:"Events",sectionKey:"events",isCollapsed:p("events"),onToggle:f,children:e.jsx(F,{events:j,jid:a,appId:s||"durable"})})]})]})}function c({label:a,value:l,muted:s}){return e.jsxs("div",{className:"flex items-center gap-1.5 text-xs",children:[e.jsx("span",{className:"text-text-tertiary",children:a}),e.jsx("span",{className:`font-medium tabular-nums ${s?"text-text-tertiary":"text-text-primary"}`,children:l})]})}export{de as McpRunDetailPage};
2
- //# sourceMappingURL=McpRunDetailPage-BzzZIXIk.js.map
@@ -1,2 +0,0 @@
1
- import{a as w,j as e}from"./vendor-query-B2UbickB.js";import{c as Pe}from"./roles-D4Wn7kE9.js";import{O as ye}from"./index-DwWP-Z_c.js";import{i as Se}from"./useEventHooks-Dn_vN2xE.js";import{P as Ce}from"./PageHeader-DJo7yMUR.js";import{X as Me,ae as ie,av as Le,ar as qe}from"./vendor-icons-DOIDKgo6.js";import{L as Q,f as Fe,c as Oe}from"./vendor-react-CXumBFUA.js";const ge=800,je=270,I=40,Ae=76,ce=24,Ee=72,oe=ge-I-Ae,be=je-ce-Ee,$=ce+be,he=I+oe,j="0.5s cubic-bezier(0.4, 0, 0.2, 1)",me=9;function We(t){return`M ${(t.x-me).toFixed(1)} ${t.y.toFixed(1)} L ${(t.x+me).toFixed(1)} ${t.y.toFixed(1)}`}function T(t){if(t.length===0)return"";if(t.length===1)return We(t[0]);const n=[];for(let l=0;l<t.length-1;l++){const i=t[Math.max(0,l-1)],c=t[l],p=t[l+1],a=t[Math.min(t.length-1,l+2)],d=(c.x+(p.x-i.x)/6).toFixed(1),u=(c.y+(p.y-i.y)/6).toFixed(1),o=(p.x-(a.x-c.x)/6).toFixed(1),x=(p.y-(a.y-c.y)/6).toFixed(1);l===0&&n.push(`M ${c.x.toFixed(1)} ${c.y.toFixed(1)}`),n.push(`C ${d} ${u}, ${o} ${x}, ${p.x.toFixed(1)} ${p.y.toFixed(1)}`)}return n.join(" ")}function Ie(t,n){if(t.length<2||n.length<2)return"";const l=T(t),i=[...n].reverse(),c=T(i),p=c.slice(c.indexOf("C"));return`${l} L ${i[0].x.toFixed(1)} ${i[0].y.toFixed(1)} ${p} Z`}function Te(t){return t>=1e4?`${Math.round(t/1e3)}k`:t>=1e3?`${(t/1e3).toFixed(1)}k`:String(t)}function ne(t){return t.length>0?t[t.length-1]:void 0}const O="#6366f1",D="#0ea5e9",q="#1E3A8A",X="#059669",ve="#b0e0e6",A="#5b93ad",De=13;function Be(t,n){const l=[...t].sort((a,d)=>a.y-d.y);let i=-1/0;const c=l.map(a=>{const d=Math.max(a.y+3,i+De);return i=d,{...a,labelY:d}}),p=c.length>0?c[c.length-1].labelY-n:0;if(p>0)for(const a of c)a.labelY-=p;return c}function ze({stations:t,selectedRole:n,onSelect:l,onUpstreamSelect:i,onPrioritySelect:c,periodHours:p}){const[a,d]=w.useState(null),u=t.length;if(u===0)return null;const o=s=>u===1?I+oe/2:I+s/(u-1)*oe,x=new Map(t.map((s,h)=>[s.role,o(h)])),y=t.map((s,h)=>{var P,V,G,U;const f=s.target_per_hour??null,C=f!=null?f*p:null;return{idx:h,x:o(h),expected:C,actual:((P=s.metric)==null?void 0:P.resolved)??0,active:((V=s.metric)==null?void 0:V.claimed)??0,pending:((G=s.metric)==null?void 0:G.pending)??0,priorityCount:((U=s.metric)==null?void 0:U.priority_count)??0}}),b=y.some(s=>s.expected!=null),v=Math.max(1,...y.map(s=>s.expected??0),...y.map(s=>s.actual),...y.map(s=>s.expected!=null?s.pending:0))*1.15,S=s=>ce+be*(1-Math.max(0,Math.min(s,v))/v),N=y.filter(s=>s.expected!=null),M=N.map(s=>({...s,y:S(s.expected)})),_=N.map(s=>({...s,y:S(s.actual)})),R=N.map(s=>({...s,y:S(s.active)})),k=N.map(s=>({...s,y:S(s.pending)})),B=T(M),z=T(_),H=T(R),Z=T(k),F=ne(_),K=ne(M),E=ne(R),J=ne(k),ee=_.length>=2&&F?`${z} L ${F.x.toFixed(1)} ${$} L ${_[0].x.toFixed(1)} ${$} Z`:"",W=N.some(s=>s.pending>0||s.active>0),te=W&&R.length>=2&&E?`${H} L ${E.x.toFixed(1)} ${$} L ${R[0].x.toFixed(1)} ${$} Z`:"",Y=W?Ie(k,R):"",r=N.some(s=>s.active>0),m=N.some(s=>s.pending>s.active),L=Be([K?{key:"target",text:"Target",color:X,y:K.y}:null,F?{key:"actual",text:"Resolved",color:q,y:F.y}:null,r&&E?{key:"active",text:"Claimed",color:O,y:E.y}:null,m&&J?{key:"queued",text:"Pending",color:D,y:J.y}:null].filter(Boolean),$+4);return e.jsxs("svg",{viewBox:`0 0 ${ge} ${je}`,className:"w-full h-full",preserveAspectRatio:"xMidYMid meet",style:{display:"block"},children:[t.map(s=>{if(!s.parent_role)return null;const h=x.get(s.parent_role);if(h==null)return null;const f=o(t.findIndex(C=>C.role===s.role));return e.jsx("line",{x1:h,y1:$,x2:f,y2:$,stroke:"#e2e8f0",strokeWidth:.75},`dep-${s.role}`)}),ee&&e.jsx("path",{d:ee,fill:q,opacity:.05,style:{transition:`d ${j}`}}),te&&e.jsx("path",{d:te,fill:O,opacity:.12,style:{transition:`d ${j}`}}),Y&&e.jsx("path",{d:Y,fill:D,opacity:.12,style:{transition:`d ${j}`}}),B&&e.jsx("path",{d:B,fill:"none",stroke:X,strokeWidth:.5,strokeLinejoin:"round",opacity:.9,style:{transition:`d ${j}`}}),M.map(s=>e.jsx("text",{x:s.x,y:s.y-3.5,textAnchor:"middle",fontSize:6.5,fill:X,fontFamily:"ui-monospace, monospace",fontWeight:"500",opacity:.7,style:{transition:`y ${j}`},children:Math.round(s.expected)},`tval-${s.idx}`)),W&&Z&&e.jsx("path",{d:Z,fill:"none",stroke:D,strokeWidth:.75,strokeDasharray:"2 3",strokeLinecap:"round",opacity:.55,style:{transition:`d ${j}`}}),H&&e.jsx("path",{d:H,fill:"none",stroke:O,strokeWidth:.75,strokeDasharray:"2 3",strokeLinecap:"round",opacity:.5,style:{transition:`d ${j}`}}),z&&e.jsx("path",{d:z,fill:"none",stroke:q,strokeWidth:.6,strokeLinejoin:"round",strokeLinecap:"round",opacity:.65,style:{transition:`d ${j}`}}),R.map((s,h)=>{if(s.pending<=0&&s.active<=0)return null;const f=Math.max(2.5,Math.min(5,2.5+s.active/10)),C=s.pending>s.active,P=Math.min(k[h].y-4,s.y-f-4);return e.jsxs("g",{children:[s.pending>0&&e.jsx("text",{x:s.x,y:P,textAnchor:"middle",fontSize:7.5,fill:C?D:"#64748b",fontFamily:"ui-monospace, monospace",fontWeight:"600",style:{transition:`y ${j}`},children:s.pending}),e.jsxs("g",{transform:`translate(${s.x} ${s.y})`,style:{transition:`transform ${j}`},children:[e.jsx("circle",{r:f,fill:O,opacity:.85}),s.active>0&&e.jsx("text",{y:f+9,textAnchor:"middle",fontSize:7.5,fill:O,fontFamily:"ui-monospace, monospace",fontWeight:"600",children:s.active})]})]},`active-${s.idx}`)}),y.map(s=>{var ue;const h=t[s.idx],f=s.x,C=s.expected!=null?S(s.actual):$,P=Math.max(2.25,Math.min(4,2.25+s.actual/160)),V=h.role===n,G=a===s.idx,U=s.expected==null?"idle · set a target rate to plot pace":`${s.actual} resolved · target ${Math.round(s.expected)}`+(s.pending>s.active?` · ${s.pending-s.active} pending`:"")+(s.active>0?` · ${s.active} claimed`:"")+(s.priorityCount>0?` · ${s.priorityCount} priority`:""),se=U.length*5.5+20,de=Math.max(I+se/2+4,Math.min(he-se/2-4,f)),pe=C-P-10;return e.jsxs("g",{onClick:()=>l(h.role),onMouseEnter:()=>d(s.idx),onMouseLeave:()=>d(null),style:{cursor:"pointer"},children:[e.jsxs("g",{transform:`translate(${f} ${C})`,style:{transition:`transform ${j}`},children:[e.jsx("circle",{r:22,fill:"transparent"}),e.jsx("circle",{r:P,fill:q,opacity:.9,style:{transition:`r ${j}`}}),s.expected!=null&&e.jsx("text",{y:-P-5,textAnchor:"middle",fontSize:9.5,fill:q,fontFamily:"ui-monospace, monospace",fontWeight:"500",children:Te(s.actual)}),G&&!V&&e.jsx("circle",{r:P+3,fill:"none",stroke:q,strokeWidth:1,opacity:.4}),V&&e.jsx("circle",{r:P+4,fill:"none",stroke:"#6366f1",strokeWidth:2})]}),s.priorityCount>0&&e.jsxs("g",{transform:`translate(${f+15} ${Math.max(C-15,12)})`,onClick:le=>{le.stopPropagation(),c==null||c(h.role)},style:{cursor:"pointer",transition:`transform ${j}`},children:[e.jsx("title",{children:`${s.priorityCount} past the priority threshold — click to pull oldest first`}),e.jsx("circle",{r:6.5+(String(s.priorityCount).length-1)*2,fill:ve,opacity:.9}),e.jsx("text",{y:2.5,textAnchor:"middle",fontSize:7,fill:A,fontFamily:"ui-monospace, monospace",fontWeight:"700",children:s.priorityCount})]}),(((ue=h.upstream_roles)==null?void 0:ue.length)??0)>0&&e.jsxs("g",{transform:`translate(${f-20} ${$})`,onClick:le=>{le.stopPropagation(),i==null||i(h.upstream_roles[0])},style:{cursor:"pointer"},children:[e.jsx("title",{children:`Fed by ${h.upstream_roles.join(", ")} — click to view that sequence`}),e.jsx("circle",{r:9,cy:-6,fill:"transparent"}),e.jsx("path",{d:"M -7 -14 C -3 -14 -1 -9 0 -2",fill:"none",stroke:"#94a3b8",strokeWidth:1,strokeDasharray:"2 2",strokeLinecap:"round"}),e.jsx("path",{d:"M 0 -2 L 8 -2",stroke:"#94a3b8",strokeWidth:1,strokeLinecap:"round"}),e.jsx("path",{d:"M 8 -2 l -3.5 -2 v 4 z",fill:"#94a3b8"})]}),e.jsx("text",{x:f,y:$+14,textAnchor:"middle",fontSize:9.5,fill:"#475569",fontFamily:"ui-sans-serif, sans-serif",fontWeight:"500",children:h.title??h.role}),e.jsx("text",{x:f,y:$+26,textAnchor:"middle",fontSize:8,fill:"#94a3b8",fontFamily:"ui-monospace, monospace",children:h.role}),G&&e.jsxs("g",{children:[e.jsx("rect",{x:de-se/2,y:pe-16,width:se,height:19,rx:3,fill:"#0f172a",opacity:.88}),e.jsx("text",{x:de,y:pe-3,textAnchor:"middle",fontSize:8.5,fill:"white",fontFamily:"ui-monospace, monospace",children:U})]})]},h.role)}),!b&&e.jsx("text",{x:I+oe/2,y:$+48,textAnchor:"middle",fontSize:8.5,fill:"#94a3b8",fontFamily:"ui-sans-serif, sans-serif",children:"Set target_per_hour on each role in Admin → Roles to enable the pace chart"}),L.map(s=>e.jsx("text",{x:he+6,y:s.labelY,fontSize:8,fill:s.color,fontFamily:"ui-sans-serif, sans-serif",fontWeight:s.key==="actual"?700:500,opacity:s.key==="active"?.85:1,style:{transition:`y ${j}`},children:s.text},s.key))]})}function xe(t){const n=`/escalations/available?role=${encodeURIComponent(t.role)}`;if(t.priority_facet){const l=JSON.stringify([{field:`metadata.${t.priority_facet}`,direction:"asc"}]);return`${n}&orderBy=${encodeURIComponent(l)}`}return`${n}&sort_by=created_at&order=asc`}const Ne=["15m","1h","24h","7d","30d"],He=t=>Ne.includes(t);function ae(t){if(t==null)return"—";if(t<1){const n=Math.round(t*60);return n<=0?"< 1s":`${n}s`}return t<60?`${t.toFixed(0)}m`:`${(t/60).toFixed(1)}h`}function re({label:t,value:n}){return e.jsxs("div",{className:"flex items-center justify-between py-1",children:[e.jsx("span",{className:"text-[10px] text-text-tertiary uppercase tracking-wider",children:t}),e.jsx("span",{className:"text-xs font-mono font-medium text-text-primary tabular-nums",children:n})]})}function Ye({period:t,onChange:n}){return e.jsx("div",{className:"flex items-center gap-1 mb-4",children:Ne.map(l=>e.jsx("button",{onClick:()=>n(l),className:`px-2 py-0.5 text-[10px] font-mono rounded transition-colors ${t===l?"bg-accent/10 text-accent font-semibold":"text-text-quaternary hover:text-text-secondary"}`,children:l},l))})}function Ve({role:t,globalPeriod:n,onClose:l}){const[i,c]=w.useState(He(n)?n:"24h"),{data:p}=ye(i),a=p==null?void 0:p.stations.find(x=>x.role===t.role),d=t.sla_minutes??void 0,u=t.target_per_hour??void 0,o=t.worker_count??void 0;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-start justify-between mb-1",children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex items-baseline gap-1.5 flex-wrap",children:[e.jsx("span",{className:"text-sm font-mono font-bold text-text-primary",children:t.role}),t.title&&e.jsx("span",{className:"text-[10px] text-text-secondary",children:t.title})]}),t.description&&e.jsx("p",{className:"text-[10px] text-text-tertiary mt-0.5 line-clamp-2 leading-relaxed",children:t.description})]}),e.jsx("button",{onClick:l,className:"text-text-quaternary hover:text-text-secondary transition-colors mt-0.5 shrink-0 ml-2",children:e.jsx(Me,{className:"w-4 h-4"})})]}),e.jsxs(Q,{to:`/admin/roles/${encodeURIComponent(t.role)}`,className:"flex items-center gap-1 text-[10px] text-accent hover:underline mb-4",children:[e.jsx(ie,{className:"w-2.5 h-2.5"}),"Edit in Roles"]}),e.jsx(Ye,{period:i,onChange:c}),(u||d||o)&&e.jsxs("div",{className:"flex items-center gap-4 mb-4 text-[10px]",children:[u&&e.jsxs("div",{children:[e.jsxs("div",{className:"font-mono font-semibold text-text-primary",children:[u,"/h"]}),e.jsx("div",{className:"text-text-quaternary uppercase tracking-wider text-[8.5px]",children:"target"})]}),d&&e.jsxs("div",{children:[e.jsxs("div",{className:"font-mono font-semibold text-text-primary",children:[d,"m"]}),e.jsx("div",{className:"text-text-quaternary uppercase tracking-wider text-[8.5px]",children:"SLA"})]}),o&&e.jsxs("div",{children:[e.jsx("div",{className:"font-mono font-semibold text-text-primary",children:o}),e.jsx("div",{className:"text-text-quaternary uppercase tracking-wider text-[8.5px]",children:"workers"})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-x-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-[9px] text-text-quaternary uppercase tracking-wider mb-1.5",children:"Wait (queue)"}),e.jsx(re,{label:"P99",value:ae((a==null?void 0:a.wait.p99)??null)}),e.jsx(re,{label:"avg",value:ae((a==null?void 0:a.wait.avg)??null)})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-[9px] text-text-quaternary uppercase tracking-wider mb-1.5",children:"Work (proc.)"}),e.jsx(re,{label:"P99",value:ae((a==null?void 0:a.work.p99)??null)}),e.jsx(re,{label:"avg",value:ae((a==null?void 0:a.work.avg)??null)})]})]}),e.jsxs("div",{className:"border-t border-surface-border/40 pt-2 mt-3 space-y-1.5",children:[d&&e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-[10px] text-text-tertiary",children:"SLA target"}),e.jsxs("span",{className:"text-xs font-mono text-text-secondary",children:[d,"m"]})]}),a&&a.priority_count>0&&e.jsxs(Q,{to:xe(t),className:"flex items-center justify-between group",children:[e.jsxs("span",{className:"text-[10px]",style:{color:A},children:[a.priority_count," priority — pull oldest first"]}),e.jsx(ie,{className:"w-3 h-3 transition-colors",style:{color:A}})]})]}),e.jsx("div",{className:"mt-4 border-t border-surface-border/40 pt-3",children:e.jsxs(Q,{to:`/escalations/available?role=${encodeURIComponent(t.role)}`,className:"flex items-center gap-1.5 text-[10px] text-accent hover:underline",children:["View full queue",e.jsx(ie,{className:"w-2.5 h-2.5"})]})})]})}function Ge({allMetrics:t,orderedRoles:n,period:l}){const i=t.reduce((o,x)=>o+x.pending,0),c=t.reduce((o,x)=>o+x.resolved,0),p=t.reduce((o,x)=>o+x.priority_count,0),a=new Map(t.map(o=>[o.role,o])),d=t.filter(o=>o.priority_count>0).length,u=t.filter(o=>o.pending>0).length;return e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"text-[9px] text-text-quaternary uppercase tracking-wider mb-3",children:["Pipeline · ",l]}),e.jsx("div",{className:"mb-4",children:d>0?e.jsxs("p",{className:"text-[11px]",style:{color:A},children:[d," station",d>1?"s":""," with priority items"]}):u>0?e.jsxs("p",{className:"text-[11px] text-status-warning",children:[u," station",u>1?"s":""," with backlog"]}):c>0?e.jsx("p",{className:"text-[11px] text-status-success",children:"Flowing — queue clear"}):e.jsx("p",{className:"text-[11px] text-text-quaternary",children:"Quiet — awaiting work"})}),e.jsxs("div",{className:"space-y-1.5 mb-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-[9px] text-text-quaternary uppercase tracking-wider",children:"Pending"}),e.jsx("span",{className:`text-xs font-mono tabular-nums ${i>0?"text-text-primary font-semibold":"text-text-quaternary"}`,children:i})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-[9px] text-text-quaternary uppercase tracking-wider",children:["Resolved · ",l]}),e.jsx("span",{className:"text-xs font-mono tabular-nums text-text-secondary",children:c})]}),p>0&&e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-[9px] text-text-quaternary uppercase tracking-wider",children:"Priority"}),e.jsx("span",{className:"text-xs font-mono tabular-nums font-semibold",style:{color:A},children:p})]})]}),e.jsx("div",{className:"border-t border-surface-border/40 pt-2 mb-1",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-[8px] text-text-quaternary uppercase tracking-wider flex-1",children:"Station"}),e.jsx("span",{className:"text-[8px] text-text-quaternary uppercase tracking-wider w-8 text-right shrink-0",children:"pend"}),e.jsx("span",{className:"text-[8px] text-text-quaternary uppercase tracking-wider w-8 text-right shrink-0",children:"clmd"}),e.jsx("span",{className:"text-[8px] text-text-quaternary uppercase tracking-wider w-8 text-right shrink-0",children:"res"})]})}),e.jsx("div",{className:"space-y-0.5",children:n.map(o=>{const x=a.get(o.role),y=(x==null?void 0:x.pending)??0,b=(x==null?void 0:x.claimed)??0,g=(x==null?void 0:x.resolved)??0,v=(x==null?void 0:x.priority_count)??0,S=o.title||o.role,N=v>0,M=y>0;return e.jsxs("div",{className:"flex items-center gap-2 py-0.5",children:[e.jsxs("span",{className:`text-[10px] font-mono flex-1 truncate ${M?"text-text-primary":"text-text-quaternary"}`,children:[S,N&&e.jsxs("span",{className:"ml-1 text-[8px] font-semibold",style:{color:A},children:[v," PRIORITY"]})]}),e.jsx("span",{className:`text-[10px] font-mono tabular-nums w-8 text-right shrink-0 ${M?"text-text-primary font-semibold":"text-text-quaternary"}`,children:y>0?y:"—"}),e.jsx("span",{className:`text-[10px] font-mono tabular-nums w-8 text-right shrink-0 ${b>0?"text-accent":"text-text-quaternary"}`,children:b>0?b:"—"}),e.jsx("span",{className:`text-[10px] font-mono tabular-nums w-8 text-right shrink-0 ${g>0?"text-text-secondary":"text-text-quaternary"}`,children:g>0?g:"—"})]},o.role)})}),e.jsx("p",{className:"text-[9px] text-text-quaternary mt-5",children:"Select a station for queue detail."})]})}function Ue({role:t,allMetrics:n,orderedRoles:l,globalPeriod:i,onClose:c}){return e.jsx("div",{className:"w-[280px] shrink-0 px-6 py-8 flex flex-col overflow-y-auto min-h-0",children:t?e.jsx(Ve,{role:t,globalPeriod:i,onClose:c}):e.jsx(Ge,{allMetrics:n,orderedRoles:l,period:i})})}const ke=`${X}14`,$e=`${D}14`,we=`${O}14`,_e=`${q}14`,Qe=["15m","1h","24h","7d","30d"],Xe={"15m":.25,"1h":1,"24h":24,"7d":168,"30d":720};function Re(t){const n=t.filter(a=>a.ops_visible),l=new Map(n.map(a=>[a.role,a])),i=new Set,p=n.filter(a=>!a.parent_role||!l.has(a.parent_role)).map(a=>{const d=[],u=[{role:a,depth:0}];for(;u.length>0;){const o=u.shift();i.has(o.role.role)||(i.add(o.role.role),d.push(o),n.filter(x=>x.parent_role===o.role.role&&!i.has(x.role)).forEach(x=>u.push({role:x,depth:o.depth+1})))}return{origin:a,stations:d}});return n.filter(a=>!i.has(a.role)).forEach(a=>p.push({origin:a,stations:[{role:a,depth:0}]})),p.sort((a,d)=>d.stations.length-a.stations.length||a.origin.role.localeCompare(d.origin.role))}function fe(t){if(t==null)return"—";if(t<1){const n=Math.round(t*60);return n<=0?"< 1s":`${n}s`}return t<60?`${t.toFixed(0)}m`:`${(t/60).toFixed(1)}h`}function Ze(t,n){if(!n||t===0)return{pct:null,color:"bg-surface-border"};const l=t/n,i=Math.round(l*100),c=l>1?"bg-status-warning":l<.2?"bg-status-draft":"bg-status-success";return{pct:i,color:c}}function Ke({role:t,metric:n,selected:l,onClick:i}){var b;const c=(n==null?void 0:n.pending)??0,p=(n==null?void 0:n.claimed)??0,a=(n==null?void 0:n.resolved)??0,d=(n==null?void 0:n.priority_count)??0,u=t.target_per_hour??null,{pct:o,color:x}=Ze(c,u),y=o!=null?Math.min(100,o):0;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{role:"button",tabIndex:0,onClick:i,onKeyDown:g=>{g.key==="Enter"&&i()},className:`grid items-center gap-4 pr-3 cursor-pointer transition-colors ${l?"border-l-2 !border-l-accent pl-2.5":"pl-3"}`,style:{gridTemplateColumns:"1fr 64px 56px 56px 60px 72px 72px 104px"},children:[e.jsxs("div",{className:"flex items-center gap-1.5 min-w-0 py-1.5",children:[e.jsx("span",{className:"font-mono font-bold text-text-primary truncate text-[11px]",children:t.role}),t.title&&e.jsx("span",{className:"text-[10px] text-text-tertiary truncate",children:t.title}),(((b=t.upstream_roles)==null?void 0:b.length)??0)>0&&e.jsx("span",{title:`Fed by ${t.upstream_roles.join(", ")}`,className:"shrink-0 leading-none",children:e.jsx(qe,{className:"w-3 h-3 text-text-quaternary"})})]}),e.jsx("div",{className:"self-stretch flex items-center justify-end px-1.5",style:{backgroundColor:ke},children:e.jsx("span",{className:`text-xs font-mono tabular-nums ${u!=null?"text-text-secondary":"text-text-quaternary"}`,children:u??"—"})}),e.jsx("div",{className:"self-stretch flex items-center justify-end px-1.5",style:{backgroundColor:$e},children:e.jsx("span",{className:`text-xs font-mono tabular-nums ${c>0?"text-text-primary font-semibold":"text-text-quaternary"}`,children:c})}),e.jsx("div",{className:"self-stretch flex items-center justify-end px-1.5",style:{backgroundColor:we},children:e.jsx("span",{className:`text-xs font-mono tabular-nums ${p>0?"text-accent font-semibold":"text-text-quaternary"}`,children:p})}),e.jsx("div",{className:"self-stretch flex items-center justify-end px-1.5",style:{backgroundColor:_e},children:e.jsx("span",{className:"text-xs font-mono tabular-nums text-text-quaternary",children:a})}),e.jsx("span",{className:"text-xs font-mono tabular-nums text-right py-1.5 text-text-secondary",children:fe((n==null?void 0:n.wait.p99)??null)}),e.jsx("span",{className:"text-xs font-mono tabular-nums text-right py-1.5 text-text-secondary",children:fe((n==null?void 0:n.work.p99)??null)}),e.jsxs("div",{className:"flex items-center gap-2 py-1.5",children:[e.jsx("div",{className:"w-12 h-1.5 bg-surface-sunken rounded-full overflow-hidden shrink-0",children:e.jsx("div",{className:`h-full rounded-full ${x}`,style:{width:`${y}%`}})}),e.jsx("span",{className:`text-[10px] font-mono tabular-nums ${o!=null&&o>100?"text-status-warning font-semibold":"text-text-quaternary"}`,children:o!=null?`${o}%`:"—"})]})]}),d>0&&e.jsxs("div",{className:"flex items-center gap-1.5 pb-2 pl-3.5",children:[e.jsx("span",{className:"w-2.5 h-2.5 rounded-full dot-ring shrink-0",style:{backgroundColor:ve}}),e.jsxs(Q,{to:xe(t),className:"text-[10px] hover:underline",style:{color:A},onClick:g=>g.stopPropagation(),children:[d," priority — pull oldest first →"]})]})]})}function Je(){const t=[{label:"ROLE"},{label:"TARGET/H",band:ke,hue:X},{label:"PENDING",band:$e,hue:D},{label:"CLAIMED",band:we,hue:O},{label:"RESOLVED",band:_e,hue:q},{label:"P99 WAIT"},{label:"P99 WORK"},{label:"TREND"}];return e.jsx("div",{className:"grid items-center gap-4 px-3 border-b border-surface-border mb-0.5",style:{gridTemplateColumns:"1fr 64px 56px 56px 60px 72px 72px 104px"},children:t.map((n,l)=>n.band?e.jsx("div",{className:"self-stretch flex items-center justify-end px-1.5",style:{backgroundColor:n.band},children:e.jsx("span",{className:"text-[9px] font-semibold uppercase tracking-wider",style:{color:n.hue},children:n.label})},n.label):e.jsx("span",{className:`text-[9px] font-semibold uppercase tracking-wider text-text-quaternary py-1.5 ${l>0&&l<7?"text-right":""}`,children:n.label},n.label))})}function et(){var Y;const[t,n]=w.useState("1h"),[l,i]=w.useState(null),[c,p]=w.useState(!1);Se();const{data:a,isLoading:d,refetch:u}=Pe(),{data:o,isLoading:x,refetch:y}=ye(t),b=(a==null?void 0:a.roles)??[],g=(o==null?void 0:o.stations)??[],v=w.useMemo(()=>Re(b),[b]),[S,N]=Fe(),M=S.get("fragment"),_=v.find(r=>r.origin.role===M)??v[0]??null,R=w.useCallback(r=>{i(null),N(m=>{const L=new URLSearchParams(m);return L.set("fragment",r),L})},[N]),k=(_==null?void 0:_.stations)??[],B=w.useMemo(()=>new Set(k.map(({role:r})=>r.role)),[k]),z=w.useMemo(()=>g.filter(r=>B.has(r.role)),[g,B]),H=w.useMemo(()=>k.map(({role:r})=>({role:r.role,title:r.title,parent_role:r.parent_role,target_per_hour:r.target_per_hour??null,upstream_roles:r.upstream_roles??[],metric:g.find(m=>m.role===r.role)})),[k,g]),Z=w.useCallback(r=>{const m=v.find(L=>L.stations.some(({role:s})=>s.role===r));m&&R(m.origin.role)},[v,R]),F=Oe(),K=w.useCallback(r=>{const m=b.find(L=>L.role===r);m&&F(xe(m))},[b,F]),E=((Y=k.find(({role:r})=>r.role===l))==null?void 0:Y.role)??null,J=d||x,ee=async()=>{p(!0),await Promise.all([u(),y()]),p(!1)},W=r=>i(m=>m===r?null:r),te=e.jsx("div",{className:"flex items-center gap-0.5",children:Qe.map(r=>e.jsx("button",{onClick:()=>n(r),className:`px-2.5 py-1 text-[10px] font-mono rounded transition-colors ${t===r?"bg-accent/10 text-accent font-semibold":"text-text-quaternary hover:text-text-secondary"}`,children:r},r))});return e.jsxs("div",{className:"flex flex-col flex-1 min-h-0",children:[e.jsx(Ce,{title:"Pace Board",docsHash:"#docs:dashboard.md:pace-board",center:te,actions:e.jsx("button",{onClick:ee,disabled:c,className:"text-text-quaternary hover:text-text-secondary transition-colors disabled:opacity-40",children:e.jsx(Le,{className:`w-3.5 h-3.5 ${c?"animate-spin":""}`})})}),J?e.jsxs("div",{className:"animate-pulse space-y-6 mt-4",children:[e.jsx("div",{className:"h-8 bg-surface-sunken rounded w-64"}),e.jsx("div",{className:"h-64 bg-surface-sunken rounded w-full"}),e.jsx("div",{className:"space-y-3",children:[1,2,3].map(r=>e.jsx("div",{className:"h-8 bg-surface-sunken rounded w-full"},r))})]}):v.length===0?e.jsxs("div",{className:"mt-8",children:[e.jsx("p",{className:"text-sm text-text-secondary mb-2",children:"Stations appear here once roles are marked visible in Operations."}),e.jsxs("p",{className:"text-xs text-text-tertiary",children:["Go to"," ",e.jsx(Q,{to:"/admin/roles",className:"text-accent hover:underline",children:"Roles"})," ","and enable ",e.jsx("strong",{children:"Visible in Operations"})," on roles that represent pipeline stations."]})]}):e.jsxs("div",{className:"flex flex-col flex-1 min-h-0",children:[v.length>1&&e.jsx("div",{className:"flex items-center gap-0.5 px-4 pt-2",children:v.map(r=>{const m=r.origin.role===(_==null?void 0:_.origin.role);return e.jsxs("button",{onClick:()=>R(r.origin.role),className:`px-2.5 py-1 text-[10px] font-mono rounded transition-colors ${m?"bg-accent/10 text-accent font-semibold":"text-text-quaternary hover:text-text-secondary"}`,children:[r.origin.title??r.origin.role,e.jsx("span",{className:`ml-1.5 tabular-nums ${m?"text-accent/60":"text-text-quaternary/60"}`,children:r.stations.length})]},r.origin.role)})}),e.jsxs("div",{className:"flex-1 min-h-0 flex items-stretch overflow-hidden",children:[e.jsx("div",{className:"flex-1 min-w-0 min-h-0 flex flex-col justify-center overflow-hidden p-4",children:e.jsx(ze,{stations:H,selectedRole:l,onSelect:W,onUpstreamSelect:Z,onPrioritySelect:K,periodHours:Xe[t]})}),e.jsx("div",{className:"w-px bg-surface-border shrink-0 self-stretch"}),e.jsx(Ue,{role:E,allMetrics:z,orderedRoles:k.map(r=>r.role),globalPeriod:t,onClose:()=>i(null)})]}),e.jsxs("div",{className:"max-h-[45vh] flex-none flex flex-col border-t border-surface-border overflow-hidden",children:[e.jsx(Je,{}),e.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto divide-y divide-surface-border/30",children:k.map(({role:r})=>e.jsx(Ke,{role:r,metric:g.find(m=>m.role===r.role),selected:l===r.role,onClick:()=>W(r.role)},r.role))})]})]})]})}const it=Object.freeze(Object.defineProperty({__proto__:null,OperationsPage:et,buildFragments:Re},Symbol.toStringTag,{value:"Module"}));export{it as O,ze as P,Re as b,xe as p};
2
- //# sourceMappingURL=OperationsPage-BaM-QDhy.js.map