@hotmeshio/long-tail 0.23.0 → 0.23.2

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 (277) hide show
  1. package/build/api/escalations/index.d.ts +1 -0
  2. package/build/api/escalations/index.js +4 -1
  3. package/build/api/escalations/list.d.ts +5 -0
  4. package/build/api/escalations/list.js +19 -5
  5. package/build/api/escalations/related.d.ts +18 -0
  6. package/build/api/escalations/related.js +205 -0
  7. package/build/api/roles.js +4 -0
  8. package/build/api/scan-codes/present.js +5 -1
  9. package/build/api/settings.d.ts +1 -1
  10. package/build/api/settings.js +3 -1
  11. package/build/modules/display.d.ts +15 -0
  12. package/build/modules/display.js +27 -0
  13. package/build/routes/escalations/index.js +3 -0
  14. package/build/routes/escalations/list.js +2 -0
  15. package/build/routes/escalations/related.d.ts +7 -0
  16. package/build/routes/escalations/related.js +60 -0
  17. package/build/scripts/consolidation-sim.d.ts +25 -0
  18. package/build/scripts/consolidation-sim.js +141 -0
  19. package/build/sdk/index.d.ts +12 -0
  20. package/build/sdk/index.js +2 -0
  21. package/build/services/escalation/grouped-list.d.ts +19 -0
  22. package/build/services/escalation/grouped-list.js +54 -0
  23. package/build/services/escalation/index.d.ts +4 -0
  24. package/build/services/escalation/index.js +9 -1
  25. package/build/services/escalation/queries.d.ts +17 -13
  26. package/build/services/escalation/queries.js +31 -40
  27. package/build/services/escalation/read-scope-sql.d.ts +13 -0
  28. package/build/services/escalation/read-scope-sql.js +19 -0
  29. package/build/services/escalation/related.d.ts +58 -0
  30. package/build/services/escalation/related.js +196 -0
  31. package/build/services/role/index.js +6 -0
  32. package/build/services/role/seed.js +4 -0
  33. package/build/services/scan-code/validate-facts.d.ts +1 -1
  34. package/build/services/scan-code/validate-facts.js +12 -1
  35. package/build/shared/form-validation/x-lt-scan.d.ts +8 -0
  36. package/build/shared/form-validation/x-lt-scan.js +20 -1
  37. package/build/shared/list-schema/index.d.ts +3 -0
  38. package/build/shared/list-schema/index.js +27 -0
  39. package/build/shared/list-schema/template.d.ts +14 -0
  40. package/build/shared/list-schema/template.js +85 -0
  41. package/build/shared/list-schema/types.d.ts +154 -0
  42. package/build/shared/list-schema/types.js +55 -0
  43. package/build/shared/list-schema/validate.d.ts +12 -0
  44. package/build/shared/list-schema/validate.js +204 -0
  45. package/build/shared/roles/segment.d.ts +22 -0
  46. package/build/shared/roles/segment.js +42 -0
  47. package/build/start/adapters.js +2 -0
  48. package/build/system/mcp-servers/admin/users.js +8 -0
  49. package/build/tsconfig.tsbuildinfo +1 -1
  50. package/build/types/index.d.ts +2 -2
  51. package/build/types/index.js +2 -1
  52. package/build/types/scan-code/constants.d.ts +7 -0
  53. package/build/types/scan-code/constants.js +7 -1
  54. package/build/types/scan-code/response.d.ts +3 -2
  55. package/build/types/scan-code/rule.d.ts +6 -1
  56. package/build/types/startup.d.ts +8 -0
  57. package/dashboard/dist/assets/{AdminDashboard-DKrqLGjn.js → AdminDashboard-BPWsgMfZ.js} +2 -2
  58. package/dashboard/dist/assets/{AdminDashboard-DKrqLGjn.js.map → AdminDashboard-BPWsgMfZ.js.map} +1 -1
  59. package/dashboard/dist/assets/{AgentConfigPage-BoQhRW6U.js → AgentConfigPage-De9imyo5.js} +2 -2
  60. package/dashboard/dist/assets/{AgentConfigPage-BoQhRW6U.js.map → AgentConfigPage-De9imyo5.js.map} +1 -1
  61. package/dashboard/dist/assets/{AgentDetailPage-DZhzuZmO.js → AgentDetailPage-B6o96Y5G.js} +3 -3
  62. package/dashboard/dist/assets/{AgentDetailPage-DZhzuZmO.js.map → AgentDetailPage-B6o96Y5G.js.map} +1 -1
  63. package/dashboard/dist/assets/{AgentsPage-5MynmbWX.js → AgentsPage-DMEmiK_W.js} +2 -2
  64. package/dashboard/dist/assets/{AgentsPage-5MynmbWX.js.map → AgentsPage-DMEmiK_W.js.map} +1 -1
  65. package/dashboard/dist/assets/AvailableEscalationsPage-DeYMngwE.js +2 -0
  66. package/dashboard/dist/assets/AvailableEscalationsPage-DeYMngwE.js.map +1 -0
  67. package/dashboard/dist/assets/{BotPicker-C3LR6Sqy.js → BotPicker-DDmpgGHZ.js} +2 -2
  68. package/dashboard/dist/assets/{BotPicker-C3LR6Sqy.js.map → BotPicker-DDmpgGHZ.js.map} +1 -1
  69. package/dashboard/dist/assets/{BulkAssignModal-COjoOIIH.js → BulkAssignModal-BqlklomG.js} +2 -2
  70. package/dashboard/dist/assets/{BulkAssignModal-COjoOIIH.js.map → BulkAssignModal-BqlklomG.js.map} +1 -1
  71. package/dashboard/dist/assets/CapabilitiesPage-DOtjDTbK.js +2 -0
  72. package/dashboard/dist/assets/{CapabilitiesPage-DKxLvOfB.js.map → CapabilitiesPage-DOtjDTbK.js.map} +1 -1
  73. package/dashboard/dist/assets/{CollapsibleSection-Cz5sRx-r.js → CollapsibleSection-CLr8LP0V.js} +2 -2
  74. package/dashboard/dist/assets/{CollapsibleSection-Cz5sRx-r.js.map → CollapsibleSection-CLr8LP0V.js.map} +1 -1
  75. package/dashboard/dist/assets/{ConfirmDeleteModal-Beq1vQtY.js → ConfirmDeleteModal-DW4DrPur.js} +2 -2
  76. package/dashboard/dist/assets/{ConfirmDeleteModal-Beq1vQtY.js.map → ConfirmDeleteModal-DW4DrPur.js.map} +1 -1
  77. package/dashboard/dist/assets/CountdownTimer-DxX72PwV.js +2 -0
  78. package/dashboard/dist/assets/CountdownTimer-DxX72PwV.js.map +1 -0
  79. package/dashboard/dist/assets/{CredentialsPage-DhiHiPsG.js → CredentialsPage-CObc9Rs5.js} +2 -2
  80. package/dashboard/dist/assets/{CredentialsPage-DhiHiPsG.js.map → CredentialsPage-CObc9Rs5.js.map} +1 -1
  81. package/dashboard/dist/assets/{CronLabel-C9SkawB-.js → CronLabel-Bb8GoNY5.js} +2 -2
  82. package/dashboard/dist/assets/{CronLabel-C9SkawB-.js.map → CronLabel-Bb8GoNY5.js.map} +1 -1
  83. package/dashboard/dist/assets/DataTable-FjFhx0SE.js +2 -0
  84. package/dashboard/dist/assets/DataTable-FjFhx0SE.js.map +1 -0
  85. package/dashboard/dist/assets/{ElapsedCell-BeK1SUDK.js → ElapsedCell-CmGhVlYl.js} +2 -2
  86. package/dashboard/dist/assets/{ElapsedCell-BeK1SUDK.js.map → ElapsedCell-CmGhVlYl.js.map} +1 -1
  87. package/dashboard/dist/assets/{EntityTimelinePanel-BThdefKj.js → EntityTimelinePanel-B4Jwy1w3.js} +2 -2
  88. package/dashboard/dist/assets/{EntityTimelinePanel-BThdefKj.js.map → EntityTimelinePanel-B4Jwy1w3.js.map} +1 -1
  89. package/dashboard/dist/assets/{EscalationListSchemaPage-DlDIYb-p.js → EscalationListSchemaPage-CZZbZ4Aa.js} +2 -2
  90. package/dashboard/dist/assets/{EscalationListSchemaPage-DlDIYb-p.js.map → EscalationListSchemaPage-CZZbZ4Aa.js.map} +1 -1
  91. package/dashboard/dist/assets/{EscalationSchemaPage-CQt-Embr.js → EscalationSchemaPage-D0ko59_S.js} +3 -3
  92. package/dashboard/dist/assets/{EscalationSchemaPage-CQt-Embr.js.map → EscalationSchemaPage-D0ko59_S.js.map} +1 -1
  93. package/dashboard/dist/assets/EscalationTimeline-BcnJEKFD.js +2 -0
  94. package/dashboard/dist/assets/EscalationTimeline-BcnJEKFD.js.map +1 -0
  95. package/dashboard/dist/assets/{EscalationTitleSelect-Dewrv8wX.js → EscalationTitleSelect-P0q5sck4.js} +2 -2
  96. package/dashboard/dist/assets/{EscalationTitleSelect-Dewrv8wX.js.map → EscalationTitleSelect-P0q5sck4.js.map} +1 -1
  97. package/dashboard/dist/assets/{EscalationsOverview-BzH-Y-5x.js → EscalationsOverview-BLPmh4AF.js} +2 -2
  98. package/dashboard/dist/assets/{EscalationsOverview-BzH-Y-5x.js.map → EscalationsOverview-BLPmh4AF.js.map} +1 -1
  99. package/dashboard/dist/assets/{EventTable-C97m6IZv.js → EventTable-gBzi5tIS.js} +2 -2
  100. package/dashboard/dist/assets/{EventTable-C97m6IZv.js.map → EventTable-gBzi5tIS.js.map} +1 -1
  101. package/dashboard/dist/assets/{FilterBar-D-6xVHIw.js → FilterBar-BulSsWb2.js} +2 -2
  102. package/dashboard/dist/assets/{FilterBar-D-6xVHIw.js.map → FilterBar-BulSsWb2.js.map} +1 -1
  103. package/dashboard/dist/assets/FormattedValue-BMHRrvrL.js +2 -0
  104. package/dashboard/dist/assets/FormattedValue-BMHRrvrL.js.map +1 -0
  105. package/dashboard/dist/assets/{GraphInvokePage-Bwi8EF9Y.js → GraphInvokePage--997yNRr.js} +2 -2
  106. package/dashboard/dist/assets/{GraphInvokePage-Bwi8EF9Y.js.map → GraphInvokePage--997yNRr.js.map} +1 -1
  107. package/dashboard/dist/assets/{HomePage-Z_Q03C0z.js → HomePage-CwXFz--v.js} +2 -2
  108. package/dashboard/dist/assets/{HomePage-Z_Q03C0z.js.map → HomePage-CwXFz--v.js.map} +1 -1
  109. package/dashboard/dist/assets/{ListToolbar-_jWTw5no.js → ListToolbar-Df4qZryJ.js} +2 -2
  110. package/dashboard/dist/assets/{ListToolbar-_jWTw5no.js.map → ListToolbar-Df4qZryJ.js.map} +1 -1
  111. package/dashboard/dist/assets/{McpOverview-CjqTuP0N.js → McpOverview-DrogIAKJ.js} +2 -2
  112. package/dashboard/dist/assets/{McpOverview-CjqTuP0N.js.map → McpOverview-DrogIAKJ.js.map} +1 -1
  113. package/dashboard/dist/assets/{McpQueryDetailPage-leCsje1U.js → McpQueryDetailPage-CJmvCAE6.js} +2 -2
  114. package/dashboard/dist/assets/{McpQueryDetailPage-leCsje1U.js.map → McpQueryDetailPage-CJmvCAE6.js.map} +1 -1
  115. package/dashboard/dist/assets/{McpQueryPage-C-PyXYX4.js → McpQueryPage-lygo4Yq0.js} +2 -2
  116. package/dashboard/dist/assets/{McpQueryPage-C-PyXYX4.js.map → McpQueryPage-lygo4Yq0.js.map} +1 -1
  117. package/dashboard/dist/assets/{McpRunDetailPage-JDrr3uUQ.js → McpRunDetailPage-hvns2sCm.js} +2 -2
  118. package/dashboard/dist/assets/{McpRunDetailPage-JDrr3uUQ.js.map → McpRunDetailPage-hvns2sCm.js.map} +1 -1
  119. package/dashboard/dist/assets/{McpRunsPage-DERXQLgZ.js → McpRunsPage-C2_7spTX.js} +2 -2
  120. package/dashboard/dist/assets/{McpRunsPage-DERXQLgZ.js.map → McpRunsPage-C2_7spTX.js.map} +1 -1
  121. package/dashboard/dist/assets/{OperationsPage-B2DA7n9m.js → OperationsPage-BlK8WlsY.js} +3 -3
  122. package/dashboard/dist/assets/OperationsPage-BlK8WlsY.js.map +1 -0
  123. package/dashboard/dist/assets/OperatorDashboard-BeWBiMGX.js +2 -0
  124. package/dashboard/dist/assets/OperatorDashboard-BeWBiMGX.js.map +1 -0
  125. package/dashboard/dist/assets/{PersonaDetailPage-ChXwJ6u5.js → PersonaDetailPage-CNHpsX_i.js} +2 -2
  126. package/dashboard/dist/assets/{PersonaDetailPage-ChXwJ6u5.js.map → PersonaDetailPage-CNHpsX_i.js.map} +1 -1
  127. package/dashboard/dist/assets/{PersonasPage-BFFxncSE.js → PersonasPage-ChASEZRg.js} +2 -2
  128. package/dashboard/dist/assets/{PersonasPage-BFFxncSE.js.map → PersonasPage-ChASEZRg.js.map} +1 -1
  129. package/dashboard/dist/assets/PortalPage-D5Lk-PKF.js +2 -0
  130. package/dashboard/dist/assets/PortalPage-D5Lk-PKF.js.map +1 -0
  131. package/dashboard/dist/assets/{ProcessDetailPage-D7EYwW-j.js → ProcessDetailPage-DNgCIwRl.js} +2 -2
  132. package/dashboard/dist/assets/{ProcessDetailPage-D7EYwW-j.js.map → ProcessDetailPage-DNgCIwRl.js.map} +1 -1
  133. package/dashboard/dist/assets/{ProcessesListPage-CakYRtnE.js → ProcessesListPage-pRjWuWlH.js} +2 -2
  134. package/dashboard/dist/assets/{ProcessesListPage-CakYRtnE.js.map → ProcessesListPage-pRjWuWlH.js.map} +1 -1
  135. package/dashboard/dist/assets/ResolverForm-CKIOAGtY.js +8 -0
  136. package/dashboard/dist/assets/ResolverForm-CKIOAGtY.js.map +1 -0
  137. package/dashboard/dist/assets/{RoleDetailPage-CKbGwezP.js → RoleDetailPage-Bh_UcfYY.js} +2 -2
  138. package/dashboard/dist/assets/{RoleDetailPage-CKbGwezP.js.map → RoleDetailPage-Bh_UcfYY.js.map} +1 -1
  139. package/dashboard/dist/assets/{RolesPage-Czu7Zku4.js → RolesPage-CK17N7zz.js} +2 -2
  140. package/dashboard/dist/assets/{RolesPage-Czu7Zku4.js.map → RolesPage-CK17N7zz.js.map} +1 -1
  141. package/dashboard/dist/assets/{RunAsSelector-6BLScYTX.js → RunAsSelector-BEKUP0p2.js} +2 -2
  142. package/dashboard/dist/assets/{RunAsSelector-6BLScYTX.js.map → RunAsSelector-BEKUP0p2.js.map} +1 -1
  143. package/dashboard/dist/assets/{ScanCodesPage-Cv9q8Bvt.js → ScanCodesPage-Bd0Pflqx.js} +2 -2
  144. package/dashboard/dist/assets/{ScanCodesPage-Cv9q8Bvt.js.map → ScanCodesPage-Bd0Pflqx.js.map} +1 -1
  145. package/dashboard/dist/assets/{ScanSchemeDetailPage-BxazXYIc.js → ScanSchemeDetailPage-CnuhozmJ.js} +2 -2
  146. package/dashboard/dist/assets/{ScanSchemeDetailPage-BxazXYIc.js.map → ScanSchemeDetailPage-CnuhozmJ.js.map} +1 -1
  147. package/dashboard/dist/assets/ScanStationPage-CoLc-q3h.js +2 -0
  148. package/dashboard/dist/assets/ScanStationPage-CoLc-q3h.js.map +1 -0
  149. package/dashboard/dist/assets/{StickyPagination-DsdtYoXR.js → StickyPagination-COrfvkBi.js} +2 -2
  150. package/dashboard/dist/assets/{StickyPagination-DsdtYoXR.js.map → StickyPagination-COrfvkBi.js.map} +1 -1
  151. package/dashboard/dist/assets/{StreamMessageDetail-CT3FQoT3.js → StreamMessageDetail-Cif2egLy.js} +2 -2
  152. package/dashboard/dist/assets/{StreamMessageDetail-CT3FQoT3.js.map → StreamMessageDetail-Cif2egLy.js.map} +1 -1
  153. package/dashboard/dist/assets/{SwimlaneTimeline-C8TjkJ10.js → SwimlaneTimeline-BnZYTrAh.js} +2 -2
  154. package/dashboard/dist/assets/{SwimlaneTimeline-C8TjkJ10.js.map → SwimlaneTimeline-BnZYTrAh.js.map} +1 -1
  155. package/dashboard/dist/assets/{TaskDetailPage-DGUzdBFN.js → TaskDetailPage-DEz_dqyR.js} +2 -2
  156. package/dashboard/dist/assets/{TaskDetailPage-DGUzdBFN.js.map → TaskDetailPage-DEz_dqyR.js.map} +1 -1
  157. package/dashboard/dist/assets/{TasksListPage-BVIP6-EZ.js → TasksListPage-oEfEGj0_.js} +2 -2
  158. package/dashboard/dist/assets/{TasksListPage-BVIP6-EZ.js.map → TasksListPage-oEfEGj0_.js.map} +1 -1
  159. package/dashboard/dist/assets/{TimeAgo-C-rd9F9g.js → TimeAgo-Dz5TgZZZ.js} +2 -2
  160. package/dashboard/dist/assets/{TimeAgo-C-rd9F9g.js.map → TimeAgo-Dz5TgZZZ.js.map} +1 -1
  161. package/dashboard/dist/assets/{TimestampCell-DPbchDOI.js → TimestampCell-BUTgE244.js} +2 -2
  162. package/dashboard/dist/assets/{TimestampCell-DPbchDOI.js.map → TimestampCell-BUTgE244.js.map} +1 -1
  163. package/dashboard/dist/assets/{ToolTestPanel-DAUC8DHK.js → ToolTestPanel-BS4g6vt-.js} +2 -2
  164. package/dashboard/dist/assets/{ToolTestPanel-DAUC8DHK.js.map → ToolTestPanel-BS4g6vt-.js.map} +1 -1
  165. package/dashboard/dist/assets/{TopicDetailPage-70mMKBzG.js → TopicDetailPage-C_I6JIVD.js} +2 -2
  166. package/dashboard/dist/assets/{TopicDetailPage-70mMKBzG.js.map → TopicDetailPage-C_I6JIVD.js.map} +1 -1
  167. package/dashboard/dist/assets/{TopicsPage-CE3hBthn.js → TopicsPage-Cr6-wfhJ.js} +2 -2
  168. package/dashboard/dist/assets/{TopicsPage-CE3hBthn.js.map → TopicsPage-Cr6-wfhJ.js.map} +1 -1
  169. package/dashboard/dist/assets/{UserName-BDBDA-LR.js → UserName-ZFpWMaFF.js} +2 -2
  170. package/dashboard/dist/assets/{UserName-BDBDA-LR.js.map → UserName-ZFpWMaFF.js.map} +1 -1
  171. package/dashboard/dist/assets/{WorkflowExecutionPage-BbkLZ1co.js → WorkflowExecutionPage-ByPixDZW.js} +2 -2
  172. package/dashboard/dist/assets/{WorkflowExecutionPage-BbkLZ1co.js.map → WorkflowExecutionPage-ByPixDZW.js.map} +1 -1
  173. package/dashboard/dist/assets/{WorkflowsDashboard-Bp1L7Ggz.js → WorkflowsDashboard-CWsJdMdR.js} +2 -2
  174. package/dashboard/dist/assets/{WorkflowsDashboard-Bp1L7Ggz.js.map → WorkflowsDashboard-CWsJdMdR.js.map} +1 -1
  175. package/dashboard/dist/assets/{WorkflowsOverview-IeTKHAi4.js → WorkflowsOverview-Dk9gyqZN.js} +2 -2
  176. package/dashboard/dist/assets/{WorkflowsOverview-IeTKHAi4.js.map → WorkflowsOverview-Dk9gyqZN.js.map} +1 -1
  177. package/dashboard/dist/assets/{YamlWorkflowDetailPage-DtKCXnKt.js → YamlWorkflowDetailPage-CHwcrsaT.js} +2 -2
  178. package/dashboard/dist/assets/{YamlWorkflowDetailPage-DtKCXnKt.js.map → YamlWorkflowDetailPage-CHwcrsaT.js.map} +1 -1
  179. package/dashboard/dist/assets/{YamlWorkflowsPage-CEcZBV_3.js → YamlWorkflowsPage-B5jRX2Ph.js} +2 -2
  180. package/dashboard/dist/assets/{YamlWorkflowsPage-CEcZBV_3.js.map → YamlWorkflowsPage-B5jRX2Ph.js.map} +1 -1
  181. package/dashboard/dist/assets/{agents-BT-sEk81.js → agents-Dd7E-27d.js} +2 -2
  182. package/dashboard/dist/assets/{agents-BT-sEk81.js.map → agents-Dd7E-27d.js.map} +1 -1
  183. package/dashboard/dist/assets/{bots-DRoAdLek.js → bots-CpaYjZTk.js} +2 -2
  184. package/dashboard/dist/assets/{bots-DRoAdLek.js.map → bots-CpaYjZTk.js.map} +1 -1
  185. package/dashboard/dist/assets/{capabilities-Bc-nJk6y.js → capabilities-CNjg_qv1.js} +2 -2
  186. package/dashboard/dist/assets/{capabilities-Bc-nJk6y.js.map → capabilities-CNjg_qv1.js.map} +1 -1
  187. package/dashboard/dist/assets/{controlplane-aXceSIRf.js → controlplane-DgmvnAtU.js} +2 -2
  188. package/dashboard/dist/assets/{controlplane-aXceSIRf.js.map → controlplane-DgmvnAtU.js.map} +1 -1
  189. package/dashboard/dist/assets/escalation-columns-Uj4U9g5H.js +2 -0
  190. package/dashboard/dist/assets/escalation-columns-Uj4U9g5H.js.map +1 -0
  191. package/dashboard/dist/assets/{index-C3VTJcrp.js → index-BFASQ7_X.js} +2 -2
  192. package/dashboard/dist/assets/{index-C3VTJcrp.js.map → index-BFASQ7_X.js.map} +1 -1
  193. package/dashboard/dist/assets/{index-DH03y-UT.js → index-BT1Ms5Q5.js} +2 -2
  194. package/dashboard/dist/assets/{index-DH03y-UT.js.map → index-BT1Ms5Q5.js.map} +1 -1
  195. package/dashboard/dist/assets/{index-Djsoi8DI.js → index-BrwqtXRh.js} +2 -2
  196. package/dashboard/dist/assets/{index-Djsoi8DI.js.map → index-BrwqtXRh.js.map} +1 -1
  197. package/dashboard/dist/assets/index-BsHVgWH6.js +13 -0
  198. package/dashboard/dist/assets/{index-BEPKAjna.js.map → index-BsHVgWH6.js.map} +1 -1
  199. package/dashboard/dist/assets/index-ByBy9M3L.js +2 -0
  200. package/dashboard/dist/assets/{index-BCFEQEMC.js.map → index-ByBy9M3L.js.map} +1 -1
  201. package/dashboard/dist/assets/{index-CZyO9hRb.js → index-C_K7OlzT.js} +2 -2
  202. package/dashboard/dist/assets/{index-CZyO9hRb.js.map → index-C_K7OlzT.js.map} +1 -1
  203. package/dashboard/dist/assets/{index-Ba-s5Yb5.js → index-CnOvJz6U.js} +2 -2
  204. package/dashboard/dist/assets/{index-Ba-s5Yb5.js.map → index-CnOvJz6U.js.map} +1 -1
  205. package/dashboard/dist/assets/{index-CcgmR-7-.js → index-CtlBjl8o.js} +2 -2
  206. package/dashboard/dist/assets/{index-CcgmR-7-.js.map → index-CtlBjl8o.js.map} +1 -1
  207. package/dashboard/dist/assets/{index-DBxpyIw5.js → index-D4Dlznn9.js} +2 -2
  208. package/dashboard/dist/assets/{index-DBxpyIw5.js.map → index-D4Dlznn9.js.map} +1 -1
  209. package/dashboard/dist/assets/{index-BUYokcrl.js → index-LRYC__mE.js} +30 -30
  210. package/dashboard/dist/assets/index-LRYC__mE.js.map +1 -0
  211. package/dashboard/dist/assets/{index-DcppjzP5.css → index-MYI2_Xb3.css} +1 -1
  212. package/dashboard/dist/assets/index-OfO0173w.js +3 -0
  213. package/dashboard/dist/assets/index-OfO0173w.js.map +1 -0
  214. package/dashboard/dist/assets/{index-h2gX31B2.js → index-RIFT3RlO.js} +2 -2
  215. package/dashboard/dist/assets/{index-h2gX31B2.js.map → index-RIFT3RlO.js.map} +1 -1
  216. package/dashboard/dist/assets/{index-CuBGGwXf.js → index-x5z73M9N.js} +2 -2
  217. package/dashboard/dist/assets/{index-CuBGGwXf.js.map → index-x5z73M9N.js.map} +1 -1
  218. package/dashboard/dist/assets/{knowledge-BhW8V-Hq.js → knowledge-Cci_r6Kl.js} +2 -2
  219. package/dashboard/dist/assets/{knowledge-BhW8V-Hq.js.map → knowledge-Cci_r6Kl.js.map} +1 -1
  220. package/dashboard/dist/assets/{mcp-BYfSMQzh.js → mcp-NY4iL0L-.js} +2 -2
  221. package/dashboard/dist/assets/{mcp-BYfSMQzh.js.map → mcp-NY4iL0L-.js.map} +1 -1
  222. package/dashboard/dist/assets/{mcp-query-DUJoOk_q.js → mcp-query-CbvZo_I_.js} +2 -2
  223. package/dashboard/dist/assets/{mcp-query-DUJoOk_q.js.map → mcp-query-CbvZo_I_.js.map} +1 -1
  224. package/dashboard/dist/assets/{personas-jT1O_SB4.js → personas-Fy-f7QQd.js} +2 -2
  225. package/dashboard/dist/assets/{personas-jT1O_SB4.js.map → personas-Fy-f7QQd.js.map} +1 -1
  226. package/dashboard/dist/assets/{pipelines-Bp-wIaz2.js → pipelines-DKiuozxV.js} +2 -2
  227. package/dashboard/dist/assets/{pipelines-Bp-wIaz2.js.map → pipelines-DKiuozxV.js.map} +1 -1
  228. package/dashboard/dist/assets/{tasks-CCrvnXbz.js → tasks-CdM1Rkk9.js} +2 -2
  229. package/dashboard/dist/assets/{tasks-CCrvnXbz.js.map → tasks-CdM1Rkk9.js.map} +1 -1
  230. package/dashboard/dist/assets/{topics-Blft0I1L.js → topics-XNy2mf3n.js} +2 -2
  231. package/dashboard/dist/assets/{topics-Blft0I1L.js.map → topics-XNy2mf3n.js.map} +1 -1
  232. package/dashboard/dist/assets/{useDebouncedValue-BYqbcism.js → useDebouncedValue-CyGcU3_S.js} +2 -2
  233. package/dashboard/dist/assets/{useDebouncedValue-BYqbcism.js.map → useDebouncedValue-CyGcU3_S.js.map} +1 -1
  234. package/dashboard/dist/assets/{useNamespace-BfxJAUgG.js → useNamespace-C2RIh_IN.js} +2 -2
  235. package/dashboard/dist/assets/{useNamespace-BfxJAUgG.js.map → useNamespace-C2RIh_IN.js.map} +1 -1
  236. package/dashboard/dist/assets/{useYamlActivityEvents-BukJuWpb.js → useYamlActivityEvents-CDiV5fjf.js} +2 -2
  237. package/dashboard/dist/assets/{useYamlActivityEvents-BukJuWpb.js.map → useYamlActivityEvents-CDiV5fjf.js.map} +1 -1
  238. package/dashboard/dist/assets/validate-DcGWN82Y.js +2 -0
  239. package/dashboard/dist/assets/validate-DcGWN82Y.js.map +1 -0
  240. package/dashboard/dist/assets/{yaml-workflows-DeRWqMGk.js → yaml-workflows-CH8UrouH.js} +2 -2
  241. package/dashboard/dist/assets/{yaml-workflows-DeRWqMGk.js.map → yaml-workflows-CH8UrouH.js.map} +1 -1
  242. package/dashboard/dist/index.html +2 -2
  243. package/docs/api/http/escalations.md +46 -0
  244. package/docs/api/sdk/escalations.md +16 -0
  245. package/docs/code-owned-configuration.md +12 -0
  246. package/docs/hitl/portal.md +2 -0
  247. package/docs/hitl/x-lt-list-schema.md +88 -1
  248. package/docs/hitl/x-lt-scan.md +4 -1
  249. package/docs/scan-codes.md +7 -1
  250. package/package.json +3 -2
  251. package/dashboard/dist/assets/AvailableEscalationsPage-CWMyy3IL.js +0 -2
  252. package/dashboard/dist/assets/AvailableEscalationsPage-CWMyy3IL.js.map +0 -1
  253. package/dashboard/dist/assets/CapabilitiesPage-DKxLvOfB.js +0 -2
  254. package/dashboard/dist/assets/CountdownTimer-BUBl_4mP.js +0 -2
  255. package/dashboard/dist/assets/CountdownTimer-BUBl_4mP.js.map +0 -1
  256. package/dashboard/dist/assets/DataTable-spX1dFyb.js +0 -2
  257. package/dashboard/dist/assets/DataTable-spX1dFyb.js.map +0 -1
  258. package/dashboard/dist/assets/EscalationListView-DTIVuym4.js +0 -2
  259. package/dashboard/dist/assets/EscalationListView-DTIVuym4.js.map +0 -1
  260. package/dashboard/dist/assets/EscalationTimeline-DNKNp6pL.js +0 -2
  261. package/dashboard/dist/assets/EscalationTimeline-DNKNp6pL.js.map +0 -1
  262. package/dashboard/dist/assets/OperationsPage-B2DA7n9m.js.map +0 -1
  263. package/dashboard/dist/assets/OperatorDashboard-C8RtPv8P.js +0 -2
  264. package/dashboard/dist/assets/OperatorDashboard-C8RtPv8P.js.map +0 -1
  265. package/dashboard/dist/assets/PortalPage-Xk1zVneM.js +0 -2
  266. package/dashboard/dist/assets/PortalPage-Xk1zVneM.js.map +0 -1
  267. package/dashboard/dist/assets/ResolverForm-BwVOJUpJ.js +0 -8
  268. package/dashboard/dist/assets/ResolverForm-BwVOJUpJ.js.map +0 -1
  269. package/dashboard/dist/assets/ScanStationPage-Cg8LCFR7.js +0 -2
  270. package/dashboard/dist/assets/ScanStationPage-Cg8LCFR7.js.map +0 -1
  271. package/dashboard/dist/assets/escalation-columns-Bf09Q89t.js +0 -2
  272. package/dashboard/dist/assets/escalation-columns-Bf09Q89t.js.map +0 -1
  273. package/dashboard/dist/assets/index-BCFEQEMC.js +0 -2
  274. package/dashboard/dist/assets/index-BEPKAjna.js +0 -13
  275. package/dashboard/dist/assets/index-BUYokcrl.js.map +0 -1
  276. package/dashboard/dist/assets/index-D1mKf_qz.js +0 -3
  277. package/dashboard/dist/assets/index-D1mKf_qz.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escalation-columns-Uj4U9g5H.js","sources":["../../src/lib/type-color.ts","../../src/components/escalation/RefineDialog.tsx","../../src/api/escalation-related.ts","../../../shared/list-schema/template.ts","../../src/components/escalation/list-view/RelatedCell.tsx","../../src/components/escalation/list-view/RowDetail.tsx","../../src/components/escalation/list-view/group-rows.ts","../../src/components/escalation/list-view/FacetTable.tsx","../../src/components/escalation/EscalationListView.tsx","../../src/pages/operator/escalation-columns.tsx"],"sourcesContent":["/**\n * Deterministic color assignment for workflow type names.\n *\n * Maps any string to a consistent color from a curated 24-color palette.\n * The same type name always produces the same color across the entire UI.\n * Uses a simple hash to distribute names evenly across the palette.\n *\n * Each entry provides:\n * text — icon and text color (Tailwind class)\n * bg — subtle background tint (Tailwind class)\n */\n\nconst PALETTE: Array<{ text: string; bg: string }> = [\n { text: 'text-rose-400', bg: 'bg-rose-400/[0.08]' },\n { text: 'text-pink-400', bg: 'bg-pink-400/[0.08]' },\n { text: 'text-fuchsia-400', bg: 'bg-fuchsia-400/[0.08]' },\n { text: 'text-purple-400', bg: 'bg-purple-400/[0.08]' },\n { text: 'text-violet-400', bg: 'bg-violet-400/[0.08]' },\n { text: 'text-indigo-400', bg: 'bg-indigo-400/[0.08]' },\n { text: 'text-blue-400', bg: 'bg-blue-400/[0.08]' },\n { text: 'text-sky-400', bg: 'bg-sky-400/[0.08]' },\n { text: 'text-cyan-400', bg: 'bg-cyan-400/[0.08]' },\n { text: 'text-teal-400', bg: 'bg-teal-400/[0.08]' },\n { text: 'text-emerald-400', bg: 'bg-emerald-400/[0.08]' },\n { text: 'text-green-400', bg: 'bg-green-400/[0.08]' },\n { text: 'text-lime-400', bg: 'bg-lime-400/[0.08]' },\n { text: 'text-yellow-400', bg: 'bg-yellow-400/[0.08]' },\n { text: 'text-amber-400', bg: 'bg-amber-400/[0.08]' },\n { text: 'text-orange-400', bg: 'bg-orange-400/[0.08]' },\n { text: 'text-red-400', bg: 'bg-red-400/[0.08]' },\n { text: 'text-stone-400', bg: 'bg-stone-400/[0.08]' },\n { text: 'text-rose-300', bg: 'bg-rose-300/[0.08]' },\n { text: 'text-violet-300', bg: 'bg-violet-300/[0.08]' },\n { text: 'text-sky-300', bg: 'bg-sky-300/[0.08]' },\n { text: 'text-teal-300', bg: 'bg-teal-300/[0.08]' },\n { text: 'text-amber-300', bg: 'bg-amber-300/[0.08]' },\n { text: 'text-pink-300', bg: 'bg-pink-300/[0.08]' },\n];\n\nfunction hash(str: string): number {\n let h = 0;\n for (let i = 0; i < str.length; i++) {\n h = ((h << 5) - h + str.charCodeAt(i)) | 0;\n }\n return Math.abs(h);\n}\n\nexport function typeColor(typeName: string): { text: string; bg: string } {\n return PALETTE[hash(typeName) % PALETTE.length];\n}\n","import { useState } from 'react';\nimport { Check, Search } from 'lucide-react';\nimport { Modal } from '../common/modal/Modal';\nimport { metadataFacetsUrl } from '../../lib/facet-url';\n\n/** One refinable fact from a row: a metadata key with its authored label and value. */\nexport interface RefinePair {\n key: string;\n label: string;\n value: unknown;\n /** The author put this fact in the row's columns; a lone bound fact arrives preselected. */\n bound?: boolean;\n}\n\n/**\n * The row-level refine gesture for authored lists (facet-table rows, board\n * cards): the row's metadata-bound facts as full-width touch rows, each a\n * toggle. Pick one or several (multi-select ANDs the facets) and drill —\n * filter this role's queue, search every role, or merge into the live filter\n * set. One dialog replaces per-cell icon pairs, so table cells spend their\n * width on data and the affordance stays tappable on the iPad floor. The\n * list is the row's whole metadata; past a handful of facts a find box\n * narrows it by label, key, or value.\n */\nconst FIND_THRESHOLD = 6;\nexport function RefineDialog({ open, onClose, role, pairs, onNavigate, onAddFacet }: {\n open: boolean;\n onClose: () => void;\n role: string;\n pairs: RefinePair[];\n /** Receives the facet deep-link. Hosts navigate (or open a panel). */\n onNavigate: (url: string) => void;\n /** When provided, \"Add to filters\" merges the selection into the live set. */\n onAddFacet?: (key: string, value: unknown) => void;\n}) {\n // A single fact, or a single column-bound fact, arrives selected — the\n // one-glance, two-tap path — while the rest of the record waits below.\n const [selected, setSelected] = useState<Set<string>>(new Set());\n const [find, setFind] = useState('');\n const [prevOpen, setPrevOpen] = useState(open);\n if (open !== prevOpen) {\n setPrevOpen(open);\n if (open) {\n const bound = pairs.filter((p) => p.bound);\n const preset = bound.length === 1 ? [bound[0].key] : pairs.length === 1 ? [pairs[0].key] : [];\n setSelected(new Set(preset));\n setFind('');\n }\n }\n const needle = find.trim().toLowerCase();\n const visible = needle\n ? pairs.filter((p) => [p.label, p.key, String(p.value)].some((t) => t.toLowerCase().includes(needle)))\n : pairs;\n\n const toggle = (key: string) => {\n setSelected((prev) => {\n const next = new Set(prev);\n if (next.has(key)) next.delete(key); else next.add(key);\n return next;\n });\n };\n\n const chosen = pairs.filter((p) => selected.has(p.key));\n const facets = Object.fromEntries(chosen.map((p) => [p.key, p.value]));\n const none = chosen.length === 0;\n\n const go = (url: string) => {\n onClose();\n onNavigate(url);\n };\n\n return (\n <Modal open={open} onClose={onClose} title=\"Refine\">\n <div className=\"space-y-4\">\n <p className=\"text-2xs text-text-tertiary\">\n Pick the facts to match — several combine into one narrower query.\n </p>\n\n {pairs.length > FIND_THRESHOLD && (\n <label className=\"flex items-center gap-2 input text-xs py-1.5\">\n <Search className=\"w-3.5 h-3.5 shrink-0 text-text-quaternary\" strokeWidth={1.5} />\n <input\n type=\"text\"\n value={find}\n onChange={(e) => setFind(e.target.value)}\n placeholder=\"Find a fact…\"\n className=\"flex-1 min-w-0 bg-transparent outline-none placeholder:text-text-quaternary\"\n aria-label=\"Find a fact\"\n data-testid=\"refine-find\"\n />\n <span className=\"text-2xs tabular-nums text-text-quaternary\">{visible.length}/{pairs.length}</span>\n </label>\n )}\n\n <div className=\"divide-y divide-surface-border/40 -mx-1 max-h-[50vh] overflow-y-auto\">\n {visible.map((p) => {\n const on = selected.has(p.key);\n return (\n <button\n key={p.key}\n type=\"button\"\n onClick={() => toggle(p.key)}\n aria-pressed={on}\n className=\"w-full flex items-center gap-3 px-1 py-2.5 text-left group min-w-0\"\n data-testid=\"refine-pair\"\n >\n <span\n className={`w-4 h-4 rounded-[3px] border flex items-center justify-center shrink-0 transition-colors ${\n on ? 'bg-accent border-accent' : 'border-surface-border group-hover:border-accent/50'\n }`}\n aria-hidden\n >\n {on && <Check className=\"w-3 h-3 text-text-inverse\" strokeWidth={3} />}\n </span>\n <span className=\"text-2xs font-semibold uppercase tracking-widest text-text-tertiary w-28 shrink-0 truncate\" title={p.key}>\n {p.label}\n </span>\n <span className=\"text-xs text-text-primary truncate flex-1 min-w-0\" title={String(p.value)}>\n {String(p.value)}\n </span>\n </button>\n );\n })}\n </div>\n\n <div className=\"flex items-center justify-end gap-3 pt-2 flex-wrap\">\n {onAddFacet && (\n <button\n onClick={() => {\n chosen.forEach((p) => onAddFacet(p.key, p.value));\n onClose();\n }}\n disabled={none}\n className=\"text-xs text-text-secondary hover:text-accent transition-colors disabled:opacity-40 disabled:cursor-not-allowed mr-auto\"\n data-testid=\"refine-add-filters\"\n >\n Add to filters\n </button>\n )}\n <button\n onClick={() => go(metadataFacetsUrl(facets))}\n disabled={none}\n className=\"btn-secondary text-xs disabled:opacity-40 disabled:cursor-not-allowed\"\n data-testid=\"refine-search-all\"\n >\n Search everywhere\n </button>\n <button\n onClick={() => go(metadataFacetsUrl(facets, role))}\n disabled={none}\n className=\"btn-primary text-xs disabled:opacity-40 disabled:cursor-not-allowed\"\n data-testid=\"refine-filter-role\"\n >\n Filter {role}\n </button>\n </div>\n </div>\n </Modal>\n );\n}\n","import { useQuery } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { RelatedAggregatesResponse, RelatedRowsResponse } from '../lib/list-schema';\n\n/**\n * Every related set a role's list schema declares, aggregated for one page\n * of host rows. Keyed under `escalations`, so the list's live invalidation\n * refreshes it with the rows.\n */\nexport function useRelatedAggregates(role: string, ids: string[], version: number | null | undefined, enabled = true) {\n const sorted = [...ids].sort();\n return useQuery<RelatedAggregatesResponse>({\n queryKey: ['escalations', 'related', role, version ?? 'latest', sorted],\n queryFn: () =>\n apiFetch('/escalations/related', {\n method: 'POST',\n body: JSON.stringify({ role, ids: sorted, ...(version != null ? { version } : {}) }),\n }),\n enabled: enabled && !!role && sorted.length > 0,\n placeholderData: (prev) => prev,\n });\n}\n\n/** One host row's rows in one related set, loaded when its detail opens. */\nexport function useRelatedRows(\n role: string,\n id: string,\n set: string,\n version: number | null | undefined,\n limit?: number,\n enabled = true,\n) {\n return useQuery<RelatedRowsResponse>({\n queryKey: ['escalations', 'related-rows', role, version ?? 'latest', id, set, limit ?? null],\n queryFn: () =>\n apiFetch('/escalations/related/rows', {\n method: 'POST',\n body: JSON.stringify({ role, id, set, ...(version != null ? { version } : {}), ...(limit ? { limit } : {}) }),\n }),\n enabled: enabled && !!role && !!id && !!set,\n });\n}\n","import { getDeep } from '../form-validation/x-lt-bind';\nimport { HELP_DOMAINS, interpolateHelp, type HelpDomain, type HelpTokenContext } from '../form-validation/x-lt-help';\n\nconst SINGLE_TOKEN = /^\\{\\{\\s*([^{}]+?)\\s*\\}\\}$/;\nconst ANY_TOKEN = /\\{\\{\\s*[^{}]+?\\s*\\}\\}/;\nconst MISSING_VALUE = '—';\n\nfunction parseJsonObject(value: unknown): Record<string, unknown> | null {\n if (value && typeof value === 'object') return value as Record<string, unknown>;\n if (typeof value !== 'string' || !value) return null;\n try {\n const parsed = JSON.parse(value);\n return parsed && typeof parsed === 'object' ? parsed : null;\n } catch {\n return null;\n }\n}\n\n/** The template domains of one escalation row, JSON-string columns parsed. */\nexport function rowTemplateContext(row: Record<string, unknown>): HelpTokenContext {\n return {\n escalation: row,\n metadata: (row.metadata as Record<string, unknown> | null) ?? {},\n envelope: parseJsonObject(row.envelope) ?? {},\n payload: parseJsonObject(row.escalation_payload) ?? {},\n resolver: parseJsonObject(row.resolver_payload) ?? {},\n };\n}\n\nfunction readToken(path: string, ctx: HelpTokenContext): unknown {\n const dot = path.indexOf('.');\n const domain = (dot === -1 ? path : path.slice(0, dot)) as HelpDomain;\n if (!HELP_DOMAINS.includes(domain)) return undefined;\n const root = ctx[domain];\n if (dot === -1) return root ?? undefined;\n try {\n return getDeep(root, path.slice(dot + 1));\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolve one facet value. A lone `{{token}}` keeps the value's own JSON type\n * (a numeric facet matches a numeric facet); a mixed template interpolates to\n * a string; a literal passes through. Undefined when a token is missing.\n */\nexport function resolveTemplateValue(value: unknown, ctx: HelpTokenContext): unknown {\n if (typeof value !== 'string') return value;\n const single = value.match(SINGLE_TOKEN);\n if (single) {\n const raw = readToken(single[1], ctx);\n return raw === null || raw === '' ? undefined : raw;\n }\n if (!ANY_TOKEN.test(value)) return value;\n const text = interpolateHelp(value, ctx);\n return text.includes(MISSING_VALUE) ? undefined : text;\n}\n\n/**\n * Resolve a related query's match against a host row: every required facet\n * (null when any is missing), plus each `narrow` facet the row resolves.\n */\nexport function resolveRelatedFacets(\n facets: Record<string, unknown>,\n ctx: HelpTokenContext,\n narrow?: Record<string, unknown>,\n): Record<string, unknown> | null {\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(facets)) {\n const resolved = resolveTemplateValue(value, ctx);\n if (resolved === undefined) return null;\n out[key] = resolved;\n }\n for (const [key, value] of Object.entries(narrow ?? {})) {\n const resolved = resolveTemplateValue(value, ctx);\n if (resolved !== undefined) out[key] = resolved;\n }\n return out;\n}\n","import { Link } from 'react-router-dom';\nimport { EM_DASH } from '../../common/display/FormattedValue';\nimport { SPLIT_PATHS, type RelatedColumnDecl, type RelatedHostAggregate, type RelatedSetResult } from '../../../lib/list-schema';\n\n/** A split value's display text: the declared label, a role title, or the value. */\nexport function splitLabel(value: string, col: RelatedColumnDecl, set?: RelatedSetResult): string {\n if (col.labels?.[value]) return col.labels[value];\n if (col.splitBy === SPLIT_PATHS.ROLE && set?.roleLabels?.[value]) return set.roleLabels[value];\n return value === '' ? 'None' : value;\n}\n\n/**\n * A related column cell: the count, then each split value as a chip in\n * declaration order (role order for a role split), largest first otherwise.\n * Splits the viewer cannot read show as a muted note, never a wrong split.\n */\nexport function RelatedCell({ col, set, agg, drillUrl }: {\n col: RelatedColumnDecl;\n set?: RelatedSetResult;\n agg?: RelatedHostAggregate;\n /** Query role splits: where a chip leads (the role list with the host's facets). */\n drillUrl?: (role: string) => string | null;\n}) {\n if (!agg || agg.unresolved) return <span className=\"text-text-quaternary\">{EM_DASH}</span>;\n const order = col.splitBy === SPLIT_PATHS.ROLE && set?.roles ? set.roles : null;\n const splits = Object.entries(agg.splits ?? {})\n .filter(([, n]) => n > 0)\n .sort(([a, x], [b, y]) => (order ? order.indexOf(a) - order.indexOf(b) : y - x));\n const restricted = col.splitBy === SPLIT_PATHS.ROLE ? (set?.restricted ?? []) : [];\n const title = [\n agg.hidden ? `${agg.hidden} not readable by you` : '',\n restricted.length ? `Not counted (outside your view): ${restricted.map((r) => set?.roleLabels?.[r] ?? r).join(', ')}` : '',\n ].filter(Boolean).join(' · ');\n\n return (\n <span className=\"inline-flex flex-wrap items-center gap-1 min-w-0\" title={title || undefined} data-testid=\"related-cell\">\n <span className=\"tabular-nums font-medium text-text-primary\">{agg.count}</span>\n {splits.map(([value, n]) => {\n const text = `${splitLabel(value, col, set)} ${n}`;\n const href = order && drillUrl ? drillUrl(value) : null;\n const chip = 'px-1.5 py-0.5 rounded bg-surface-sunken text-2xs text-text-secondary whitespace-nowrap tabular-nums';\n return href ? (\n <Link key={value} to={href} onClick={(e) => e.stopPropagation()} className={`${chip} hover:text-accent`} data-testid=\"related-chip\">\n {text}\n </Link>\n ) : (\n <span key={value} className={chip} data-testid=\"related-chip\">{text}</span>\n );\n })}\n {(agg.hidden || restricted.length > 0) && (\n <span className=\"text-2xs text-text-quaternary italic\" data-testid=\"related-restricted\">\n {agg.hidden && !splits.length ? 'split restricted' : 'partial'}\n </span>\n )}\n </span>\n );\n}\n","import { useNavigate } from 'react-router-dom';\nimport { DataTable, type Column } from '../../common/data/DataTable';\nimport { FormattedValue, EM_DASH } from '../../common/display/FormattedValue';\nimport { useRelatedRows } from '../../../api/escalation-related';\nimport { interpolateItemTemplate, type EscalationItem } from '../../../lib/escalation-items';\nimport { displayRoleTitle } from '../../../lib/role-display';\nimport type { RelatedRow, RowDetailSectionDecl } from '../../../lib/list-schema';\nimport { rowContext } from './row-parts';\nimport type { LTEscalationRecord } from '../../../api/types';\n\n/** `format: \"role\"` renders a role name as its title. */\nconst ROLE_FORMAT = 'role';\n\nfunction cellText(template: string, row: RelatedRow): string {\n const ctx = row.escalation ? rowContext(row.escalation as unknown as LTEscalationRecord) : {};\n return interpolateItemTemplate(template, row.item as EscalationItem | undefined, ctx);\n}\n\nfunction DetailSection({ role, host, version, section, roleLabels }: {\n role: string;\n host: LTEscalationRecord;\n version: number | null | undefined;\n section: RowDetailSectionDecl;\n roleLabels?: Record<string, string>;\n}) {\n const navigate = useNavigate();\n const query = useRelatedRows(role, host.id, section.related, version, section.limit);\n const rows = query.data?.rows ?? [];\n const labels = query.data?.roleLabels ?? roleLabels ?? {};\n const restricted = query.data?.restricted ?? [];\n\n // A column whose every row restates a facet the opened row carries says\n // nothing new beneath it: the row already shows that facet.\n const hostValues = new Set(\n Object.values(host.metadata ?? {})\n .filter((v) => (typeof v === 'string' && v !== '') || typeof v === 'number' || typeof v === 'boolean')\n .map(String),\n );\n const shown = section.columns.filter((col, i) => {\n // The first column names each row; it always stays.\n if (i === 0 || rows.length === 0) return true;\n const values = new Set(rows.map((row) => cellText(col.value, row)));\n return !(values.size === 1 && hostValues.has([...values][0]));\n });\n\n const columns: Column<RelatedRow>[] = shown.map((col, i) => ({\n key: `d-${i}`,\n label: col.label,\n priority: col.priority ?? (i === 0 ? 1 : 2),\n render: (row) => {\n const text = cellText(col.value, row);\n if (col.format === ROLE_FORMAT && text !== EM_DASH) {\n return <span className=\"block truncate\">{labels[text] ?? displayRoleTitle({ role: text })}</span>;\n }\n return (\n <span className=\"block truncate\" title={text !== EM_DASH ? text : undefined}>\n <FormattedValue raw={text} format={col.format} />\n </span>\n );\n },\n }));\n\n const target = (row: RelatedRow): string | null =>\n (row.escalation?.id as string | undefined) ?? row.item?.reciprocalId ?? null;\n\n return (\n <div data-testid=\"row-detail-section\">\n <p className=\"text-2xs font-semibold uppercase tracking-widest text-text-tertiary pt-3 pb-1\">\n {section.label ?? section.related}\n {query.data && <span className=\"ml-2 font-normal normal-case tracking-normal tabular-nums\">{query.data.total}</span>}\n </p>\n {query.isLoading ? (\n <p className=\"text-2xs text-text-tertiary italic pb-2\">Loading…</p>\n ) : (\n <DataTable\n columns={columns}\n data={rows}\n keyFn={(row) => row.item?.itemKey ?? String(row.escalation?.id)}\n onRowClick={(row) => {\n const id = target(row);\n if (id) navigate(`/escalations/detail/${id}`);\n }}\n layout=\"fixed\"\n density=\"compact\"\n inline\n emptyMessage=\"\"\n />\n )}\n {!query.isLoading && rows.length === 0 && (\n <p className=\"text-2xs text-text-quaternary italic pb-2\">None.</p>\n )}\n {query.data && query.data.total > rows.length && (\n <p className=\"text-2xs text-text-quaternary pb-2\">Showing {rows.length} of {query.data.total}.</p>\n )}\n {restricted.length > 0 && (\n <p className=\"text-2xs text-text-quaternary italic pb-2\">\n Not shown (outside your view): {restricted.map((r) => labels[r] ?? r).join(', ')}\n </p>\n )}\n </div>\n );\n}\n\n/** A host row's declared detail sections, each loaded when the row opens. */\nexport function RowDetail({ role, host, version, sections }: {\n role: string;\n host: LTEscalationRecord;\n version: number | null | undefined;\n sections: RowDetailSectionDecl[];\n}) {\n return (\n <div className=\"space-y-1\" data-testid=\"row-detail\">\n {sections.map((section, i) => (\n <DetailSection key={i} role={role} host={host} version={version} section={section} />\n ))}\n </div>\n );\n}\n","import { interpolateHelp } from '../../../lib/x-lt-help';\nimport { GROUP_FOLDS, type GroupFold, type RelatedHostAggregate } from '../../../lib/list-schema';\nimport { EM_DASH } from '../../common/display/FormattedValue';\nimport { rowContext, type ColumnDef } from './row-parts';\nimport type { LTEscalationRecord } from '../../../api/types';\n\n/** One page group from the grouped list read. */\nexport interface EscalationGroup {\n key: string | null;\n ids: string[];\n}\n\n/** A facet-table row: one escalation, or a group of rows sharing a facet. */\nexport interface TableRow {\n key: string;\n rows: LTEscalationRecord[];\n /** The shared facet value; null for an ungrouped row or a row without the facet. */\n groupKey: string | null;\n /** 0 for a top-level line; 1 for a member shown under its open group. */\n depth?: number;\n /** A member that closes its group's block. */\n lastChild?: boolean;\n /** A member's group line. */\n parent?: TableRow;\n}\n\n/** The lines the table draws: each open group followed by its members. */\nexport function withOpenMembers(rows: TableRow[], open: ReadonlySet<string>): TableRow[] {\n return rows.flatMap((row) => {\n if (row.rows.length < 2 || !open.has(row.key)) return [row];\n const members = row.rows.map((m, i): TableRow => ({\n key: `${row.key}/${m.id}`,\n rows: [m],\n groupKey: row.groupKey,\n depth: 1,\n lastChild: i === row.rows.length - 1,\n parent: row,\n }));\n return [row, ...members];\n });\n}\n\n/** Table rows in page order: one per group when grouped, else one per row. */\nexport function buildTableRows(rows: LTEscalationRecord[], groups?: EscalationGroup[] | null): TableRow[] {\n if (!groups) return rows.map((r) => ({ key: r.id, rows: [r], groupKey: null }));\n const byId = new Map(rows.map((r) => [r.id, r]));\n return groups\n .map((g) => ({\n key: g.key != null ? `group:${g.key}` : g.ids[0],\n rows: g.ids.map((id) => byId.get(id)).filter((r): r is LTEscalationRecord => !!r),\n groupKey: g.key,\n }))\n .filter((g) => g.rows.length > 0);\n}\n\nfunction numeric(values: string[]): number[] | null {\n const nums = values.map((v) => Number(v));\n return nums.every((n) => Number.isFinite(n)) ? nums : null;\n}\n\n/**\n * A plain column's text across a group's rows. `first` reads the lead row;\n * `min`/`max` compare numerically when every value is a number, else as text\n * (ISO instants order as text); `sum` adds numbers; `count` counts rows.\n */\nexport function foldColumnText(col: ColumnDef & { group?: GroupFold }, rows: LTEscalationRecord[]): string {\n const fold = col.group ?? GROUP_FOLDS.FIRST;\n if (fold === GROUP_FOLDS.COUNT) return String(rows.length);\n const values = rows.map((r) => interpolateHelp(col.value, rowContext(r))).filter((v) => v && v !== EM_DASH);\n if (fold === GROUP_FOLDS.DISTINCT) return values.length ? [...new Set(values)].join(', ') : EM_DASH;\n if (fold === GROUP_FOLDS.FIRST || rows.length === 1) return values[0] ?? EM_DASH;\n if (!values.length) return EM_DASH;\n const nums = numeric(values);\n if (fold === GROUP_FOLDS.SUM) return nums ? String(nums.reduce((a, b) => a + b, 0)) : EM_DASH;\n if (nums) return String(fold === GROUP_FOLDS.MIN ? Math.min(...nums) : Math.max(...nums));\n const sorted = [...values].sort();\n return fold === GROUP_FOLDS.MIN ? sorted[0] : sorted[sorted.length - 1];\n}\n\n/** One aggregate across several host rows: counts and splits sum. */\nexport function mergeAggregates(aggs: Array<RelatedHostAggregate | undefined>): RelatedHostAggregate | undefined {\n const present = aggs.filter((a): a is RelatedHostAggregate => !!a);\n if (!present.length) return undefined;\n if (present.every((a) => a.unresolved)) return { count: 0, unresolved: true };\n const out: RelatedHostAggregate = { count: 0 };\n for (const a of present) {\n if (a.unresolved) continue;\n out.count += a.count;\n if (a.hidden) out.hidden = (out.hidden ?? 0) + a.hidden;\n if (a.splits) {\n out.splits ??= {};\n for (const [k, n] of Object.entries(a.splits)) out.splits[k] = (out.splits[k] ?? 0) + n;\n }\n }\n return out;\n}\n","import { useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { ChevronRight } from 'lucide-react';\nimport { interpolateHelp } from '../../../lib/x-lt-help';\nimport { DataTable, type Column as TableColumn } from '../../common/data/DataTable';\nimport { FormattedValue, EM_DASH } from '../../common/display/FormattedValue';\nimport { RefineDialog } from '../RefineDialog';\nimport { useRelatedAggregates } from '../../../api/escalation-related';\nimport { useRelatedSetEvents } from '../../../hooks/useEventHooks';\nimport { metadataFacetsUrl } from '../../../lib/facet-url';\nimport {\n readListSchemaRelations,\n resolveRelatedFacets,\n rowTemplateContext,\n type GroupFold,\n type ListSchemaRelations,\n type RelatedColumnDecl,\n type RelatedSetResult,\n} from '../../../lib/list-schema';\nimport {\n escalationDotClass,\n rowContext,\n rowRefinePairs,\n RowActionButton,\n RefineTrigger,\n IDENTITY_COLUMN_WIDTH,\n actionColumnWidth,\n type ColumnDef,\n type RowActionDef,\n} from './row-parts';\nimport { RelatedCell } from './RelatedCell';\nimport { RowDetail } from './RowDetail';\nimport { buildTableRows, foldColumnText, mergeAggregates, withOpenMembers, type EscalationGroup, type TableRow } from './group-rows';\nimport type { LTEscalationRecord } from '../../../api/types';\n\nexport type { EscalationGroup } from './group-rows';\n\n/** A plain column (a `value` template) or a related column (a `related` set). */\ntype TableColumnDecl = ColumnDef & Partial<Omit<RelatedColumnDecl, 'label'>> & { group?: GroupFold };\n\nexport interface FacetTableSchema {\n 'x-lt-columns'?: Array<ColumnDef | (Omit<ColumnDef, 'value'> & RelatedColumnDecl)>;\n 'x-lt-row-action'?: RowActionDef;\n [key: string]: unknown;\n}\n\n/** One member per distinct resolved facet match (members whose facets do not resolve stay). */\nfunction distinctByMatch(members: LTEscalationRecord[], facets: Record<string, unknown>, narrow?: Record<string, unknown>): LTEscalationRecord[] {\n const seen = new Set<string>();\n return members.filter((m) => {\n const match = resolveRelatedFacets(facets, rowTemplateContext(m as unknown as Record<string, unknown>), narrow);\n if (!match) return true;\n const key = JSON.stringify(match);\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\n/** The related declaration, or none when the stored schema does not validate. */\nfunction safeRelations(schema: FacetTableSchema): ListSchemaRelations | null {\n try {\n return readListSchemaRelations(schema);\n } catch {\n return null;\n }\n}\n\n/**\n * The pending queue as a facet table. Plain columns template over each row;\n * related columns aggregate the row's related sets (one request per page);\n * a declared row detail expands each row into its related rows; grouped\n * rows fold their columns and expand to their members.\n */\ninterface FacetTableProps {\n schema: FacetTableSchema;\n rows: LTEscalationRecord[];\n /** Grouped reads: the page's groups, in order. */\n groups?: EscalationGroup[] | null;\n role: string;\n /** The list schema version the page rendered. */\n version?: number | null;\n onRowClick?: (row: LTEscalationRecord) => void;\n /** RefineDialog \"Add to filters\": merge into the live filter set. */\n onAddFacet?: (key: string, value: unknown) => void;\n forceView?: boolean;\n}\n\n/** Reads the page's related sets and keeps them live; mounted only when the schema declares sets. */\nfunction RelatedFacetTable(props: FacetTableProps & { relations: ListSchemaRelations }) {\n const related = useRelatedAggregates(props.role, props.rows.map((r) => r.id), props.version);\n const sets = related.data?.sets ?? {};\n useRelatedSetEvents(Object.values(sets).flatMap((set) => set.roles ?? []));\n return <FacetTableBody {...props} sets={sets} setsLoading={related.isLoading} />;\n}\n\nexport function FacetTable(props: FacetTableProps) {\n const relations = useMemo(() => safeRelations(props.schema), [props.schema]);\n return relations && Object.keys(relations.sets).length > 0\n ? <RelatedFacetTable {...props} relations={relations} />\n : <FacetTableBody {...props} relations={relations} sets={{}} setsLoading={false} />;\n}\n\nfunction FacetTableBody({ schema, rows, groups, role, version, onRowClick, onAddFacet, forceView, relations, sets, setsLoading }: FacetTableProps & {\n relations: ListSchemaRelations | null;\n sets: Record<string, RelatedSetResult>;\n setsLoading: boolean;\n}) {\n const navigate = useNavigate();\n const columnDefs = (schema['x-lt-columns'] ?? []) as TableColumnDecl[];\n const rowAction = schema['x-lt-row-action'];\n const sections = relations?.rowDetail ?? [];\n const [refineRow, setRefineRow] = useState<LTEscalationRecord | null>(null);\n const [open, setOpen] = useState<Set<string>>(() => new Set());\n\n const tableRows = useMemo(() => buildTableRows(rows, groups), [rows, groups]);\n const lines = useMemo(() => withOpenMembers(tableRows, open), [tableRows, open]);\n const grouped = !!groups;\n const expandable = sections.length > 0 || grouped;\n // A row opens when it has something beneath it: a group its members, a row its detail.\n const opens = (r: TableRow) => r.rows.length > 1 || sections.length > 0;\n\n const toggle = (key: string) =>\n setOpen((prev) => {\n const next = new Set(prev);\n if (next.has(key)) next.delete(key); else next.add(key);\n return next;\n });\n\n const relatedCell = (col: TableColumnDecl, members: LTEscalationRecord[]) => {\n const name = col.related!;\n const set = sets[name];\n const query = relations?.sets[name]?.query;\n // Members that share a facet match read the same related rows: count them once.\n const counted = query?.facets ? distinctByMatch(members, query.facets, query.narrow) : members;\n const agg = mergeAggregates(counted.map((m) => set?.aggregates[col.splitBy ?? '']?.[m.id]));\n const drillUrl = query?.facets && members.length === 1\n ? (relatedRole: string) => {\n const match = resolveRelatedFacets(query.facets!, rowTemplateContext(members[0] as unknown as Record<string, unknown>), query.narrow);\n return match ? metadataFacetsUrl(match, relatedRole) : null;\n }\n : undefined;\n return <RelatedCell col={col as RelatedColumnDecl} set={set} agg={setsLoading ? undefined : agg} drillUrl={drillUrl} />;\n };\n\n // The authored columns render through the same dense table the engineer\n // views use: the card fold at narrow widths, never a horizontal scroll.\n // Authors steer the fold with `priority` (1 title, 2 folds, 3 dropped).\n const actionLabel = rowAction?.label ?? (forceView ? 'View' : 'Claim');\n const lead = (r: TableRow) => r.rows[0];\n const columns: TableColumn<TableRow>[] = [\n ...(expandable ? [{\n key: '_expand',\n label: '',\n priority: 1 as const,\n className: 'w-12 px-1',\n render: (r: TableRow) => (\n // A member's chevron steps in under its group's, so depth reads at a glance.\n <span className={`flex ${r.depth ? 'pl-5' : ''}`}>\n {opens(r) && (\n <button\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); toggle(r.key); }}\n className=\"p-1 rounded icon-link hover:bg-surface-hover transition-colors\"\n aria-expanded={open.has(r.key)}\n aria-label={open.has(r.key) ? 'Collapse row' : 'Expand row'}\n data-testid=\"row-expand\"\n >\n <ChevronRight className={`w-3.5 h-3.5 transition-transform ${open.has(r.key) ? 'rotate-90' : ''}`} strokeWidth={1.75} />\n </button>\n )}\n </span>\n ),\n }] : []),\n {\n key: '_status',\n label: '',\n priority: 1,\n className: 'w-8',\n render: (r) => (\n <span className=\"inline-flex items-center gap-1\">\n <span className={`w-2.5 h-2.5 inline-block rounded-full dot-ring ${escalationDotClass(lead(r))}`} title={lead(r).status} />\n {r.rows.length > 1 && (\n <span className=\"text-2xs tabular-nums text-text-tertiary\" title={`${r.rows.length} rows in this group`} data-testid=\"group-size\">\n {r.rows.length}\n </span>\n )}\n </span>\n ),\n },\n ...columnDefs.map((col, i): TableColumn<TableRow> => ({\n key: `col-${i}`,\n label: col.label,\n priority: col.priority ?? (i === 0 ? 1 : 2),\n width: col.width ?? (i === 0 && !columnDefs.some((c) => c.width) ? IDENTITY_COLUMN_WIDTH : undefined),\n render: (r) => {\n if (col.related) return relatedCell(col, r.rows);\n const text = r.rows.length > 1 ? foldColumnText(col, r.rows) : interpolateHelp(col.value, rowContext(lead(r)));\n // A member shows only what differs from its group: the group line already states the rest.\n if (r.parent && text === foldColumnText(col, r.parent.rows)) return null;\n // The identity steps in for a member, so the tree reads in the data too.\n const indent = i === 0 && r.depth ? 'pl-4' : '';\n return (\n <span className={`block truncate ${indent}`} title={text && text !== EM_DASH ? text : undefined}>\n <FormattedValue raw={text} format={col.format} />\n </span>\n );\n },\n })),\n {\n key: '_refine',\n label: '',\n priority: 1,\n className: 'w-8 px-1',\n render: (r) =>\n r.rows.length === 1 && rowRefinePairs(lead(r), columnDefs).length > 0\n ? <RefineTrigger onOpen={() => setRefineRow(lead(r))} />\n : null,\n },\n {\n // The action column sizes to its label so the button never wraps.\n key: '_action',\n label: '',\n priority: 1,\n width: actionColumnWidth(actionLabel),\n className: 'text-right whitespace-nowrap',\n render: (r) => r.rows.length === 1\n ? <RowActionButton row={lead(r)} def={rowAction} onView={() => onRowClick?.(lead(r))} forceView={forceView} />\n : null,\n },\n ];\n\n // Containment by depth: an open line takes a light band, its members a\n // stronger band stepped in under it, and a row's detail the band of its\n // row, indented past it. No rules: indentation and value carry the tree.\n const rowClassName = (r: TableRow) => {\n if (r.depth) return 'bg-surface-sunken border-b-surface-border/40';\n return open.has(r.key) && opens(r) ? 'bg-surface-sunken/50 border-b-surface-border/40' : '';\n };\n\n const renderExpansion = (r: TableRow) => {\n if (!open.has(r.key) || r.rows.length > 1 || sections.length === 0) return null;\n return (\n <div\n onClick={(e) => e.stopPropagation()}\n className={`${r.depth ? 'bg-surface-sunken pl-20' : 'bg-surface-sunken/50 pl-12'} pr-3 pt-1 pb-4`}\n data-testid=\"row-detail-block\"\n >\n <RowDetail role={role} host={lead(r)} version={version} sections={sections} />\n </div>\n );\n };\n\n return (\n <>\n <DataTable\n columns={columns}\n data={lines}\n layout=\"fixed\"\n density=\"dense\"\n keyFn={(r) => r.key}\n onRowClick={onRowClick ? (r) => (r.rows.length === 1 ? onRowClick(lead(r)) : toggle(r.key)) : undefined}\n rowClassName={expandable ? rowClassName : undefined}\n emptyMessage=\"No pending items.\"\n renderExpansion={expandable ? renderExpansion : undefined}\n />\n <RefineDialog\n open={!!refineRow}\n onClose={() => setRefineRow(null)}\n role={role}\n pairs={refineRow ? rowRefinePairs(refineRow, columnDefs) : []}\n onNavigate={navigate}\n onAddFacet={onAddFacet}\n />\n </>\n );\n}\n","import { useState, useEffect } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { interpolateHelp } from '../../lib/x-lt-help';\nimport { MarkdownRenderer } from '../common/display/MarkdownRenderer';\nimport { DateValue } from '../common/display/DateValue';\nimport { FormattedValue as FieldValue, EM_DASH, isAgeFormat } from '../common/display/FormattedValue';\nimport { StickyPagination } from '../common/data/StickyPagination';\nimport { useEscalations } from '../../api/escalations';\nimport { schemaNeedsEnvelope } from '../../lib/schema-needs-envelope';\nimport { getDeep } from '../../lib/x-lt-bind';\nimport { typeColor } from '../../lib/type-color';\nimport { RefineDialog, type RefinePair } from './RefineDialog';\nimport {\n escalationDotClass,\n rowContext,\n RowActionButton,\n RefineTrigger,\n METADATA_TOKEN,\n type ColumnDef,\n type RowActionDef,\n} from './list-view/row-parts';\nimport { FacetTable, type EscalationGroup } from './list-view/FacetTable';\nimport type { LTEscalationRecord } from '../../api/types';\n\nexport { rowContext, rowRefinePairs } from './list-view/row-parts';\nexport type { ColumnDef, RowActionDef } from './list-view/row-parts';\nexport { FIELD_FORMATS } from '../common/display/FormattedValue';\n\n/**\n * EscalationListView — the role-authored rich view of an escalation list, driven\n * by a versioned `list_schema` (x-lt-* markup). The list-page analog of the\n * resolve form: the same `{{domain.path}}` token binding (via interpolateHelp)\n * against each row's context, and MarkdownRenderer for rich bodies.\n *\n * Layouts:\n * active-history — single live item as a card on the left + history column on right\n * active — just the single live item card (no history)\n * facet-table — full pending queue as a table, columns from x-lt-columns\n * facet-board — one card per x-lt-group-by facet value (an entity board:\n * machines, stations), rendered from each group's latest row\n */\n\ninterface CardDef {\n title?: string;\n subtitle?: string;\n body?: string;\n fields?: { label: string; value: string; format?: string }[];\n}\n\ninterface HistoryDef {\n row?: { title?: string; subtitle?: string; meta?: string };\n limit?: number;\n status?: string;\n}\n\n\ninterface BoardCardDef {\n title?: string;\n /** Status chip — any token (commonly {{escalation.subtype}}). */\n state?: string;\n fields?: { label: string; value: string; format?: string }[];\n}\n\n\nexport interface ListSchema {\n 'x-lt-layout'?: string;\n 'x-lt-help'?: string;\n 'x-lt-active'?: CardDef;\n 'x-lt-history'?: HistoryDef;\n 'x-lt-columns'?: ColumnDef[];\n /** facet-board: the \"domain.path\" whose value identifies each entity. */\n 'x-lt-group-by'?: string;\n /** facet-board: the per-entity card definition. */\n 'x-lt-card'?: BoardCardDef;\n /** The per-row action button (claim | view, label, claim duration). */\n 'x-lt-row-action'?: RowActionDef;\n /** facet-table: related sets, row detail sections (see shared/list-schema). */\n 'x-lt-related'?: Record<string, unknown>;\n 'x-lt-row-detail'?: unknown[];\n}\n\n/**\n * Repaint-only minute tick so `format: \"age\"` values stay current. Pure\n * re-render — no network. Mounted once at the view root, only when the\n * schema actually uses ages.\n */\nfunction useAgeTick(enabled: boolean): void {\n const [, setTick] = useState(0);\n useEffect(() => {\n if (!enabled) return;\n const t = window.setInterval(() => setTick((n) => n + 1), 60_000);\n return () => window.clearInterval(t);\n }, [enabled]);\n}\n\nfunction schemaUsesAge(schema: ListSchema): boolean {\n return [...(schema['x-lt-columns'] ?? []), ...(schema['x-lt-card']?.fields ?? [])]\n .some((f) => isAgeFormat(f.format));\n}\n\n\n\n\n\nfunction ActiveCard({ esc, card, rowAction, onOpen, forceView }: {\n esc: LTEscalationRecord;\n card: CardDef;\n rowAction?: RowActionDef;\n onOpen?: () => void;\n forceView?: boolean;\n}) {\n const ctx = rowContext(esc);\n const title = card.title ? interpolateHelp(card.title, ctx) : esc.type;\n return (\n <div>\n <div className=\"flex items-start justify-between gap-6\">\n <button onClick={onOpen} className=\"text-left group min-w-0\">\n <h3 className=\"heading-2 group-hover:text-accent transition-colors leading-tight\">\n {title}\n </h3>\n {card.subtitle && (\n <p className=\"text-xs text-text-tertiary mt-1.5\">{interpolateHelp(card.subtitle, ctx)}</p>\n )}\n </button>\n\n {/* The row action — one-click claim (then the detail page opens already\n claimed), or view for read-only templates. */}\n <RowActionButton row={esc} def={rowAction} onView={onOpen} prominent forceView={forceView} />\n </div>\n\n {card.fields && card.fields.length > 0 && (\n <dl className=\"flex flex-wrap gap-x-10 gap-y-4 mt-6\">\n {card.fields.map((f, i) => (\n <div key={i}>\n <dt className=\"text-2xs font-semibold uppercase tracking-widest text-text-tertiary\">{f.label}</dt>\n <dd className=\"text-xs text-text-primary mt-1\"><FieldValue raw={interpolateHelp(f.value, ctx)} /></dd>\n </div>\n ))}\n </dl>\n )}\n\n {card.body && (\n <div className=\"mt-7 pt-6 border-t border-surface-border/50\">\n <MarkdownRenderer content={interpolateHelp(card.body, ctx)} />\n </div>\n )}\n </div>\n );\n}\n\nfunction HistoryColumn({ role, def, onRowClick }: {\n role: string;\n def: HistoryDef;\n onRowClick?: (row: LTEscalationRecord) => void;\n}) {\n const [show, setShow] = useState(false);\n const query = useEscalations({\n role,\n status: def.status ?? 'resolved',\n sort_by: 'resolved_at',\n order: 'desc',\n limit: def.limit ?? 25,\n enabled: show,\n include: schemaNeedsEnvelope(def) ? 'envelope' : undefined,\n });\n const rows = query.data?.escalations ?? [];\n const total = query.data?.total ?? 0;\n const rowDef = def.row ?? {};\n\n if (!show) {\n return (\n <button\n onClick={() => setShow(true)}\n className=\"text-xs text-accent hover:underline\"\n data-testid=\"load-history\"\n >\n Load full history →\n </button>\n );\n }\n\n if (query.isLoading) {\n return <p className=\"text-xs text-text-tertiary italic\">Loading history…</p>;\n }\n\n if (rows.length === 0) {\n return <p className=\"text-xs text-text-tertiary italic\">No past revisions.</p>;\n }\n\n return (\n <div>\n <div className=\"divide-y divide-surface-border/40\">\n {rows.map((e) => {\n const ctx = rowContext(e);\n return (\n <button\n key={e.id}\n onClick={() => onRowClick?.(e)}\n className=\"w-full text-left py-2.5 group flex items-center gap-3\"\n >\n {/* Status as a bare outlined dot — colour carries the meaning. */}\n <span\n className={`w-2.5 h-2.5 shrink-0 rounded-full dot-ring ${escalationDotClass(e)}`}\n title={e.status}\n />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block text-xs text-text-primary group-hover:text-accent transition-colors truncate\">\n {rowDef.title ? interpolateHelp(rowDef.title, ctx) : e.type}\n </span>\n {rowDef.subtitle && (\n <span className=\"block text-2xs text-text-tertiary truncate\">\n {interpolateHelp(rowDef.subtitle, ctx)}\n </span>\n )}\n </span>\n {rowDef.meta\n ? <span className=\"text-2xs text-text-tertiary shrink-0\">{interpolateHelp(rowDef.meta, ctx)}</span>\n : e.resolved_at && <DateValue date={e.resolved_at} format=\"relative\" className=\"text-2xs text-text-tertiary shrink-0 whitespace-nowrap\" />}\n </button>\n );\n })}\n </div>\n {total > rows.length && (\n <p className=\"text-2xs text-text-quaternary mt-3\">Showing {rows.length} of {total}.</p>\n )}\n </div>\n );\n}\n\n\n\nfunction SectionLabel({ children }: { children: React.ReactNode }) {\n return (\n <p className=\"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-3\">{children}</p>\n );\n}\n\n// ── facet-board — one card per entity (machine, station) ─────────────────────\n\ninterface BoardGroup {\n key: string;\n /** The group's identity as stored (native type preserved for the facet URL). */\n rawValue: unknown;\n latest: LTEscalationRecord;\n count: number;\n}\n\n/**\n * Group rows by the resolved x-lt-group-by value; each card renders from the\n * group's most recent row (by created_at). Rows without the facet are skipped —\n * the board reflects the scope, it doesn't invent entities.\n */\nexport function groupBoardRows(rows: LTEscalationRecord[], groupBy: string): BoardGroup[] {\n const dot = groupBy.indexOf('.');\n const facetKey = groupBy.startsWith('metadata.') ? groupBy.slice('metadata.'.length) : null;\n const groups = new Map<string, BoardGroup>();\n for (const row of rows) {\n const ctx = rowContext(row);\n let v: unknown;\n try {\n v = dot === -1\n ? (ctx as unknown as Record<string, unknown>)[groupBy]\n : getDeep((ctx as unknown as Record<string, unknown>)[groupBy.slice(0, dot)], groupBy.slice(dot + 1));\n } catch {\n v = undefined;\n }\n if (v === undefined || v === null || v === '') continue;\n const key = String(v);\n const rawValue = facetKey ? (row.metadata?.[facetKey] ?? v) : v;\n const existing = groups.get(key);\n if (!existing) {\n groups.set(key, { key, rawValue, latest: row, count: 1 });\n } else {\n existing.count += 1;\n if (new Date(row.created_at) > new Date(existing.latest.created_at)) existing.latest = row;\n }\n }\n return [...groups.values()].sort((a, b) => a.key.localeCompare(b.key));\n}\n\n\nfunction FacetBoard({ schema, rows, role, onOpenDetail, onOpenGroup, onAddFacet, forceView }: {\n schema: ListSchema;\n rows: LTEscalationRecord[];\n role: string;\n forceView?: boolean;\n /** Plain card click — the group's latest row opens in the detail view. */\n onOpenDetail?: (row: LTEscalationRecord) => void;\n /** History affordances — receive a filtered table/timeline deep link. */\n onOpenGroup?: (url: string) => void;\n /** Shift+click — merge one facet into the live filter set (additive). */\n onAddFacet?: (key: string, value: unknown) => void;\n}) {\n const navigate = useNavigate();\n const groupBy = schema['x-lt-group-by'];\n const card = schema['x-lt-card'] ?? {};\n const rowAction = schema['x-lt-row-action'];\n const [refineGroup, setRefineGroup] = useState<BoardGroup | null>(null);\n\n if (!groupBy) {\n return <p className=\"text-xs text-text-tertiary italic\">facet-board needs an x-lt-group-by path.</p>;\n }\n const facetKey = groupBy.startsWith('metadata.') ? groupBy.slice('metadata.'.length) : null;\n const groups = groupBoardRows(rows, groupBy);\n if (groups.length === 0) {\n return <p className=\"text-xs text-text-tertiary italic\">No entities in scope.</p>;\n }\n\n // The card's refinable facts: the entity identity (the group-by facet)\n // plus every metadata-bound card field — one dialog per card, replacing\n // hover-revealed per-field icons (hover-only fails the iPad floor).\n const groupRefinePairs = (g: BoardGroup): RefinePair[] => {\n const pairs: RefinePair[] = [];\n if (facetKey) pairs.push({ key: facetKey, label: facetKey, value: g.rawValue });\n const seen = new Set(pairs.map((p) => p.key));\n for (const f of card.fields ?? []) {\n const bound = f.value.match(METADATA_TOKEN)?.[1];\n if (!bound || seen.has(bound)) continue;\n const raw = g.latest.metadata?.[bound];\n if (raw === undefined || raw === null || raw === '') continue;\n seen.add(bound);\n pairs.push({ key: bound, label: f.label, value: raw });\n }\n return pairs;\n };\n\n return (\n <div className=\"grid grid-cols-[repeat(auto-fill,minmax(15rem,1fr))] gap-4\" data-testid=\"facet-board\">\n {groups.map((g) => {\n const ctx = rowContext(g.latest);\n const title = card.title ? interpolateHelp(card.title, ctx) : g.key;\n const state = card.state ? interpolateHelp(card.state, ctx) : (g.latest.subtype || g.latest.status);\n const stateHue = typeColor(state);\n const refinable = groupRefinePairs(g).length > 0;\n\n const activate = (e: { shiftKey: boolean }) => {\n if (e.shiftKey && facetKey && onAddFacet) {\n onAddFacet(facetKey, g.rawValue);\n return;\n }\n onOpenDetail?.(g.latest);\n };\n\n return (\n <div\n key={g.key}\n role=\"button\"\n tabIndex={0}\n onClick={activate}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); activate(e); }\n }}\n title={facetKey ? 'Open the latest item · ⇧ click to filter the board' : 'Open the latest item'}\n className=\"group/card border-l-2 border-accent/30 bg-surface-sunken/40 rounded-[0.125em] px-4 py-3.5 cursor-pointer transition-colors hover:bg-surface-sunken/70 focus:outline-none focus-visible:ring-1 focus-visible:ring-accent/40\"\n data-testid=\"facet-board-card\"\n >\n <div className=\"flex items-center justify-between gap-2 mb-2.5\">\n <span className=\"text-2xs font-semibold uppercase tracking-wider text-text-secondary truncate\">\n {title}\n </span>\n <span className=\"flex items-center gap-1 shrink-0\">\n <span\n className=\"px-1.5 py-0.5 rounded text-2xs font-mono font-medium\"\n style={{ color: stateHue.text, backgroundColor: stateHue.bg }}\n title={state}\n >\n {state}\n </span>\n {refinable && <RefineTrigger onOpen={() => setRefineGroup(g)} className=\"-my-1 -mr-1\" />}\n </span>\n </div>\n {card.fields && card.fields.length > 0 && (\n <dl className=\"space-y-1\">\n {card.fields.map((f, i) => {\n const text = interpolateHelp(f.value, ctx);\n return (\n <div key={i} className=\"flex items-baseline justify-between gap-3\">\n <dt className=\"text-2xs uppercase tracking-wider text-text-quaternary shrink-0\">{f.label}</dt>\n <dd\n className=\"min-w-0 truncate text-2xs text-text-primary\"\n title={text && text !== EM_DASH ? text : undefined}\n >\n <FieldValue raw={text} format={f.format} />\n </dd>\n </div>\n );\n })}\n </dl>\n )}\n\n <div className=\"mt-3 flex justify-end\">\n <RowActionButton row={g.latest} def={rowAction} onView={() => onOpenDetail?.(g.latest)} forceView={forceView} />\n </div>\n </div>\n );\n })}\n\n <RefineDialog\n open={!!refineGroup}\n onClose={() => setRefineGroup(null)}\n role={role}\n pairs={refineGroup ? groupRefinePairs(refineGroup) : []}\n onNavigate={onOpenGroup ?? navigate}\n onAddFacet={onAddFacet}\n />\n </div>\n );\n}\n\nexport function EscalationListView({ role, listSchema, listSchemaVersion, activeEscalations, groups, onRowClick, onOpenGroup, onAddFacet, forceViewAction, total, page, totalPages, pageSize, onPageChange, onPageSizeChange }: {\n role: string;\n listSchema: ListSchema;\n /** The list schema version rendered; related sets read the same version. */\n listSchemaVersion?: number | null;\n activeEscalations: LTEscalationRecord[];\n /** facet-table grouped reads: the page's groups, in order. */\n groups?: EscalationGroup[] | null;\n onRowClick?: (row: LTEscalationRecord) => void;\n /** facet-board history affordances — receive a filtered deep link. */\n onOpenGroup?: (url: string) => void;\n /** facet-board ⇧ click — merge one facet into the live filter set. */\n onAddFacet?: (key: string, value: unknown) => void;\n /** Render claim row-actions as view actions. For surfaces listing rows the\n * viewer already holds (e.g. My Escalations), where a claim gesture is\n * inapplicable — the button opens the detail page instead. */\n forceViewAction?: boolean;\n total?: number;\n page?: number;\n totalPages?: number;\n pageSize?: number;\n onPageChange?: (page: number) => void;\n onPageSizeChange?: (size: number) => void;\n}) {\n const layout = listSchema['x-lt-layout'];\n const card = listSchema['x-lt-active'] ?? {};\n const rowAction = listSchema['x-lt-row-action'];\n const active = activeEscalations[0];\n const help = listSchema['x-lt-help'];\n useAgeTick(schemaUsesAge(listSchema));\n\n // The active item is a distinct surface on the page wash — the same card\n // treatment the detail page gives its form sections. The label heads the\n // card; the history column beside it stays a quiet chronicle on the wash.\n const activeBlock = (\n <div className=\"border border-surface-border/60 bg-surface-sunken rounded-[0.25em] p-4\">\n <SectionLabel>Active</SectionLabel>\n {active ? (\n <ActiveCard esc={active} card={card} rowAction={rowAction} onOpen={() => onRowClick?.(active)} forceView={forceViewAction} />\n ) : (\n <p className=\"text-xs text-text-tertiary italic\">No active item right now.</p>\n )}\n </div>\n );\n\n const header = help && active ? (\n <div className=\"mb-8\"><MarkdownRenderer content={interpolateHelp(help, rowContext(active))} /></div>\n ) : help ? (\n <div className=\"mb-8\"><MarkdownRenderer content={help} /></div>\n ) : null;\n\n if (layout === 'facet-table') {\n // The table stands alone — no header text above it. Instructions belong\n // in the form's help surfaces; totals live in the pagination bar.\n const resolvedTotal = total ?? activeEscalations.length;\n return (\n <div>\n <FacetTable schema={listSchema as Record<string, unknown>} rows={activeEscalations} groups={groups} role={role} version={listSchemaVersion} onRowClick={onRowClick} onAddFacet={onAddFacet} forceView={forceViewAction} />\n {page !== undefined && totalPages !== undefined && onPageChange && (\n <StickyPagination\n page={page}\n totalPages={totalPages}\n onPageChange={onPageChange}\n total={resolvedTotal}\n pageSize={pageSize ?? 25}\n onPageSizeChange={onPageSizeChange}\n />\n )}\n </div>\n );\n }\n\n if (layout === 'facet-board') {\n return (\n <div>\n {header}\n <FacetBoard\n schema={listSchema}\n rows={activeEscalations}\n role={role}\n onOpenDetail={onRowClick}\n onOpenGroup={onOpenGroup}\n onAddFacet={onAddFacet}\n forceView={forceViewAction}\n />\n {page !== undefined && totalPages !== undefined && onPageChange && totalPages > 1 && (\n <StickyPagination\n page={page}\n totalPages={totalPages}\n onPageChange={onPageChange}\n total={total ?? activeEscalations.length}\n pageSize={pageSize ?? 25}\n onPageSizeChange={onPageSizeChange}\n />\n )}\n </div>\n );\n }\n\n if (layout === 'active-history') {\n return (\n <div>\n {header}\n <div className=\"grid grid-cols-1 @split:grid-cols-[1.6fr_1fr] gap-8 @split:gap-12 items-start\">\n {activeBlock}\n {/* pt-4 seats the History label on the Active label's optical line\n (the card's own padding provides that inset on the left). */}\n <div className=\"@split:pt-4\">\n <SectionLabel>History</SectionLabel>\n <HistoryColumn role={role} def={listSchema['x-lt-history'] ?? {}} onRowClick={onRowClick} />\n </div>\n </div>\n </div>\n );\n }\n\n // \"active\" (or any non-table layout): just the active card.\n return (\n <div>\n {header}\n {activeBlock}\n </div>\n );\n}\n","import { useState } from 'react';\nimport { Link } from 'react-router-dom';\nimport { Circle, Bell, Clock, ListFilter, Search, History } from 'lucide-react';\nimport { EntityTimelinePanel } from '../../components/escalation/EntityTimelinePanel';\nimport { useShellPanelOptional } from '../../hooks/useShellPanel';\nimport type { Column } from '../../components/common/data/DataTable';\nimport { FilterBar, FilterSelect, FilterInput, FilterDivider } from '../../components/common/data/FilterBar';\nimport { PriorityBadge } from '../../components/common/display/PriorityBadge';\nimport { RolePill } from '../../components/common/display/RolePill';\nimport { WorkflowPill } from '../../components/common/display/WorkflowPill';\nimport { UserName } from '../../components/common/display/UserName';\nimport { CountdownTimer } from '../../components/common/display/CountdownTimer';\nimport { formatAgoCompact } from '../../lib/format';\nimport { isEffectivelyClaimed, isAckEscalation } from '../../lib/escalation';\nimport { metadataFacetUrl } from '../../lib/facet-url';\nimport type { LTEscalationRecord } from '../../api/types';\n\nexport interface EscalationColumnOpts {\n highlightKeys?: string[];\n}\n\n// Shared cell text: a consistent resting shade for every cell, sharpening to\n// the primary text colour when the row is hovered. Cells (and pills via their\n// `inherit` tone) all read this single source so the whole row darkens as one.\nconst CELL_TEXT = 'text-text-secondary transition-colors group-hover/row:text-text-primary';\n\n/** Status dot — rendered inline before summary. */\nfunction StatusDot({ row }: { row: LTEscalationRecord }) {\n if (isAckEscalation(row)) {\n const color = row.status === 'resolved' ? 'text-status-success' : 'text-text-tertiary';\n return <Bell className={`w-3 h-3 shrink-0 ${color}`} />;\n }\n if (row.status === 'resolved') {\n return <Circle className=\"w-2.5 h-2.5 shrink-0 text-status-success\" strokeWidth={2.5} />;\n }\n if (row.status === 'cancelled') {\n return <Circle className=\"w-2.5 h-2.5 shrink-0 text-status-error\" strokeWidth={2.5} />;\n }\n if (row.status === 'expired') {\n return <Circle className=\"w-2.5 h-2.5 shrink-0 text-text-tertiary\" strokeWidth={2.5} />;\n }\n if (isEffectivelyClaimed(row)) {\n return <Circle className=\"w-2.5 h-2.5 shrink-0 text-status-warning\" strokeWidth={2.5} />;\n }\n // pending (unclaimed)\n return <Circle className=\"w-2.5 h-2.5 shrink-0 text-status-active\" strokeWidth={2.5} />;\n}\n\n/** Key/value metadata dict with 1 row collapsed by default, expand for the rest. */\nexport function MetadataCell({\n metadata,\n role,\n highlightKeys,\n}: {\n metadata: Record<string, unknown> | null;\n role: string;\n highlightKeys?: string[];\n}) {\n const [expanded, setExpanded] = useState(false);\n // Null outside the shell (tests, standalone renders) — the timeline\n // affordance simply doesn't render there.\n const shell = useShellPanelOptional();\n\n if (!metadata || Object.keys(metadata).length === 0) {\n return <span className=\"text-2xs text-text-tertiary\">—</span>;\n }\n\n const hl = highlightKeys ?? [];\n // Highlighted keys first, then the rest in insertion order.\n const allKeys = [\n ...hl.filter((k) => k in metadata),\n ...Object.keys(metadata).filter((k) => !hl.includes(k)),\n ];\n\n const shown = expanded ? allKeys : allKeys.slice(0, 1);\n const hiddenCount = allKeys.length - 1;\n\n return (\n <div className=\"w-full\" onClick={(e) => e.stopPropagation()}>\n <div className=\"space-y-px\">\n {shown.map((k, i) => {\n const sv = typeof metadata[k] === 'object' && metadata[k] !== null\n ? JSON.stringify(metadata[k])\n : String(metadata[k]);\n const isHl = hl.includes(k);\n const isLastShown = i === shown.length - 1;\n return (\n <div key={k} className=\"group/mrow flex items-center gap-1 min-w-0\">\n <span\n className={`shrink-0 w-14 text-2xs font-mono uppercase tracking-wide truncate ${isHl ? 'text-accent' : 'text-text-tertiary'}`}\n title={k}\n >\n {k}\n </span>\n <span\n className={`flex-1 min-w-0 text-2xs font-medium truncate ${isHl ? 'text-text-primary' : 'text-text-secondary'}`}\n title={sv}\n >\n {sv}\n </span>\n <span className=\"flex items-center gap-px shrink-0 opacity-50 group-hover/mrow:opacity-100 transition-opacity\">\n <Link\n to={metadataFacetUrl(k, metadata[k], role)}\n className=\"p-0.5 rounded text-text-quaternary hover:text-accent transition-colors\"\n title={`Filter ${role}: ${k} = ${sv}`}\n onClick={(ev) => ev.stopPropagation()}\n >\n <ListFilter className=\"w-3 h-3\" />\n </Link>\n <Link\n to={metadataFacetUrl(k, metadata[k])}\n className=\"p-0.5 rounded text-text-quaternary hover:text-accent transition-colors\"\n title={`Search all: ${k} = ${sv}`}\n onClick={(ev) => ev.stopPropagation()}\n >\n <Search className=\"w-3 h-3\" />\n </Link>\n {/* filter-present / search-present / history-past — the third\n verb of the triad. String values only: the timeline's GIN\n containment match only serves JSON-string facets. */}\n {shell && typeof metadata[k] === 'string' && (\n <button\n className=\"p-0.5 rounded text-text-quaternary hover:text-accent transition-colors\"\n title={`Timeline: every station ${sv} has moved through`}\n onClick={(ev) => {\n ev.stopPropagation();\n shell.setPanel(\n <EntityTimelinePanel facetKey={k} value={metadata[k] as string} role={role} />,\n { key: 'entity-timeline', width: 420 },\n );\n }}\n >\n <History className=\"w-3 h-3\" />\n </button>\n )}\n </span>\n {/* +N inline at end of single visible row when collapsed */}\n {!expanded && hiddenCount > 0 && (\n <button\n onClick={(ev) => { ev.stopPropagation(); setExpanded(true); }}\n className=\"shrink-0 text-2xs text-text-quaternary hover:text-accent transition-colors font-mono\"\n title={`Show ${hiddenCount} more fields`}\n >\n +{hiddenCount}\n </button>\n )}\n {/* ↑ inline at end of last row when expanded */}\n {expanded && isLastShown && hiddenCount > 0 && (\n <button\n onClick={(ev) => { ev.stopPropagation(); setExpanded(false); }}\n className=\"shrink-0 text-2xs text-text-quaternary hover:text-accent transition-colors\"\n title=\"Show less\"\n >\n ↑\n </button>\n )}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\n/** Build the shared column set, optionally wiring metadata filter callbacks. */\nexport function makeEscalationColumns(opts: EscalationColumnOpts = {}): Column<LTEscalationRecord>[] {\n return [\n {\n key: 'description',\n label: 'Summary',\n priority: 1,\n render: (row) => (\n <div className=\"flex items-center gap-2 overflow-hidden\">\n <span className=\"shrink-0\"><StatusDot row={row} /></span>\n <span className={`truncate text-xs ${CELL_TEXT}`}>{row.description || row.type}</span>\n </div>\n ),\n className: 'max-w-0',\n },\n // The manufacturing-floor column budget: identity, owner, urgency, age.\n // Everything else (workflow type, metadata, exact timestamps) lives in\n // the facet drawer and the detail page — never as a scrolling column.\n {\n key: 'assigned_to',\n label: 'Assignee',\n priority: 2,\n render: (row) => (row.assigned_to\n ? <UserName userId={row.assigned_to} className={`block truncate text-xs ${CELL_TEXT}`} />\n : <span className=\"text-xs text-text-quaternary\">—</span>),\n className: 'w-36 max-w-[9rem]',\n },\n {\n key: 'role',\n label: 'Role',\n priority: 2,\n render: (row) => (\n <span className={CELL_TEXT}>\n <RolePill role={row.role} size=\"md\" tone=\"inherit\" />\n </span>\n ),\n className: 'w-44 min-w-[11rem]',\n },\n {\n key: 'priority',\n label: 'Pri',\n priority: 2,\n render: (row) => (\n <span className={CELL_TEXT}>\n <PriorityBadge priority={row.priority} size=\"sm\" tone=\"inherit\" />\n </span>\n ),\n className: 'w-10',\n },\n // Enrichment columns — the jumping-off facets. The budget governs the\n // floor: these return only when the table has room (@split / @wall),\n // and in card mode they fold to pairs. The metadata cell carries the\n // clickable refine icons: filter within the role, search across roles\n // (admins), shift+click to AND facets.\n {\n key: 'workflow_type',\n label: 'Workflow',\n priority: 2,\n showFrom: 'split',\n render: (row) => <WorkflowPill type={row.workflow_type || row.type} />,\n className: 'w-40 whitespace-nowrap',\n },\n {\n key: 'metadata',\n label: 'Metadata',\n priority: 2,\n showFrom: 'wall',\n render: (row) => (\n <MetadataCell\n metadata={row.metadata}\n role={row.role}\n highlightKeys={opts.highlightKeys}\n />\n ),\n className: 'w-80 max-w-[19rem] align-top',\n },\n {\n key: 'created_at',\n label: 'Ago',\n priority: 1,\n render: (row) => (\n <span className={`text-xs tabular-nums ${CELL_TEXT}`} title={row.created_at}>\n {formatAgoCompact(row.created_at)}\n </span>\n ),\n className: 'w-14 whitespace-nowrap',\n },\n ];\n}\n\n/** Base columns shared by all escalation list pages (no filter callback). */\nexport const ESCALATION_COLUMNS: Column<LTEscalationRecord>[] = makeEscalationColumns();\n\n/** Time-remaining column for claimed escalations — aligns with checkbox column on All Escalations. */\nexport const TIME_LEFT_COLUMN: Column<LTEscalationRecord> = {\n key: 'expires',\n label: (<Clock className=\"w-3.5 h-3.5 text-text-tertiary\" />) as any,\n render: (row) =>\n row.assigned_until ? (\n <CountdownTimer until={row.assigned_until} />\n ) : (\n <span className=\"text-xs text-text-tertiary\">—</span>\n ),\n className: 'w-16 whitespace-nowrap',\n priority: 1,\n};\n\n/** Status icon column — color-coded filled circle, or bell for ACK/notification escalations. */\nexport const STATUS_COLUMN: Column<LTEscalationRecord> = {\n key: 'status',\n label: '',\n render: (row) => {\n if (isAckEscalation(row)) {\n const color = row.status === 'resolved' ? 'text-status-success' : 'text-text-tertiary';\n return <Bell className={`w-3 h-3 ${color}`} />;\n }\n if (row.status === 'resolved') {\n return <Circle className=\"w-2.5 h-2.5 text-status-success\" strokeWidth={2.5} />;\n }\n if (isEffectivelyClaimed(row)) {\n return <Circle className=\"w-2.5 h-2.5 text-status-warning\" strokeWidth={2.5} />;\n }\n // pending (unclaimed)\n return <Circle className=\"w-2.5 h-2.5 text-text-tertiary\" strokeWidth={2.5} />;\n },\n className: 'w-8',\n priority: 1,\n};\n\n/** Claimed-only status icon (always orange, or bell for ACK). */\nexport const CLAIMED_STATUS_COLUMN: Column<LTEscalationRecord> = {\n key: 'status',\n label: '',\n render: (row) =>\n isAckEscalation(row)\n ? <Bell className=\"w-3 h-3 text-status-warning\" />\n : <Circle className=\"w-2.5 h-2.5 text-status-warning\" strokeWidth={2.5} />,\n className: 'w-8',\n priority: 1,\n};\n\n/** Priority filter options shared by both pages. */\nexport const PRIORITY_OPTIONS = [\n { value: '1', label: 'P1' },\n { value: '2', label: 'P2' },\n { value: '3', label: 'P3' },\n { value: '4', label: 'P4' },\n];\n\n/** Status filter options for escalation list pages. `all` spans every status so a\n * metadata search (e.g. one order id) returns its escalations regardless of status. */\nexport const STATUS_OPTIONS = [\n { value: 'all', label: 'All' },\n { value: 'available', label: 'Available' },\n { value: 'claimed', label: 'Claimed' },\n { value: 'resolved', label: 'Resolved' },\n { value: 'cancelled', label: 'Cancelled' },\n { value: 'expired', label: 'Expired' },\n];\n\n/** Shared filter bar for escalation list pages. */\nexport function EscalationFilterBar({\n filters,\n setFilter,\n roles,\n types,\n showStatus = false,\n showSearch = true,\n showRole = true,\n actions,\n}: {\n filters: { role: string; type: string; priority: string; status?: string; search?: string };\n setFilter: (key: any, value: string) => void;\n roles: string[];\n types: string[];\n showStatus?: boolean;\n // Free-text search lives here by default, but the faceted page folds it into\n // the drawer instead so there's a single search surface.\n showSearch?: boolean;\n /** Kiosk sessions hide the role filter — the session IS the role. */\n showRole?: boolean;\n actions?: React.ReactNode;\n}) {\n // Non-default filters power the folded Filters button's badge.\n const activeFilterCount = [\n filters.role,\n filters.type,\n filters.priority,\n filters.status && filters.status !== 'all' ? filters.status : '',\n filters.search ?? '',\n ].filter(Boolean).length;\n\n return (\n <FilterBar actions={actions} activeFilterCount={activeFilterCount}>\n {showStatus && (\n <>\n <FilterSelect\n label=\"Status\"\n value={filters.status ?? ''}\n onChange={(v) => setFilter('status', v)}\n options={STATUS_OPTIONS}\n />\n <FilterDivider />\n </>\n )}\n {/* Role is the queue's primary facet — URL-driven (?role=). Pages whose\n title doubles as a queue selector share the same param, so the two\n controls mirror each other. Kiosk sessions hide it: the session IS\n the role. */}\n {showRole && (\n <>\n <FilterSelect\n label=\"Role\"\n value={filters.role}\n onChange={(v) => setFilter('role', v)}\n options={roles.map((r) => ({ value: r, label: r }))}\n />\n <FilterDivider />\n </>\n )}\n <FilterSelect\n label=\"Priority\"\n value={filters.priority}\n onChange={(v) => setFilter('priority', v)}\n options={PRIORITY_OPTIONS}\n />\n <FilterDivider />\n <FilterSelect\n label=\"Workflow Type\"\n value={filters.type}\n onChange={(v) => setFilter('type', v)}\n options={types.map((t) => ({ value: t, label: t }))}\n />\n {showSearch && (\n <>\n <FilterDivider />\n <FilterInput\n label=\"Search\"\n value={filters.search ?? ''}\n onChange={(v) => setFilter('search', v)}\n placeholder=\"ID, workflow, origin…\"\n />\n </>\n )}\n </FilterBar>\n );\n}\n"],"names":["PALETTE","hash","str","h","i","typeColor","typeName","FIND_THRESHOLD","RefineDialog","open","onClose","role","pairs","onNavigate","onAddFacet","selected","setSelected","useState","find","setFind","prevOpen","setPrevOpen","bound","p","preset","needle","visible","t","toggle","key","prev","next","chosen","facets","none","go","url","jsx","Modal","jsxs","Search","e","on","Check","metadataFacetsUrl","useRelatedAggregates","ids","version","enabled","sorted","useQuery","apiFetch","useRelatedRows","id","set","limit","SINGLE_TOKEN","ANY_TOKEN","MISSING_VALUE","parseJsonObject","value","parsed","rowTemplateContext","row","readToken","path","ctx","dot","domain","HELP_DOMAINS","root","getDeep","resolveTemplateValue","single","raw","text","interpolateHelp","resolveRelatedFacets","narrow","out","resolved","splitLabel","col","_a","SPLIT_PATHS","_b","RelatedCell","agg","drillUrl","EM_DASH","order","splits","n","a","b","y","restricted","title","r","href","chip","Link","ROLE_FORMAT","cellText","template","rowContext","interpolateItemTemplate","DetailSection","host","section","roleLabels","navigate","useNavigate","query","rows","labels","_c","hostValues","v","columns","values","displayRoleTitle","FormattedValue","target","DataTable","RowDetail","sections","withOpenMembers","members","m","buildTableRows","groups","byId","g","numeric","nums","foldColumnText","fold","GROUP_FOLDS","mergeAggregates","aggs","present","k","distinctByMatch","seen","match","safeRelations","schema","readListSchemaRelations","RelatedFacetTable","props","related","sets","useRelatedSetEvents","FacetTableBody","FacetTable","relations","useMemo","onRowClick","forceView","setsLoading","columnDefs","rowAction","refineRow","setRefineRow","setOpen","tableRows","lines","grouped","expandable","opens","relatedCell","name","counted","relatedRole","actionLabel","lead","ChevronRight","escalationDotClass","c","IDENTITY_COLUMN_WIDTH","indent","rowRefinePairs","RefineTrigger","actionColumnWidth","RowActionButton","rowClassName","renderExpansion","Fragment","useAgeTick","setTick","useEffect","schemaUsesAge","f","isAgeFormat","ActiveCard","esc","card","onOpen","FieldValue","MarkdownRenderer","HistoryColumn","def","show","setShow","useEscalations","schemaNeedsEnvelope","total","rowDef","DateValue","SectionLabel","children","groupBoardRows","groupBy","facetKey","rawValue","existing","FacetBoard","onOpenDetail","onOpenGroup","refineGroup","setRefineGroup","groupRefinePairs","METADATA_TOKEN","state","stateHue","refinable","activate","EscalationListView","listSchema","listSchemaVersion","activeEscalations","forceViewAction","page","totalPages","pageSize","onPageChange","onPageSizeChange","layout","active","help","activeBlock","header","resolvedTotal","StickyPagination","CELL_TEXT","StatusDot","isAckEscalation","color","Bell","Circle","isEffectivelyClaimed","MetadataCell","metadata","highlightKeys","expanded","setExpanded","shell","useShellPanelOptional","hl","allKeys","shown","hiddenCount","sv","isHl","isLastShown","metadataFacetUrl","ev","ListFilter","EntityTimelinePanel","History","makeEscalationColumns","opts","UserName","RolePill","PriorityBadge","WorkflowPill","formatAgoCompact","ESCALATION_COLUMNS","TIME_LEFT_COLUMN","Clock","CountdownTimer","PRIORITY_OPTIONS","STATUS_OPTIONS","EscalationFilterBar","filters","setFilter","roles","types","showStatus","showSearch","showRole","actions","activeFilterCount","FilterBar","FilterSelect","FilterDivider","FilterInput"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{a as n,j as s}from"./vendor-query-DvWWuNIB.js";import{aG as h,e as g}from"./index-BUYokcrl.js";import{D as y}from"./DataTable-spX1dFyb.js";import{F as C,b as j}from"./FilterBar-D-6xVHIw.js";import{R as q,a as u}from"./RowActions-Bdd7z4eB.js";import{u as R}from"./useFilterParams-DBRw1Hcv.js";import{P as b}from"./PageHeader-CMd3f4bz.js";import{T as _}from"./TaskQueuePill-h0oorVMe.js";import{W as N}from"./WorkflowPill-Dg7BDTyM.js";import{az as v,E as S,g as E}from"./vendor-icons-CeVtUKyP.js";import{u as I}from"./vendor-react-_9U4mKFr.js";import"./EmptyState-DgC_6njU.js";import"./useContainerWidth-DSLp1gEm.js";function G(){const r=I(),{data:c,isLoading:m}=h(),{filters:t,setFilter:i}=R({filters:{search:"",queue:""}}),[a,p]=n.useState(t.search);n.useEffect(()=>{if(a===t.search)return;const e=setTimeout(()=>i("search",a),g);return()=>clearTimeout(e)},[a,i,t.search]);const o=c??[],d=n.useMemo(()=>[...new Set(o.map(e=>e.task_queue).filter(Boolean))].sort(),[o]),f=n.useMemo(()=>{let e=o;if(t.search){const l=t.search.toLowerCase();e=e.filter(w=>w.name.toLowerCase().includes(l))}return t.queue&&(e=e.filter(l=>l.task_queue===t.queue)),e},[o,t]),k=[{key:"name",label:"Workflow",render:e=>s.jsx(N,{type:e.name})},{key:"task_queue",label:"Queue",render:e=>s.jsx(_,{queue:e.task_queue}),className:"whitespace-nowrap"},{key:"registered",label:"Status",render:e=>e.registered?s.jsxs("span",{className:"inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-2xs font-medium bg-accent/10 text-accent",children:[s.jsx(v,{className:"w-3 h-3"}),"Certified"]}):s.jsx("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded text-2xs font-medium bg-surface-sunken text-text-tertiary",children:"Durable"}),className:"whitespace-nowrap"},{key:"actions",label:"",render:e=>s.jsx(q,{children:e.registered?s.jsx(u,{icon:S,title:"View config",onClick:()=>r(`/workflows/registry/${encodeURIComponent(e.name)}`)}):s.jsx(u,{icon:E,title:"Register workflow",onClick:()=>r(`/workflows/registry/new?workflow_type=${encodeURIComponent(e.name)}&task_queue=${encodeURIComponent(e.task_queue)}`)})}),className:"w-16 text-right"}],x=e=>{e.registered?r(`/workflows/registry/${encodeURIComponent(e.name)}`):r(`/workflows/registry/new?workflow_type=${encodeURIComponent(e.name)}&task_queue=${encodeURIComponent(e.task_queue)}`)};return s.jsxs("div",{children:[s.jsx(b,{title:"Workers",docsHash:"#docs:dashboard.md:task-queues"}),s.jsxs(C,{children:[s.jsx("input",{type:"text",placeholder:"Search workers...",value:a,onChange:e=>p(e.target.value),className:"input text-2xs py-1 px-2 w-56"}),s.jsx(j,{label:"Queue",value:t.queue,onChange:e=>i("queue",e),options:d.map(e=>({value:e,label:e}))})]}),s.jsx(y,{columns:k,data:f,keyFn:e=>e.name,onRowClick:x,isLoading:m,emptyMessage:"No active workers"})]})}export{G as WorkersPage};
2
- //# sourceMappingURL=index-C3VTJcrp.js.map
1
+ import{a as n,j as s}from"./vendor-query-DvWWuNIB.js";import{aH as h,e as g}from"./index-LRYC__mE.js";import{D as y}from"./DataTable-FjFhx0SE.js";import{F as C,b as j}from"./FilterBar-BulSsWb2.js";import{R as q,a as u}from"./RowActions-Bdd7z4eB.js";import{u as R}from"./useFilterParams-DBRw1Hcv.js";import{P as b}from"./PageHeader-CMd3f4bz.js";import{T as _}from"./TaskQueuePill-h0oorVMe.js";import{W as N}from"./WorkflowPill-Dg7BDTyM.js";import{az as v,E as S,g as E}from"./vendor-icons-CeVtUKyP.js";import{u as I}from"./vendor-react-_9U4mKFr.js";import"./EmptyState-DgC_6njU.js";import"./useContainerWidth-DSLp1gEm.js";function z(){const r=I(),{data:c,isLoading:m}=h(),{filters:t,setFilter:i}=R({filters:{search:"",queue:""}}),[a,p]=n.useState(t.search);n.useEffect(()=>{if(a===t.search)return;const e=setTimeout(()=>i("search",a),g);return()=>clearTimeout(e)},[a,i,t.search]);const o=c??[],d=n.useMemo(()=>[...new Set(o.map(e=>e.task_queue).filter(Boolean))].sort(),[o]),f=n.useMemo(()=>{let e=o;if(t.search){const l=t.search.toLowerCase();e=e.filter(w=>w.name.toLowerCase().includes(l))}return t.queue&&(e=e.filter(l=>l.task_queue===t.queue)),e},[o,t]),k=[{key:"name",label:"Workflow",render:e=>s.jsx(N,{type:e.name})},{key:"task_queue",label:"Queue",render:e=>s.jsx(_,{queue:e.task_queue}),className:"whitespace-nowrap"},{key:"registered",label:"Status",render:e=>e.registered?s.jsxs("span",{className:"inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-2xs font-medium bg-accent/10 text-accent",children:[s.jsx(v,{className:"w-3 h-3"}),"Certified"]}):s.jsx("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded text-2xs font-medium bg-surface-sunken text-text-tertiary",children:"Durable"}),className:"whitespace-nowrap"},{key:"actions",label:"",render:e=>s.jsx(q,{children:e.registered?s.jsx(u,{icon:S,title:"View config",onClick:()=>r(`/workflows/registry/${encodeURIComponent(e.name)}`)}):s.jsx(u,{icon:E,title:"Register workflow",onClick:()=>r(`/workflows/registry/new?workflow_type=${encodeURIComponent(e.name)}&task_queue=${encodeURIComponent(e.task_queue)}`)})}),className:"w-16 text-right"}],x=e=>{e.registered?r(`/workflows/registry/${encodeURIComponent(e.name)}`):r(`/workflows/registry/new?workflow_type=${encodeURIComponent(e.name)}&task_queue=${encodeURIComponent(e.task_queue)}`)};return s.jsxs("div",{children:[s.jsx(b,{title:"Workers",docsHash:"#docs:dashboard.md:task-queues"}),s.jsxs(C,{children:[s.jsx("input",{type:"text",placeholder:"Search workers...",value:a,onChange:e=>p(e.target.value),className:"input text-2xs py-1 px-2 w-56"}),s.jsx(j,{label:"Queue",value:t.queue,onChange:e=>i("queue",e),options:d.map(e=>({value:e,label:e}))})]}),s.jsx(y,{columns:k,data:f,keyFn:e=>e.name,onRowClick:x,isLoading:m,emptyMessage:"No active workers"})]})}export{z as WorkersPage};
2
+ //# sourceMappingURL=index-BFASQ7_X.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-C3VTJcrp.js","sources":["../../src/pages/workflows/workers/WorkersPage.tsx"],"sourcesContent":["import { SEARCH_DEBOUNCE_MS } from '../../../lib/realtime-refresh';\nimport { useState, useEffect, useMemo } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { Plus, Eye, ShieldCheck } from 'lucide-react';\nimport { useActiveWorkers } from '../../../api/workflows';\nimport { DataTable, type Column } from '../../../components/common/data/DataTable';\nimport { FilterBar, FilterSelect } from '../../../components/common/data/FilterBar';\nimport { RowAction, RowActionGroup } from '../../../components/common/layout/RowActions';\nimport { useFilterParams } from '../../../hooks/useFilterParams';\nimport type { ActiveWorker } from '../../../api/types';\nimport { PageHeader } from '../../../components/common/layout/PageHeader';\nimport { TaskQueuePill } from '../../../components/common/display/TaskQueuePill';\nimport { WorkflowPill } from '../../../components/common/display/WorkflowPill';\n\n// ── Page ──────────────────────────────────────────────────────────────────────\n\nexport function WorkersPage() {\n const navigate = useNavigate();\n const { data, isLoading } = useActiveWorkers();\n const { filters, setFilter } = useFilterParams({\n filters: { search: '', queue: '' },\n });\n\n const [searchInput, setSearchInput] = useState(filters.search);\n\n useEffect(() => {\n if (searchInput === filters.search) return;\n const timer = setTimeout(() => setFilter('search', searchInput), SEARCH_DEBOUNCE_MS);\n return () => clearTimeout(timer);\n }, [searchInput, setFilter, filters.search]);\n\n const allWorkers = data ?? [];\n\n const queues = useMemo(\n () => [...new Set(allWorkers.map((w) => w.task_queue).filter(Boolean))].sort(),\n [allWorkers],\n );\n\n const workers = useMemo(() => {\n let result = allWorkers;\n if (filters.search) {\n const q = filters.search.toLowerCase();\n result = result.filter((w) => w.name.toLowerCase().includes(q));\n }\n if (filters.queue) result = result.filter((w) => w.task_queue === filters.queue);\n return result;\n }, [allWorkers, filters]);\n\n const columns: Column<ActiveWorker>[] = [\n {\n key: 'name',\n label: 'Workflow',\n render: (row) => <WorkflowPill type={row.name} />,\n },\n {\n key: 'task_queue',\n label: 'Queue',\n render: (row) => <TaskQueuePill queue={row.task_queue} />,\n className: 'whitespace-nowrap',\n },\n {\n key: 'registered',\n label: 'Status',\n render: (row) => row.registered\n ? <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-2xs font-medium bg-accent/10 text-accent\"><ShieldCheck className=\"w-3 h-3\" />Certified</span>\n : <span className=\"inline-flex items-center px-1.5 py-0.5 rounded text-2xs font-medium bg-surface-sunken text-text-tertiary\">Durable</span>,\n className: 'whitespace-nowrap',\n },\n {\n key: 'actions',\n label: '',\n render: (row) => (\n <RowActionGroup>\n {row.registered ? (\n <RowAction\n icon={Eye}\n title=\"View config\"\n onClick={() => navigate(`/workflows/registry/${encodeURIComponent(row.name)}`)}\n />\n ) : (\n <RowAction\n icon={Plus}\n title=\"Register workflow\"\n onClick={() => navigate(`/workflows/registry/new?workflow_type=${encodeURIComponent(row.name)}&task_queue=${encodeURIComponent(row.task_queue)}`)}\n />\n )}\n </RowActionGroup>\n ),\n className: 'w-16 text-right',\n },\n ];\n\n const handleRowClick = (row: ActiveWorker) => {\n if (row.registered) {\n navigate(`/workflows/registry/${encodeURIComponent(row.name)}`);\n } else {\n navigate(`/workflows/registry/new?workflow_type=${encodeURIComponent(row.name)}&task_queue=${encodeURIComponent(row.task_queue)}`);\n }\n };\n\n return (\n <div>\n <PageHeader title=\"Workers\" docsHash=\"#docs:dashboard.md:task-queues\" />\n\n <FilterBar>\n <input\n type=\"text\"\n placeholder=\"Search workers...\"\n value={searchInput}\n onChange={(e) => setSearchInput(e.target.value)}\n className=\"input text-2xs py-1 px-2 w-56\"\n />\n <FilterSelect\n label=\"Queue\"\n value={filters.queue}\n onChange={(v) => setFilter('queue', v)}\n options={queues.map((q) => ({ value: q, label: q }))}\n />\n </FilterBar>\n\n <DataTable\n columns={columns}\n data={workers}\n keyFn={(row) => row.name}\n onRowClick={handleRowClick}\n isLoading={isLoading}\n emptyMessage=\"No active workers\"\n />\n </div>\n );\n}\n"],"names":["WorkersPage","navigate","useNavigate","data","isLoading","useActiveWorkers","filters","setFilter","useFilterParams","searchInput","setSearchInput","useState","useEffect","timer","SEARCH_DEBOUNCE_MS","allWorkers","queues","useMemo","w","workers","result","q","columns","row","WorkflowPill","TaskQueuePill","jsxs","jsx","ShieldCheck","RowActionGroup","RowAction","Eye","Plus","handleRowClick","PageHeader","FilterBar","FilterSelect","v","DataTable"],"mappings":"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"}
1
+ {"version":3,"file":"index-BFASQ7_X.js","sources":["../../src/pages/workflows/workers/WorkersPage.tsx"],"sourcesContent":["import { SEARCH_DEBOUNCE_MS } from '../../../lib/realtime-refresh';\nimport { useState, useEffect, useMemo } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { Plus, Eye, ShieldCheck } from 'lucide-react';\nimport { useActiveWorkers } from '../../../api/workflows';\nimport { DataTable, type Column } from '../../../components/common/data/DataTable';\nimport { FilterBar, FilterSelect } from '../../../components/common/data/FilterBar';\nimport { RowAction, RowActionGroup } from '../../../components/common/layout/RowActions';\nimport { useFilterParams } from '../../../hooks/useFilterParams';\nimport type { ActiveWorker } from '../../../api/types';\nimport { PageHeader } from '../../../components/common/layout/PageHeader';\nimport { TaskQueuePill } from '../../../components/common/display/TaskQueuePill';\nimport { WorkflowPill } from '../../../components/common/display/WorkflowPill';\n\n// ── Page ──────────────────────────────────────────────────────────────────────\n\nexport function WorkersPage() {\n const navigate = useNavigate();\n const { data, isLoading } = useActiveWorkers();\n const { filters, setFilter } = useFilterParams({\n filters: { search: '', queue: '' },\n });\n\n const [searchInput, setSearchInput] = useState(filters.search);\n\n useEffect(() => {\n if (searchInput === filters.search) return;\n const timer = setTimeout(() => setFilter('search', searchInput), SEARCH_DEBOUNCE_MS);\n return () => clearTimeout(timer);\n }, [searchInput, setFilter, filters.search]);\n\n const allWorkers = data ?? [];\n\n const queues = useMemo(\n () => [...new Set(allWorkers.map((w) => w.task_queue).filter(Boolean))].sort(),\n [allWorkers],\n );\n\n const workers = useMemo(() => {\n let result = allWorkers;\n if (filters.search) {\n const q = filters.search.toLowerCase();\n result = result.filter((w) => w.name.toLowerCase().includes(q));\n }\n if (filters.queue) result = result.filter((w) => w.task_queue === filters.queue);\n return result;\n }, [allWorkers, filters]);\n\n const columns: Column<ActiveWorker>[] = [\n {\n key: 'name',\n label: 'Workflow',\n render: (row) => <WorkflowPill type={row.name} />,\n },\n {\n key: 'task_queue',\n label: 'Queue',\n render: (row) => <TaskQueuePill queue={row.task_queue} />,\n className: 'whitespace-nowrap',\n },\n {\n key: 'registered',\n label: 'Status',\n render: (row) => row.registered\n ? <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-2xs font-medium bg-accent/10 text-accent\"><ShieldCheck className=\"w-3 h-3\" />Certified</span>\n : <span className=\"inline-flex items-center px-1.5 py-0.5 rounded text-2xs font-medium bg-surface-sunken text-text-tertiary\">Durable</span>,\n className: 'whitespace-nowrap',\n },\n {\n key: 'actions',\n label: '',\n render: (row) => (\n <RowActionGroup>\n {row.registered ? (\n <RowAction\n icon={Eye}\n title=\"View config\"\n onClick={() => navigate(`/workflows/registry/${encodeURIComponent(row.name)}`)}\n />\n ) : (\n <RowAction\n icon={Plus}\n title=\"Register workflow\"\n onClick={() => navigate(`/workflows/registry/new?workflow_type=${encodeURIComponent(row.name)}&task_queue=${encodeURIComponent(row.task_queue)}`)}\n />\n )}\n </RowActionGroup>\n ),\n className: 'w-16 text-right',\n },\n ];\n\n const handleRowClick = (row: ActiveWorker) => {\n if (row.registered) {\n navigate(`/workflows/registry/${encodeURIComponent(row.name)}`);\n } else {\n navigate(`/workflows/registry/new?workflow_type=${encodeURIComponent(row.name)}&task_queue=${encodeURIComponent(row.task_queue)}`);\n }\n };\n\n return (\n <div>\n <PageHeader title=\"Workers\" docsHash=\"#docs:dashboard.md:task-queues\" />\n\n <FilterBar>\n <input\n type=\"text\"\n placeholder=\"Search workers...\"\n value={searchInput}\n onChange={(e) => setSearchInput(e.target.value)}\n className=\"input text-2xs py-1 px-2 w-56\"\n />\n <FilterSelect\n label=\"Queue\"\n value={filters.queue}\n onChange={(v) => setFilter('queue', v)}\n options={queues.map((q) => ({ value: q, label: q }))}\n />\n </FilterBar>\n\n <DataTable\n columns={columns}\n data={workers}\n keyFn={(row) => row.name}\n onRowClick={handleRowClick}\n isLoading={isLoading}\n emptyMessage=\"No active workers\"\n />\n </div>\n );\n}\n"],"names":["WorkersPage","navigate","useNavigate","data","isLoading","useActiveWorkers","filters","setFilter","useFilterParams","searchInput","setSearchInput","useState","useEffect","timer","SEARCH_DEBOUNCE_MS","allWorkers","queues","useMemo","w","workers","result","q","columns","row","WorkflowPill","TaskQueuePill","jsxs","jsx","ShieldCheck","RowActionGroup","RowAction","Eye","Plus","handleRowClick","PageHeader","FilterBar","FilterSelect","v","DataTable"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{a as d,j as e}from"./vendor-query-DvWWuNIB.js";import{aJ as le,M as A,aK as re,Y as G,g as V,aL as ie,aM as ce,aN as oe,aO as de,O as q,aP as xe,aw as me}from"./index-BUYokcrl.js";import{u as J}from"./useFilterParams-DBRw1Hcv.js";import{D as H}from"./DataTable-spX1dFyb.js";import{S as Y}from"./StickyPagination-DsdtYoXR.js";import{F as W,a as Q,b as X}from"./FilterBar-D-6xVHIw.js";import{C as I}from"./ConfirmDeleteModal-Beq1vQtY.js";import{R as Z,a as R}from"./RowActions-Bdd7z4eB.js";import{P as ee}from"./PageHeader-CMd3f4bz.js";import{R as E}from"./RolePill-Di2CAHuD.js";import{u as ue,a as pe,b as he,c as je,d as fe,e as ve,f as ge,g as ye,h as be}from"./bots-DRoAdLek.js";import{T as Ne}from"./TimeAgo-C-rd9F9g.js";import{ab as we,ac as ke,aL as Se,z as F,g as Ce,aa as te,at as Pe,D as se,U as _e,f as Re}from"./vendor-icons-CeVtUKyP.js";import{u as Ae,a as Ee,b as Ue,c as Be}from"./personas-jT1O_SB4.js";import{S as De}from"./ScopeBadge-CSItPVOH.js";import{L as Ke,f as Te}from"./vendor-react-_9U4mKFr.js";import{S as Ie}from"./SegmentedTabs-BpJh4Hwn.js";import"./EmptyState-DgC_6njU.js";import"./useContainerWidth-DSLp1gEm.js";function Fe({open:a,onClose:r}){const t=le(),[n,i]=d.useState({external_id:"",email:"",display_name:"",password:""}),[m,f]=d.useState(a);a!==m&&(f(a),a&&i({external_id:"",email:"",display_name:"",password:""}));const h=()=>{n.external_id.trim()&&t.mutate({external_id:n.external_id.trim(),email:n.email.trim()||void 0,display_name:n.display_name.trim()||void 0,password:n.password||void 0},{onSuccess:r})},u=(s,j)=>i(p=>({...p,[s]:j}));return e.jsx(A,{open:a,onClose:r,title:"Create User",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"External ID (required)"}),e.jsx("input",{type:"text",value:n.external_id,onChange:s=>u("external_id",s.target.value),placeholder:"e.g., john.doe",className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Display Name"}),e.jsx("input",{type:"text",value:n.display_name,onChange:s=>u("display_name",s.target.value),placeholder:"John Doe",className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Email"}),e.jsx("input",{type:"text",value:n.email,onChange:s=>u("email",s.target.value),placeholder:"john@example.com",className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Password"}),e.jsx("input",{type:"password",value:n.password,onChange:s=>u("password",s.target.value),placeholder:"Leave blank for no password",className:"input text-xs w-full"})]}),t.error&&e.jsx("p",{className:"text-xs text-status-error",children:t.error.message}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:r,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:h,disabled:!n.external_id.trim()||t.isPending,className:"btn-primary text-xs",children:t.isPending?"Creating...":"Create"})]})]})})}function Me({open:a,onClose:r,user:t}){const n=re(),[i,m]=d.useState({display_name:"",email:"",status:"active"}),[f,h]=d.useState(t);t!==f&&(h(t),t&&m({display_name:t.display_name??"",email:t.email??"",status:t.status}));const u=()=>{t&&n.mutate({id:t.id,display_name:i.display_name.trim()||void 0,email:i.email.trim()||void 0,status:i.status},{onSuccess:r})};return e.jsx(A,{open:a,onClose:r,title:`Edit — ${(t==null?void 0:t.display_name)||(t==null?void 0:t.external_id)||""}`,children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Display Name"}),e.jsx("input",{type:"text",value:i.display_name,onChange:s=>m(j=>({...j,display_name:s.target.value})),className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Email"}),e.jsx("input",{type:"text",value:i.email,onChange:s=>m(j=>({...j,email:s.target.value})),className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Status"}),e.jsxs("select",{value:i.status,onChange:s=>m(j=>({...j,status:s.target.value})),className:"select text-xs w-full",children:[e.jsx("option",{value:"active",children:"Active"}),e.jsx("option",{value:"inactive",children:"Inactive"}),e.jsx("option",{value:"suspended",children:"Suspended"})]})]}),n.error&&e.jsx("p",{className:"text-xs text-status-error",children:n.error.message}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:r,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:u,disabled:n.isPending,className:"btn-primary text-xs",children:n.isPending?"Saving...":"Save"})]})]})})}function Oe({open:a,onClose:r}){const t=ue(),[n,i]=d.useState({name:"",display_name:"",description:""}),[m,f]=d.useState(a);a!==m&&(f(a),a&&i({name:"",display_name:"",description:""}));const h=()=>{n.name.trim()&&t.mutate({name:n.name.trim(),display_name:n.display_name.trim()||void 0,description:n.description.trim()||void 0},{onSuccess:r})},u=(s,j)=>i(p=>({...p,[s]:j}));return e.jsx(A,{open:a,onClose:r,title:"Create Service Account",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Name (required)"}),e.jsx("input",{type:"text",value:n.name,onChange:s=>u("name",s.target.value.replace(/\s+/g,"-").toLowerCase()),placeholder:"e.g., ci-bot",className:"input text-xs w-full font-mono"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Display Name"}),e.jsx("input",{type:"text",value:n.display_name,onChange:s=>u("display_name",s.target.value),placeholder:"CI Bot",className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Description"}),e.jsx("input",{type:"text",value:n.description,onChange:s=>u("description",s.target.value),placeholder:"Runs scheduled workflows",className:"input text-xs w-full"})]}),t.error&&e.jsx("p",{className:"text-xs text-status-error",children:t.error.message}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:r,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:h,disabled:!n.name.trim()||t.isPending,className:"btn-primary text-xs",children:t.isPending?"Creating...":"Create"})]})]})})}function $e({open:a,onClose:r,bot:t}){const n=pe(),[i,m]=d.useState({display_name:"",description:"",status:"active"}),[f,h]=d.useState(t);t!==f&&(h(t),t&&m({display_name:t.display_name??"",description:t.description??"",status:t.status}));const u=()=>{t&&n.mutate({id:t.id,display_name:i.display_name.trim()||void 0,description:i.description.trim()||void 0,status:i.status},{onSuccess:r})};return e.jsx(A,{open:a,onClose:r,title:`Edit — ${(t==null?void 0:t.display_name)||(t==null?void 0:t.external_id)||""}`,children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Display Name"}),e.jsx("input",{type:"text",value:i.display_name,onChange:s=>m(j=>({...j,display_name:s.target.value})),className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Description"}),e.jsx("input",{type:"text",value:i.description,onChange:s=>m(j=>({...j,description:s.target.value})),className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Status"}),e.jsxs("select",{value:i.status,onChange:s=>m(j=>({...j,status:s.target.value})),className:"select text-xs w-full",children:[e.jsx("option",{value:"active",children:"Active"}),e.jsx("option",{value:"inactive",children:"Inactive"}),e.jsx("option",{value:"suspended",children:"Suspended"})]})]}),n.error&&e.jsx("p",{className:"text-xs text-status-error",children:n.error.message}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:r,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:u,disabled:n.isPending,className:"btn-primary text-xs",children:n.isPending?"Saving...":"Save"})]})]})})}function ze({botId:a}){const{data:r}=he(a),t=je(),n=fe(),[i,m]=d.useState(""),[f,h]=d.useState("read"),[u,s]=d.useState(null),[j,p]=d.useState(!1),[v,x]=d.useState(null),y=(r==null?void 0:r.keys)??[],o={read:{label:"Read only",scopes:["mcp:read"],hint:"Discovery and monitoring — read-safe tools only"},full:{label:"Full access",scopes:["mcp:read","mcp:full"],hint:"All tools — can modify state"}},b=()=>{i.trim()&&t.mutate({botId:a,name:i.trim(),scopes:o[f].scopes},{onSuccess:g=>{s(g.rawKey),m("")}})},N=()=>{u&&(navigator.clipboard.writeText(u),p(!0),setTimeout(()=>p(!1),2e3))},k=()=>{v&&n.mutate({botId:a,keyId:v.id},{onSuccess:()=>x(null)})};return e.jsxs("div",{children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-3",children:"API Keys"}),u&&e.jsxs("div",{className:"mb-3 p-3 bg-status-success/10 border border-status-success/30 rounded-md",children:[e.jsx("p",{className:"text-2xs font-semibold text-status-success mb-1",children:"Key generated — copy now, it won't be shown again"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("code",{className:"text-2xs font-mono text-text-primary bg-surface-sunken px-2 py-1 rounded flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap",children:u}),e.jsx("button",{onClick:N,className:"text-text-tertiary hover:text-text-primary shrink-0",title:"Copy to clipboard",children:j?e.jsx(we,{className:"w-3.5 h-3.5 text-status-success"}):e.jsx(ke,{className:"w-3.5 h-3.5"})})]})]}),y.length===0?e.jsx("p",{className:"text-xs text-text-tertiary mb-3",children:"No API keys."}):e.jsx("div",{className:"space-y-1.5 mb-3",children:y.map(g=>e.jsxs("div",{className:"group/key flex items-center justify-between px-2.5 py-1.5 bg-surface-sunken rounded text-xs",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx(Se,{className:"w-3 h-3 text-text-tertiary"}),e.jsx("span",{className:"text-text-primary font-mono",children:g.name}),(g.scopes??[]).map(l=>e.jsx("span",{className:`px-1.5 py-0.5 rounded text-2xs font-mono ${l.includes("full")?"bg-status-warning/15 text-status-warning":"bg-accent/10 text-accent"}`,children:l},l)),g.last_used_at&&e.jsxs("span",{className:"text-2xs text-text-tertiary",children:["used ",e.jsx(Ne,{date:g.last_used_at})]})]}),e.jsx("button",{onClick:()=>x(g),className:"opacity-0 group-hover/key:opacity-100 transition-opacity text-text-tertiary hover:text-status-error",title:"Revoke key",children:e.jsx(F,{className:"w-3 h-3"})})]},g.id))}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("input",{type:"text",value:i,onChange:g=>m(g.target.value),placeholder:"Key name...",className:"input text-xs font-mono"}),e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("div",{className:"flex rounded-md border border-surface-border overflow-hidden shrink-0",children:Object.entries(o).map(([g,l])=>e.jsx("button",{type:"button",onClick:()=>h(g),title:l.hint,className:`px-2.5 py-1 text-2xs font-medium transition-colors ${f===g?"bg-accent text-text-inverse":"bg-surface text-text-secondary hover:bg-surface-hover"}`,children:l.label},g))}),e.jsxs("button",{onClick:b,disabled:!i.trim()||t.isPending,className:"btn-primary text-xs inline-flex items-center gap-1 shrink-0",children:[e.jsx(Ce,{className:"w-3 h-3"}),t.isPending?"...":"Generate"]})]})]}),t.error&&e.jsx("p",{className:"text-2xs text-status-error mt-1",children:t.error.message}),e.jsx(I,{open:!!v,onClose:()=>x(null),onConfirm:k,title:"Revoke API Key",description:e.jsxs(e.Fragment,{children:["Revoke API key"," ",e.jsx("span",{className:"font-medium text-text-primary font-mono",children:v==null?void 0:v.name}),"? This bot will no longer be able to authenticate with this key."]}),isPending:n.isPending,error:n.error})]})}function Le({bot:a}){const{data:r}=G(),t=ve(),n=ge(),[i,m]=d.useState(""),[f,h]=d.useState("member"),u=(r==null?void 0:r.roles)??[],s=a.roles??[],j=d.useMemo(()=>{const x=new Set(s.map(y=>y.role));return u.filter(y=>!x.has(y))},[u,s]),p=()=>{i.trim()&&t.mutate({botId:a.id,role:i.trim(),type:f},{onSuccess:()=>{m(""),h("member")}})},v=x=>{n.mutate({botId:a.id,role:x})};return e.jsxs("div",{children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-3",children:"Roles"}),s.length===0?e.jsx("p",{className:"text-xs text-text-tertiary mb-3",children:"No roles assigned."}):e.jsx("div",{className:"flex flex-wrap gap-2 mb-3",children:s.map(x=>e.jsxs("span",{className:"inline-flex items-center gap-1.5 px-2.5 py-1 text-xs bg-surface-sunken rounded-full text-text-secondary",children:[e.jsx(E,{role:x.role}),e.jsx("span",{className:"text-2xs text-text-tertiary",children:x.type}),e.jsx("button",{onClick:()=>v(x.role),className:"text-text-tertiary hover:text-status-error transition-colors ml-0.5",title:`Remove ${x.role}`,children:"×"})]},x.role))}),j.length>0&&e.jsxs("div",{className:"space-y-2",children:[e.jsxs("select",{value:i,onChange:x=>m(x.target.value),className:"select text-xs font-mono w-full min-w-0","aria-label":"Role",children:[e.jsx("option",{value:"",children:"Select a role..."}),j.map(x=>e.jsx("option",{value:x,children:x},x))]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 items-end",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("label",{className:"block text-2xs text-text-tertiary mb-1",children:"Type"}),e.jsxs("select",{value:f,onChange:x=>h(x.target.value),className:"select text-xs w-full min-w-0","aria-label":"Role type",children:[e.jsx("option",{value:"member",children:"member"}),e.jsx("option",{value:"admin",children:"admin"}),e.jsx("option",{value:"superadmin",children:"superadmin"})]})]}),e.jsx("div",{className:"flex justify-end",children:e.jsx("button",{onClick:p,disabled:!i||t.isPending,className:"btn-primary text-xs",children:t.isPending?"...":"Add Role"})})]})]}),t.error&&e.jsx("p",{className:"text-2xs text-status-error mt-1",children:t.error.message})]})}function Ge({bot:a}){return a?e.jsxs("div",{className:"border-l border-surface-border pl-6 pt-4 min-h-[300px] space-y-6",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm text-text-primary",children:a.display_name||a.external_id}),a.description&&e.jsx("p",{className:"text-xs text-text-tertiary mt-0.5",children:a.description})]}),e.jsx(ze,{botId:a.id}),e.jsx(Le,{bot:a})]}):e.jsx("div",{className:"border-l border-surface-border pl-6 pt-4 min-h-[300px]",children:e.jsx("p",{className:"text-xs text-text-tertiary",children:"Select a service account to manage its API keys and roles."})})}const Ve={active:"bg-status-success",inactive:"bg-text-tertiary",suspended:"bg-status-error"},qe=[{value:"active",label:"Active"},{value:"inactive",label:"Inactive"},{value:"suspended",label:"Suspended"}];function Je({embedded:a=!1}){const{filters:r,setFilter:t,pagination:n}=J({filters:{status:"",search:""}}),i=ye(),[m,f]=d.useState(!1),[h,u]=d.useState(null),[s,j]=d.useState(null),[p,v]=d.useState(null),{data:x,isLoading:y}=be({status:r.status||void 0,search:r.search||void 0,limit:n.pageSize,offset:n.offset}),o=(x==null?void 0:x.total)??0,b=(x==null?void 0:x.bots)??[],N=d.useMemo(()=>s?b.find(l=>l.id===s.id)??s:null,[b,s]),k=[{key:"display_name",label:"Service Account",render:l=>e.jsxs("div",{className:"flex items-center gap-2.5",children:[e.jsx("span",{className:`w-2.5 h-2.5 rounded-full dot-ring shrink-0 ${Ve[l.status]??"bg-status-pending"}`,title:l.status}),e.jsx("span",{className:"text-sm text-text-primary whitespace-nowrap",children:l.display_name||l.external_id})]})},{key:"description",label:"Description",render:l=>e.jsx("span",{className:"block max-w-[32rem] truncate text-xs text-text-tertiary",title:l.description??void 0,children:l.description??""})},{key:"roles",label:"Roles",render:l=>e.jsx("div",{className:"flex gap-1 flex-wrap",children:(l.roles??[]).map(S=>e.jsx(E,{role:S.role},S.role))})},{key:"created_at",label:"Created",render:l=>e.jsx(V,{date:l.created_at}),className:"w-36 whitespace-nowrap"},{key:"actions",label:"",render:l=>e.jsxs(Z,{children:[e.jsx(R,{icon:te,title:"Edit service account",onClick:()=>u(l)}),e.jsx(R,{icon:F,title:"Delete service account",onClick:()=>v(l),colorClass:"text-text-tertiary hover:text-status-error"})]}),className:"w-16 text-right"}],g=()=>{p&&i.mutate(p.id,{onSuccess:()=>{v(null),(s==null?void 0:s.id)===p.id&&j(null)}})};return e.jsxs("div",{children:[a?e.jsx("div",{className:"flex justify-end mb-4",children:e.jsx("button",{onClick:()=>f(!0),className:"btn-primary text-xs",children:"Add Service Account"})}):e.jsx(ee,{title:"Service Accounts",actions:e.jsx("button",{onClick:()=>f(!0),className:"btn-primary text-xs",children:"Add Service Account"})}),e.jsxs(W,{children:[e.jsx(Q,{label:"Search",value:r.search,onChange:l=>t("search",l),placeholder:"name, id, description…"}),e.jsx(X,{label:"Status",value:r.status,onChange:l=>t("status",l),options:qe})]}),e.jsxs("div",{className:"grid grid-cols-1 @split:grid-cols-[1fr_360px] gap-6 items-start",children:[e.jsxs("div",{className:"overflow-x-clip",children:[e.jsx(H,{columns:k,data:b,keyFn:l=>l.id,isLoading:y,emptyMessage:"No service accounts yet",onRowClick:l=>j(l),activeRowKey:(N==null?void 0:N.id)??null}),e.jsx(Y,{page:n.page,totalPages:n.totalPages(o),onPageChange:n.setPage,total:o,pageSize:n.pageSize,onPageSizeChange:n.setPageSize})]}),e.jsx("div",{className:"sticky top-4",children:e.jsx(Ge,{bot:N})})]}),e.jsx(Oe,{open:m,onClose:()=>f(!1)}),e.jsx($e,{open:!!h,onClose:()=>u(null),bot:h}),e.jsx(I,{open:!!p,onClose:()=>v(null),onConfirm:g,title:"Delete Service Account",description:e.jsxs(e.Fragment,{children:["Delete"," ",e.jsx("span",{className:"font-medium text-text-primary",children:(p==null?void 0:p.display_name)||(p==null?void 0:p.external_id)}),"? This will also revoke all API keys. This action cannot be undone."]}),isPending:i.isPending,error:i.error})]})}function He({value:a,systemKeys:r=[],pending:t=!1,error:n,onPatch:i}){const m=Object.entries(a??{}),f=new Set(r),[h,u]=d.useState(null),[s,j]=d.useState(""),[p,v]=d.useState(""),[x,y]=d.useState(null),[o,b]=d.useState(null),[N,k]=d.useState(""),[g,l]=d.useState(""),[S,C]=d.useState(null),P=c=>typeof c=="string"?c:JSON.stringify(c),O=c=>{const w=c.trim();try{return JSON.parse(w)}catch{return w}};function $(c){if(f.has(c)&&o!==c){b(c);return}b(null),u(c),j(c),v(P((a??{})[c])),y(null),C(null)}function ae(){if(h===null)return;const c=s.trim();if(!c){C("Property name is required");return}if(c!==h&&m.some(([B])=>B===c)){C(`"${c}" already exists`);return}const w={};c!==h&&(w.rename={[h]:c});const _=O(p);if((P(_)!==P((a??{})[h])||c!==h)&&P(_)!==P((a??{})[h])&&(w.set={[c]:_}),!w.set&&!w.rename){U();return}i(w),U()}function U(){u(null),j(""),v(""),C(null)}function z(){const c=N.trim();if(!c){C("Property name is required");return}if(m.some(([w])=>w===c)){C(`"${c}" already exists`);return}i({set:{[c]:O(g)}}),k(""),l(""),C(null)}return e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary",children:"Properties"}),m.length===0&&e.jsx("p",{className:"text-xs text-text-tertiary italic",children:"No properties — add one below."}),m.map(([c,w])=>{const _=f.has(c),B=h===c,ne=x===c;return e.jsx("div",{className:"group text-xs",children:B?e.jsxs("div",{className:"space-y-1.5 border-l-2 border-l-accent pl-2",children:[e.jsx("input",{value:s,onChange:D=>j(D.target.value),"aria-label":"Property name",className:"input text-xs w-full min-w-0 font-mono"}),e.jsx("input",{value:p,onChange:D=>v(D.target.value),"aria-label":"Property value",placeholder:"value (string or JSON)",className:"input text-xs w-full min-w-0"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("button",{onClick:ae,disabled:t,className:"text-2xs font-medium text-accent hover:text-accent-hover",children:t?"Saving...":"Save"}),e.jsx("button",{onClick:U,className:"text-2xs text-text-tertiary hover:text-text-secondary",children:"Cancel"}),e.jsx("button",{onClick:()=>{y(c),u(null)},className:"text-2xs text-status-error/50 hover:text-status-error ml-auto",children:"Remove"})]})]}):ne?e.jsxs("span",{className:"flex items-center gap-2 text-2xs",children:[e.jsxs("span",{className:"text-status-error",children:["Remove ",e.jsx("span",{className:"font-medium font-mono",children:c}),"?"]}),e.jsx("button",{onClick:()=>{i({remove:[c]}),y(null)},disabled:t,className:"font-medium text-status-error hover:text-status-error/80",children:t?"...":"Yes"}),e.jsx("button",{onClick:()=>y(null),className:"text-text-tertiary hover:text-text-secondary",children:"No"})]}):o===c?e.jsxs("span",{className:"flex items-center gap-2 text-2xs",children:[e.jsxs("span",{className:"text-text-secondary",children:[e.jsx("span",{className:"font-mono font-medium",children:c})," is a system property — the platform resolves identities with it. Edit?"]}),e.jsx("button",{onClick:()=>$(c),className:"font-medium text-accent hover:text-accent-hover",children:"Edit"}),e.jsx("button",{onClick:()=>b(null),className:"text-text-tertiary hover:text-text-secondary",children:"Cancel"})]}):e.jsxs("button",{onClick:()=>$(c),className:"flex items-center gap-2 w-full min-w-0 text-left rounded px-1 py-0.5 -mx-1 hover:bg-surface-hover transition-colors",title:`Edit ${c}`,children:[e.jsx("span",{className:"font-mono font-medium text-text-secondary shrink-0",children:c}),_&&e.jsx("span",{className:"shrink-0 text-accent/80",title:"system",children:e.jsx(Pe,{className:"w-3 h-3","aria-label":"system"})}),e.jsx("span",{className:"flex-1 min-w-0 truncate text-right text-text-primary tabular-nums",children:P(w)})]})},c)}),e.jsxs("div",{className:"pt-1.5 border-t border-surface-border space-y-1.5",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsx("input",{value:N,onChange:c=>k(c.target.value),placeholder:"property","aria-label":"New property name",className:"input text-xs w-full min-w-0 font-mono"}),e.jsx("input",{value:g,onChange:c=>l(c.target.value),onKeyDown:c=>{c.key==="Enter"&&z()},placeholder:"value","aria-label":"New property value",className:"input text-xs w-full min-w-0"})]}),N.trim()&&e.jsx("div",{className:"flex justify-end",children:e.jsx("button",{onClick:z,disabled:t,className:"btn-primary text-xs",children:t?"...":"Add Property"})})]}),(S||n)&&e.jsx("p",{role:"alert",className:"text-2xs text-status-error",children:S||n})]})}const T=[{value:"all|all",label:"See all · act on all",read_scope:"all",write_scope:"all"},{value:"all|self",label:"See all · act on self",read_scope:"all",write_scope:"self"},{value:"self|self",label:"See self · act on self",read_scope:"self",write_scope:"self"},{value:"all|none",label:"See all · read-only",read_scope:"all",write_scope:"none"},{value:"self|none",label:"See self · read-only",read_scope:"self",write_scope:"none"}],K="all|all";function L(a){return T.find(r=>r.value===a)??T[0]}function M({children:a}){return e.jsx("div",{className:"border border-surface-border bg-surface-sunken rounded-[var(--lt-radius-section)] p-4",children:a})}function Ye({user:a}){const r=oe(),{data:t}=de();return e.jsx(M,{children:e.jsx(He,{value:a.metadata??{},systemKeys:(t==null?void 0:t.keys)??[],pending:r.isPending,error:r.error?r.error.message:null,onPatch:n=>r.mutate({id:a.id,ops:n})})})}function We({user:a}){const{data:r}=Ae(),{data:t}=Ee(a.id),n=Ue(),i=Be(),[m,f]=d.useState(""),h=(t==null?void 0:t.personas)??[],u=d.useMemo(()=>{const s=new Set(h.map(j=>j.key));return((r==null?void 0:r.personas)??[]).filter(j=>!s.has(j.key))},[r,h]);return h.length===0&&u.length===0?null:e.jsx(M,{children:e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary",children:"Personas"}),h.length>0&&e.jsx("div",{className:"flex flex-col gap-2",children:h.map(s=>e.jsxs("span",{className:"flex items-center gap-2.5 w-full min-w-0 pl-2.5 pr-2 py-1 text-xs bg-surface-sunken rounded-full text-text-secondary",children:[e.jsx(se,{className:"w-3 h-3 shrink-0 text-text-tertiary","aria-hidden":!0}),e.jsx(Ke,{to:`/admin/personas/${encodeURIComponent(s.key)}`,className:"flex-1 min-w-0 truncate transition-colors hover:text-accent",title:s.key,children:s.title||s.key}),e.jsxs("span",{className:"shrink-0 text-2xs text-text-tertiary tabular-nums",children:[s.roles.length," role",s.roles.length===1?"":"s"]}),e.jsx("button",{onClick:()=>i.mutate({userId:a.id,key:s.key}),className:"shrink-0 text-text-tertiary hover:text-status-error transition-colors ml-1",title:`Unassign ${s.title||s.key}`,children:"×"})]},s.key))}),u.length>0&&e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("select",{value:m,onChange:s=>f(s.target.value),className:"select text-xs w-full min-w-0","aria-label":"Persona",children:[e.jsx("option",{value:"",children:"Assign a persona..."}),u.map(s=>e.jsx("option",{value:s.key,children:s.title||s.key},s.key))]}),e.jsx("button",{onClick:()=>{m&&n.mutate({userId:a.id,key:m},{onSuccess:()=>f("")})},disabled:!m||n.isPending,className:"btn-primary text-xs shrink-0",children:n.isPending?"...":"Assign"})]}),(n.error||i.error)&&e.jsx("p",{className:"text-2xs text-status-error",children:(n.error||i.error).message})]})})}function Qe({user:a}){const{data:r}=G(),t=ie(),n=ce(),[i,m]=d.useState(""),[f,h]=d.useState("member"),[u,s]=d.useState(K),j=(r==null?void 0:r.roles)??[],p=(a==null?void 0:a.roles)??[],v=d.useMemo(()=>{const o=new Set(p.map(b=>b.role));return j.filter(b=>!o.has(b))},[j,p]),x=()=>{if(!a||!i.trim())return;const o=L(f==="member"?u:K);t.mutate({userId:a.id,role:i.trim(),type:f,read_scope:o.read_scope,write_scope:o.write_scope},{onSuccess:()=>{m(""),h("member"),s(K)}})},y=o=>{a&&n.mutate({userId:a.id,role:o})};return e.jsxs("div",{className:"border-l border-surface-border pl-6 pt-4 pb-8 min-h-[300px]",children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-4",children:"Role Membership"}),a?e.jsxs("div",{className:"space-y-6",children:[e.jsx("div",{children:e.jsx("p",{className:"text-sm text-text-primary",children:a.display_name||a.external_id})}),e.jsx(We,{user:a}),e.jsx(M,{children:e.jsxs("div",{className:"space-y-4",children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary",children:"Roles"}),p.length===0?e.jsx("p",{className:"text-xs text-text-tertiary",children:"No roles assigned."}):e.jsx("div",{className:"flex flex-col gap-2",children:p.map(o=>e.jsxs("span",{className:"flex items-center gap-2.5 w-full min-w-0 pl-2.5 pr-2 py-1 text-xs bg-surface-sunken rounded-full text-text-secondary",children:[e.jsx("span",{className:"flex-1 min-w-0 truncate",title:o.role,children:e.jsx(E,{role:o.role,tone:"inherit"})}),e.jsx("span",{className:"w-14 shrink-0 text-2xs uppercase tracking-wide text-text-tertiary",children:o.type}),o.type==="member"&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"w-px h-3 bg-surface-border shrink-0","aria-hidden":!0}),e.jsx(De,{read:o.read_scope,write:o.write_scope,className:"shrink-0"})]}),o.granted_by_persona&&e.jsx("span",{className:"shrink-0",title:`Granted by persona ${o.granted_by_persona}`,children:e.jsx(se,{className:"w-3 h-3 text-text-tertiary","aria-hidden":!0})}),e.jsx("button",{onClick:()=>y(o.role),className:"shrink-0 text-text-tertiary hover:text-status-error transition-colors ml-1",title:`Remove ${o.role}`,children:"×"})]},o.role))}),v.length>0&&e.jsxs("div",{className:"pt-3 border-t border-surface-border space-y-2",children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary",children:"Add Role"}),e.jsxs("select",{value:i,onChange:o=>m(o.target.value),className:"select text-xs font-mono w-full min-w-0","aria-label":"Role",children:[e.jsx("option",{value:"",children:"Select a role..."}),v.map(o=>e.jsx("option",{value:o,children:o},o))]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("label",{className:"block text-2xs text-text-tertiary mb-1",children:"Type"}),e.jsxs("select",{value:f,onChange:o=>h(o.target.value),className:"select text-xs w-full min-w-0","aria-label":"Role type",children:[e.jsx("option",{value:"member",children:"member"}),e.jsx("option",{value:"admin",children:"admin"}),e.jsx("option",{value:"superadmin",children:"superadmin"})]})]}),f==="member"&&e.jsxs("div",{className:"min-w-0",children:[e.jsx("label",{className:"block text-2xs text-text-tertiary mb-1",children:"Scope"}),e.jsx("select",{value:u,onChange:o=>s(o.target.value),className:"select text-xs w-full min-w-0","aria-label":"Work-surface scope",children:T.map(o=>e.jsx("option",{value:o.value,children:o.label},o.value))})]})]}),e.jsx("div",{className:"flex justify-end pt-1",children:e.jsx("button",{onClick:x,disabled:!i||t.isPending,className:"btn-primary text-xs",children:t.isPending?"...":"Add Role"})}),t.error&&e.jsx("p",{className:"text-2xs text-status-error",children:t.error.message})]})]})}),e.jsx(Ye,{user:a})]}):e.jsx("p",{className:"text-xs text-text-tertiary",children:"Select a user to manage their roles."})]})}function Xe({active:a,onChange:r}){return e.jsx(Ie,{"aria-label":"Account kind",active:a,onChange:r,tabs:[{key:"users",label:"User Accounts",icon:e.jsx(_e,{className:"w-3.5 h-3.5"})},{key:"service-accounts",label:"Service Accounts",icon:e.jsx(Re,{className:"w-3.5 h-3.5"})}]})}const Ze=[{value:"active",label:"Active"},{value:"inactive",label:"Inactive"},{value:"suspended",label:"Suspended"}],et={active:"bg-status-success",inactive:"bg-text-tertiary",suspended:"bg-status-error"};function bt(){const{isBuilder:a}=q(),[r,t]=Te(),n=r.get("tab"),i=a&&n==="service-accounts"?"service-accounts":"users",m=f=>{t(f==="users"?{}:{tab:f})};return e.jsxs("div",{children:[e.jsx(ee,{title:"Accounts",docsHash:"#docs:dashboard.md:accounts",actions:a?e.jsx(Xe,{active:i,onChange:m}):void 0}),i==="users"?e.jsx(tt,{}):e.jsx(Je,{embedded:!0})]})}function tt(){const{isBuilder:a}=q(),{filters:r,setFilter:t,pagination:n}=J({filters:{status:"",search:""}}),i=xe(),[m,f]=d.useState(!1),[h,u]=d.useState(null),[s,j]=d.useState(null),[p,v]=d.useState(null),{data:x,isLoading:y}=me({status:r.status||void 0,search:r.search||void 0,limit:n.pageSize,offset:n.offset}),o=(x==null?void 0:x.total)??0,b=(x==null?void 0:x.users)??[],N=d.useMemo(()=>s?b.find(l=>l.id===s.id)??s:null,[b,s]),k=[{key:"display_name",label:"User",render:l=>e.jsxs("div",{className:"flex items-center gap-2.5",children:[e.jsx("span",{className:`w-2.5 h-2.5 rounded-full dot-ring shrink-0 ${et[l.status]??"bg-status-pending"}`,title:l.status}),e.jsx("span",{className:"text-xs text-text-primary whitespace-nowrap",children:l.display_name||l.external_id})]})},{key:"email",label:"Email",render:l=>l.email?e.jsx("span",{className:"text-xs text-text-secondary whitespace-nowrap",children:l.email}):e.jsx("span",{className:"text-xs text-text-quaternary",children:"—"})},{key:"roles",label:"Roles",render:l=>e.jsx("div",{className:"flex gap-2 flex-wrap",children:(l.roles??[]).map(S=>e.jsx(E,{role:S.role,size:"md"},S.role))})},{key:"created_at",label:"Created",render:l=>e.jsx(V,{date:l.created_at}),className:"w-36 whitespace-nowrap"},...a?[{key:"actions",label:"",render:l=>e.jsxs(Z,{children:[e.jsx(R,{icon:te,title:"Edit user",onClick:()=>u(l)}),e.jsx(R,{icon:F,title:"Delete user",onClick:()=>v(l),colorClass:"text-text-tertiary hover:text-status-error"})]}),className:"w-16 text-right"}]:[]],g=()=>{p&&i.mutate(p.id,{onSuccess:()=>v(null)})};return e.jsxs("div",{children:[a&&e.jsx("div",{className:"flex justify-end mb-4",children:e.jsx("button",{onClick:()=>f(!0),className:"btn-primary text-xs",children:"Add User"})}),e.jsxs(W,{children:[e.jsx(Q,{label:"Search",value:r.search,onChange:l=>t("search",l),placeholder:"name, email, id…"}),e.jsx(X,{label:"Status",value:r.status,onChange:l=>t("status",l),options:Ze})]}),e.jsxs("div",{className:"grid grid-cols-1 @split:grid-cols-[1fr_460px] gap-6 items-start",children:[e.jsxs("div",{className:"overflow-x-clip",children:[e.jsx(H,{columns:k,data:b,keyFn:l=>l.id,isLoading:y,emptyMessage:"No users found",onRowClick:l=>j(l),activeRowKey:(N==null?void 0:N.id)??null}),e.jsx(Y,{page:n.page,totalPages:n.totalPages(o),onPageChange:n.setPage,total:o,pageSize:n.pageSize,onPageSizeChange:n.setPageSize})]}),e.jsx("div",{className:"sticky top-4",children:e.jsx(Qe,{user:N})})]}),e.jsx(Fe,{open:m,onClose:()=>f(!1)}),e.jsx(Me,{open:!!h,onClose:()=>u(null),user:h}),e.jsx(I,{open:!!p,onClose:()=>v(null),onConfirm:g,title:"Delete User",description:e.jsxs(e.Fragment,{children:["Delete"," ",e.jsx("span",{className:"font-medium text-text-primary",children:(p==null?void 0:p.display_name)||(p==null?void 0:p.external_id)}),"? This action cannot be undone."]}),isPending:i.isPending,error:i.error})]})}export{bt as UsersPage};
2
- //# sourceMappingURL=index-DH03y-UT.js.map
1
+ import{a as d,j as e}from"./vendor-query-DvWWuNIB.js";import{aK as le,M as A,aL as re,Y as G,g as V,aM as ie,aN as ce,aO as oe,aP as de,O as q,aQ as xe,ax as me}from"./index-LRYC__mE.js";import{u as J}from"./useFilterParams-DBRw1Hcv.js";import{D as H}from"./DataTable-FjFhx0SE.js";import{S as Y}from"./StickyPagination-COrfvkBi.js";import{F as Q,a as W,b as X}from"./FilterBar-BulSsWb2.js";import{C as I}from"./ConfirmDeleteModal-DW4DrPur.js";import{R as Z,a as R}from"./RowActions-Bdd7z4eB.js";import{P as ee}from"./PageHeader-CMd3f4bz.js";import{R as E}from"./RolePill-Di2CAHuD.js";import{u as ue,a as pe,b as he,c as je,d as fe,e as ve,f as ge,g as ye,h as be}from"./bots-CpaYjZTk.js";import{T as Ne}from"./TimeAgo-Dz5TgZZZ.js";import{ab as we,ac as ke,aL as Se,z as F,g as Ce,aa as te,at as Pe,D as se,U as _e,f as Re}from"./vendor-icons-CeVtUKyP.js";import{u as Ae,a as Ee,b as Ue,c as Be}from"./personas-Fy-f7QQd.js";import{S as De}from"./ScopeBadge-CSItPVOH.js";import{L as Ke,f as Te}from"./vendor-react-_9U4mKFr.js";import{S as Ie}from"./SegmentedTabs-BpJh4Hwn.js";import"./EmptyState-DgC_6njU.js";import"./useContainerWidth-DSLp1gEm.js";function Fe({open:a,onClose:r}){const t=le(),[n,i]=d.useState({external_id:"",email:"",display_name:"",password:""}),[m,f]=d.useState(a);a!==m&&(f(a),a&&i({external_id:"",email:"",display_name:"",password:""}));const h=()=>{n.external_id.trim()&&t.mutate({external_id:n.external_id.trim(),email:n.email.trim()||void 0,display_name:n.display_name.trim()||void 0,password:n.password||void 0},{onSuccess:r})},u=(s,j)=>i(p=>({...p,[s]:j}));return e.jsx(A,{open:a,onClose:r,title:"Create User",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"External ID (required)"}),e.jsx("input",{type:"text",value:n.external_id,onChange:s=>u("external_id",s.target.value),placeholder:"e.g., john.doe",className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Display Name"}),e.jsx("input",{type:"text",value:n.display_name,onChange:s=>u("display_name",s.target.value),placeholder:"John Doe",className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Email"}),e.jsx("input",{type:"text",value:n.email,onChange:s=>u("email",s.target.value),placeholder:"john@example.com",className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Password"}),e.jsx("input",{type:"password",value:n.password,onChange:s=>u("password",s.target.value),placeholder:"Leave blank for no password",className:"input text-xs w-full"})]}),t.error&&e.jsx("p",{className:"text-xs text-status-error",children:t.error.message}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:r,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:h,disabled:!n.external_id.trim()||t.isPending,className:"btn-primary text-xs",children:t.isPending?"Creating...":"Create"})]})]})})}function Me({open:a,onClose:r,user:t}){const n=re(),[i,m]=d.useState({display_name:"",email:"",status:"active"}),[f,h]=d.useState(t);t!==f&&(h(t),t&&m({display_name:t.display_name??"",email:t.email??"",status:t.status}));const u=()=>{t&&n.mutate({id:t.id,display_name:i.display_name.trim()||void 0,email:i.email.trim()||void 0,status:i.status},{onSuccess:r})};return e.jsx(A,{open:a,onClose:r,title:`Edit — ${(t==null?void 0:t.display_name)||(t==null?void 0:t.external_id)||""}`,children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Display Name"}),e.jsx("input",{type:"text",value:i.display_name,onChange:s=>m(j=>({...j,display_name:s.target.value})),className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Email"}),e.jsx("input",{type:"text",value:i.email,onChange:s=>m(j=>({...j,email:s.target.value})),className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Status"}),e.jsxs("select",{value:i.status,onChange:s=>m(j=>({...j,status:s.target.value})),className:"select text-xs w-full",children:[e.jsx("option",{value:"active",children:"Active"}),e.jsx("option",{value:"inactive",children:"Inactive"}),e.jsx("option",{value:"suspended",children:"Suspended"})]})]}),n.error&&e.jsx("p",{className:"text-xs text-status-error",children:n.error.message}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:r,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:u,disabled:n.isPending,className:"btn-primary text-xs",children:n.isPending?"Saving...":"Save"})]})]})})}function Oe({open:a,onClose:r}){const t=ue(),[n,i]=d.useState({name:"",display_name:"",description:""}),[m,f]=d.useState(a);a!==m&&(f(a),a&&i({name:"",display_name:"",description:""}));const h=()=>{n.name.trim()&&t.mutate({name:n.name.trim(),display_name:n.display_name.trim()||void 0,description:n.description.trim()||void 0},{onSuccess:r})},u=(s,j)=>i(p=>({...p,[s]:j}));return e.jsx(A,{open:a,onClose:r,title:"Create Service Account",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Name (required)"}),e.jsx("input",{type:"text",value:n.name,onChange:s=>u("name",s.target.value.replace(/\s+/g,"-").toLowerCase()),placeholder:"e.g., ci-bot",className:"input text-xs w-full font-mono"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Display Name"}),e.jsx("input",{type:"text",value:n.display_name,onChange:s=>u("display_name",s.target.value),placeholder:"CI Bot",className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Description"}),e.jsx("input",{type:"text",value:n.description,onChange:s=>u("description",s.target.value),placeholder:"Runs scheduled workflows",className:"input text-xs w-full"})]}),t.error&&e.jsx("p",{className:"text-xs text-status-error",children:t.error.message}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:r,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:h,disabled:!n.name.trim()||t.isPending,className:"btn-primary text-xs",children:t.isPending?"Creating...":"Create"})]})]})})}function $e({open:a,onClose:r,bot:t}){const n=pe(),[i,m]=d.useState({display_name:"",description:"",status:"active"}),[f,h]=d.useState(t);t!==f&&(h(t),t&&m({display_name:t.display_name??"",description:t.description??"",status:t.status}));const u=()=>{t&&n.mutate({id:t.id,display_name:i.display_name.trim()||void 0,description:i.description.trim()||void 0,status:i.status},{onSuccess:r})};return e.jsx(A,{open:a,onClose:r,title:`Edit — ${(t==null?void 0:t.display_name)||(t==null?void 0:t.external_id)||""}`,children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Display Name"}),e.jsx("input",{type:"text",value:i.display_name,onChange:s=>m(j=>({...j,display_name:s.target.value})),className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Description"}),e.jsx("input",{type:"text",value:i.description,onChange:s=>m(j=>({...j,description:s.target.value})),className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Status"}),e.jsxs("select",{value:i.status,onChange:s=>m(j=>({...j,status:s.target.value})),className:"select text-xs w-full",children:[e.jsx("option",{value:"active",children:"Active"}),e.jsx("option",{value:"inactive",children:"Inactive"}),e.jsx("option",{value:"suspended",children:"Suspended"})]})]}),n.error&&e.jsx("p",{className:"text-xs text-status-error",children:n.error.message}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:r,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:u,disabled:n.isPending,className:"btn-primary text-xs",children:n.isPending?"Saving...":"Save"})]})]})})}function ze({botId:a}){const{data:r}=he(a),t=je(),n=fe(),[i,m]=d.useState(""),[f,h]=d.useState("read"),[u,s]=d.useState(null),[j,p]=d.useState(!1),[v,x]=d.useState(null),y=(r==null?void 0:r.keys)??[],o={read:{label:"Read only",scopes:["mcp:read"],hint:"Discovery and monitoring — read-safe tools only"},full:{label:"Full access",scopes:["mcp:read","mcp:full"],hint:"All tools — can modify state"}},b=()=>{i.trim()&&t.mutate({botId:a,name:i.trim(),scopes:o[f].scopes},{onSuccess:g=>{s(g.rawKey),m("")}})},N=()=>{u&&(navigator.clipboard.writeText(u),p(!0),setTimeout(()=>p(!1),2e3))},k=()=>{v&&n.mutate({botId:a,keyId:v.id},{onSuccess:()=>x(null)})};return e.jsxs("div",{children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-3",children:"API Keys"}),u&&e.jsxs("div",{className:"mb-3 p-3 bg-status-success/10 border border-status-success/30 rounded-md",children:[e.jsx("p",{className:"text-2xs font-semibold text-status-success mb-1",children:"Key generated — copy now, it won't be shown again"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("code",{className:"text-2xs font-mono text-text-primary bg-surface-sunken px-2 py-1 rounded flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap",children:u}),e.jsx("button",{onClick:N,className:"text-text-tertiary hover:text-text-primary shrink-0",title:"Copy to clipboard",children:j?e.jsx(we,{className:"w-3.5 h-3.5 text-status-success"}):e.jsx(ke,{className:"w-3.5 h-3.5"})})]})]}),y.length===0?e.jsx("p",{className:"text-xs text-text-tertiary mb-3",children:"No API keys."}):e.jsx("div",{className:"space-y-1.5 mb-3",children:y.map(g=>e.jsxs("div",{className:"group/key flex items-center justify-between px-2.5 py-1.5 bg-surface-sunken rounded text-xs",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx(Se,{className:"w-3 h-3 text-text-tertiary"}),e.jsx("span",{className:"text-text-primary font-mono",children:g.name}),(g.scopes??[]).map(l=>e.jsx("span",{className:`px-1.5 py-0.5 rounded text-2xs font-mono ${l.includes("full")?"bg-status-warning/15 text-status-warning":"bg-accent/10 text-accent"}`,children:l},l)),g.last_used_at&&e.jsxs("span",{className:"text-2xs text-text-tertiary",children:["used ",e.jsx(Ne,{date:g.last_used_at})]})]}),e.jsx("button",{onClick:()=>x(g),className:"opacity-0 group-hover/key:opacity-100 transition-opacity text-text-tertiary hover:text-status-error",title:"Revoke key",children:e.jsx(F,{className:"w-3 h-3"})})]},g.id))}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("input",{type:"text",value:i,onChange:g=>m(g.target.value),placeholder:"Key name...",className:"input text-xs font-mono"}),e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("div",{className:"flex rounded-md border border-surface-border overflow-hidden shrink-0",children:Object.entries(o).map(([g,l])=>e.jsx("button",{type:"button",onClick:()=>h(g),title:l.hint,className:`px-2.5 py-1 text-2xs font-medium transition-colors ${f===g?"bg-accent text-text-inverse":"bg-surface text-text-secondary hover:bg-surface-hover"}`,children:l.label},g))}),e.jsxs("button",{onClick:b,disabled:!i.trim()||t.isPending,className:"btn-primary text-xs inline-flex items-center gap-1 shrink-0",children:[e.jsx(Ce,{className:"w-3 h-3"}),t.isPending?"...":"Generate"]})]})]}),t.error&&e.jsx("p",{className:"text-2xs text-status-error mt-1",children:t.error.message}),e.jsx(I,{open:!!v,onClose:()=>x(null),onConfirm:k,title:"Revoke API Key",description:e.jsxs(e.Fragment,{children:["Revoke API key"," ",e.jsx("span",{className:"font-medium text-text-primary font-mono",children:v==null?void 0:v.name}),"? This bot will no longer be able to authenticate with this key."]}),isPending:n.isPending,error:n.error})]})}function Le({bot:a}){const{data:r}=G(),t=ve(),n=ge(),[i,m]=d.useState(""),[f,h]=d.useState("member"),u=(r==null?void 0:r.roles)??[],s=a.roles??[],j=d.useMemo(()=>{const x=new Set(s.map(y=>y.role));return u.filter(y=>!x.has(y))},[u,s]),p=()=>{i.trim()&&t.mutate({botId:a.id,role:i.trim(),type:f},{onSuccess:()=>{m(""),h("member")}})},v=x=>{n.mutate({botId:a.id,role:x})};return e.jsxs("div",{children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-3",children:"Roles"}),s.length===0?e.jsx("p",{className:"text-xs text-text-tertiary mb-3",children:"No roles assigned."}):e.jsx("div",{className:"flex flex-wrap gap-2 mb-3",children:s.map(x=>e.jsxs("span",{className:"inline-flex items-center gap-1.5 px-2.5 py-1 text-xs bg-surface-sunken rounded-full text-text-secondary",children:[e.jsx(E,{role:x.role}),e.jsx("span",{className:"text-2xs text-text-tertiary",children:x.type}),e.jsx("button",{onClick:()=>v(x.role),className:"text-text-tertiary hover:text-status-error transition-colors ml-0.5",title:`Remove ${x.role}`,children:"×"})]},x.role))}),j.length>0&&e.jsxs("div",{className:"space-y-2",children:[e.jsxs("select",{value:i,onChange:x=>m(x.target.value),className:"select text-xs font-mono w-full min-w-0","aria-label":"Role",children:[e.jsx("option",{value:"",children:"Select a role..."}),j.map(x=>e.jsx("option",{value:x,children:x},x))]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 items-end",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("label",{className:"block text-2xs text-text-tertiary mb-1",children:"Type"}),e.jsxs("select",{value:f,onChange:x=>h(x.target.value),className:"select text-xs w-full min-w-0","aria-label":"Role type",children:[e.jsx("option",{value:"member",children:"member"}),e.jsx("option",{value:"admin",children:"admin"}),e.jsx("option",{value:"superadmin",children:"superadmin"})]})]}),e.jsx("div",{className:"flex justify-end",children:e.jsx("button",{onClick:p,disabled:!i||t.isPending,className:"btn-primary text-xs",children:t.isPending?"...":"Add Role"})})]})]}),t.error&&e.jsx("p",{className:"text-2xs text-status-error mt-1",children:t.error.message})]})}function Ge({bot:a}){return a?e.jsxs("div",{className:"border-l border-surface-border pl-6 pt-4 min-h-[300px] space-y-6",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm text-text-primary",children:a.display_name||a.external_id}),a.description&&e.jsx("p",{className:"text-xs text-text-tertiary mt-0.5",children:a.description})]}),e.jsx(ze,{botId:a.id}),e.jsx(Le,{bot:a})]}):e.jsx("div",{className:"border-l border-surface-border pl-6 pt-4 min-h-[300px]",children:e.jsx("p",{className:"text-xs text-text-tertiary",children:"Select a service account to manage its API keys and roles."})})}const Ve={active:"bg-status-success",inactive:"bg-text-tertiary",suspended:"bg-status-error"},qe=[{value:"active",label:"Active"},{value:"inactive",label:"Inactive"},{value:"suspended",label:"Suspended"}];function Je({embedded:a=!1}){const{filters:r,setFilter:t,pagination:n}=J({filters:{status:"",search:""}}),i=ye(),[m,f]=d.useState(!1),[h,u]=d.useState(null),[s,j]=d.useState(null),[p,v]=d.useState(null),{data:x,isLoading:y}=be({status:r.status||void 0,search:r.search||void 0,limit:n.pageSize,offset:n.offset}),o=(x==null?void 0:x.total)??0,b=(x==null?void 0:x.bots)??[],N=d.useMemo(()=>s?b.find(l=>l.id===s.id)??s:null,[b,s]),k=[{key:"display_name",label:"Service Account",render:l=>e.jsxs("div",{className:"flex items-center gap-2.5",children:[e.jsx("span",{className:`w-2.5 h-2.5 rounded-full dot-ring shrink-0 ${Ve[l.status]??"bg-status-pending"}`,title:l.status}),e.jsx("span",{className:"text-sm text-text-primary whitespace-nowrap",children:l.display_name||l.external_id})]})},{key:"description",label:"Description",render:l=>e.jsx("span",{className:"block max-w-[32rem] truncate text-xs text-text-tertiary",title:l.description??void 0,children:l.description??""})},{key:"roles",label:"Roles",render:l=>e.jsx("div",{className:"flex gap-1 flex-wrap",children:(l.roles??[]).map(S=>e.jsx(E,{role:S.role},S.role))})},{key:"created_at",label:"Created",render:l=>e.jsx(V,{date:l.created_at}),className:"w-36 whitespace-nowrap"},{key:"actions",label:"",render:l=>e.jsxs(Z,{children:[e.jsx(R,{icon:te,title:"Edit service account",onClick:()=>u(l)}),e.jsx(R,{icon:F,title:"Delete service account",onClick:()=>v(l),colorClass:"text-text-tertiary hover:text-status-error"})]}),className:"w-16 text-right"}],g=()=>{p&&i.mutate(p.id,{onSuccess:()=>{v(null),(s==null?void 0:s.id)===p.id&&j(null)}})};return e.jsxs("div",{children:[a?e.jsx("div",{className:"flex justify-end mb-4",children:e.jsx("button",{onClick:()=>f(!0),className:"btn-primary text-xs",children:"Add Service Account"})}):e.jsx(ee,{title:"Service Accounts",actions:e.jsx("button",{onClick:()=>f(!0),className:"btn-primary text-xs",children:"Add Service Account"})}),e.jsxs(Q,{children:[e.jsx(W,{label:"Search",value:r.search,onChange:l=>t("search",l),placeholder:"name, id, description…"}),e.jsx(X,{label:"Status",value:r.status,onChange:l=>t("status",l),options:qe})]}),e.jsxs("div",{className:"grid grid-cols-1 @split:grid-cols-[1fr_360px] gap-6 items-start",children:[e.jsxs("div",{className:"overflow-x-clip",children:[e.jsx(H,{columns:k,data:b,keyFn:l=>l.id,isLoading:y,emptyMessage:"No service accounts yet",onRowClick:l=>j(l),activeRowKey:(N==null?void 0:N.id)??null}),e.jsx(Y,{page:n.page,totalPages:n.totalPages(o),onPageChange:n.setPage,total:o,pageSize:n.pageSize,onPageSizeChange:n.setPageSize})]}),e.jsx("div",{className:"sticky top-4",children:e.jsx(Ge,{bot:N})})]}),e.jsx(Oe,{open:m,onClose:()=>f(!1)}),e.jsx($e,{open:!!h,onClose:()=>u(null),bot:h}),e.jsx(I,{open:!!p,onClose:()=>v(null),onConfirm:g,title:"Delete Service Account",description:e.jsxs(e.Fragment,{children:["Delete"," ",e.jsx("span",{className:"font-medium text-text-primary",children:(p==null?void 0:p.display_name)||(p==null?void 0:p.external_id)}),"? This will also revoke all API keys. This action cannot be undone."]}),isPending:i.isPending,error:i.error})]})}function He({value:a,systemKeys:r=[],pending:t=!1,error:n,onPatch:i}){const m=Object.entries(a??{}),f=new Set(r),[h,u]=d.useState(null),[s,j]=d.useState(""),[p,v]=d.useState(""),[x,y]=d.useState(null),[o,b]=d.useState(null),[N,k]=d.useState(""),[g,l]=d.useState(""),[S,C]=d.useState(null),P=c=>typeof c=="string"?c:JSON.stringify(c),O=c=>{const w=c.trim();try{return JSON.parse(w)}catch{return w}};function $(c){if(f.has(c)&&o!==c){b(c);return}b(null),u(c),j(c),v(P((a??{})[c])),y(null),C(null)}function ae(){if(h===null)return;const c=s.trim();if(!c){C("Property name is required");return}if(c!==h&&m.some(([B])=>B===c)){C(`"${c}" already exists`);return}const w={};c!==h&&(w.rename={[h]:c});const _=O(p);if((P(_)!==P((a??{})[h])||c!==h)&&P(_)!==P((a??{})[h])&&(w.set={[c]:_}),!w.set&&!w.rename){U();return}i(w),U()}function U(){u(null),j(""),v(""),C(null)}function z(){const c=N.trim();if(!c){C("Property name is required");return}if(m.some(([w])=>w===c)){C(`"${c}" already exists`);return}i({set:{[c]:O(g)}}),k(""),l(""),C(null)}return e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary",children:"Properties"}),m.length===0&&e.jsx("p",{className:"text-xs text-text-tertiary italic",children:"No properties — add one below."}),m.map(([c,w])=>{const _=f.has(c),B=h===c,ne=x===c;return e.jsx("div",{className:"group text-xs",children:B?e.jsxs("div",{className:"space-y-1.5 border-l-2 border-l-accent pl-2",children:[e.jsx("input",{value:s,onChange:D=>j(D.target.value),"aria-label":"Property name",className:"input text-xs w-full min-w-0 font-mono"}),e.jsx("input",{value:p,onChange:D=>v(D.target.value),"aria-label":"Property value",placeholder:"value (string or JSON)",className:"input text-xs w-full min-w-0"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("button",{onClick:ae,disabled:t,className:"text-2xs font-medium text-accent hover:text-accent-hover",children:t?"Saving...":"Save"}),e.jsx("button",{onClick:U,className:"text-2xs text-text-tertiary hover:text-text-secondary",children:"Cancel"}),e.jsx("button",{onClick:()=>{y(c),u(null)},className:"text-2xs text-status-error/50 hover:text-status-error ml-auto",children:"Remove"})]})]}):ne?e.jsxs("span",{className:"flex items-center gap-2 text-2xs",children:[e.jsxs("span",{className:"text-status-error",children:["Remove ",e.jsx("span",{className:"font-medium font-mono",children:c}),"?"]}),e.jsx("button",{onClick:()=>{i({remove:[c]}),y(null)},disabled:t,className:"font-medium text-status-error hover:text-status-error/80",children:t?"...":"Yes"}),e.jsx("button",{onClick:()=>y(null),className:"text-text-tertiary hover:text-text-secondary",children:"No"})]}):o===c?e.jsxs("span",{className:"flex items-center gap-2 text-2xs",children:[e.jsxs("span",{className:"text-text-secondary",children:[e.jsx("span",{className:"font-mono font-medium",children:c})," is a system property — the platform resolves identities with it. Edit?"]}),e.jsx("button",{onClick:()=>$(c),className:"font-medium text-accent hover:text-accent-hover",children:"Edit"}),e.jsx("button",{onClick:()=>b(null),className:"text-text-tertiary hover:text-text-secondary",children:"Cancel"})]}):e.jsxs("button",{onClick:()=>$(c),className:"flex items-center gap-2 w-full min-w-0 text-left rounded px-1 py-0.5 -mx-1 hover:bg-surface-hover transition-colors",title:`Edit ${c}`,children:[e.jsx("span",{className:"font-mono font-medium text-text-secondary shrink-0",children:c}),_&&e.jsx("span",{className:"shrink-0 text-accent/80",title:"system",children:e.jsx(Pe,{className:"w-3 h-3","aria-label":"system"})}),e.jsx("span",{className:"flex-1 min-w-0 truncate text-right text-text-primary tabular-nums",children:P(w)})]})},c)}),e.jsxs("div",{className:"pt-1.5 border-t border-surface-border space-y-1.5",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsx("input",{value:N,onChange:c=>k(c.target.value),placeholder:"property","aria-label":"New property name",className:"input text-xs w-full min-w-0 font-mono"}),e.jsx("input",{value:g,onChange:c=>l(c.target.value),onKeyDown:c=>{c.key==="Enter"&&z()},placeholder:"value","aria-label":"New property value",className:"input text-xs w-full min-w-0"})]}),N.trim()&&e.jsx("div",{className:"flex justify-end",children:e.jsx("button",{onClick:z,disabled:t,className:"btn-primary text-xs",children:t?"...":"Add Property"})})]}),(S||n)&&e.jsx("p",{role:"alert",className:"text-2xs text-status-error",children:S||n})]})}const T=[{value:"all|all",label:"See all · act on all",read_scope:"all",write_scope:"all"},{value:"all|self",label:"See all · act on self",read_scope:"all",write_scope:"self"},{value:"self|self",label:"See self · act on self",read_scope:"self",write_scope:"self"},{value:"all|none",label:"See all · read-only",read_scope:"all",write_scope:"none"},{value:"self|none",label:"See self · read-only",read_scope:"self",write_scope:"none"}],K="all|all";function L(a){return T.find(r=>r.value===a)??T[0]}function M({children:a}){return e.jsx("div",{className:"border border-surface-border bg-surface-sunken rounded-[var(--lt-radius-section)] p-4",children:a})}function Ye({user:a}){const r=oe(),{data:t}=de();return e.jsx(M,{children:e.jsx(He,{value:a.metadata??{},systemKeys:(t==null?void 0:t.keys)??[],pending:r.isPending,error:r.error?r.error.message:null,onPatch:n=>r.mutate({id:a.id,ops:n})})})}function Qe({user:a}){const{data:r}=Ae(),{data:t}=Ee(a.id),n=Ue(),i=Be(),[m,f]=d.useState(""),h=(t==null?void 0:t.personas)??[],u=d.useMemo(()=>{const s=new Set(h.map(j=>j.key));return((r==null?void 0:r.personas)??[]).filter(j=>!s.has(j.key))},[r,h]);return h.length===0&&u.length===0?null:e.jsx(M,{children:e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary",children:"Personas"}),h.length>0&&e.jsx("div",{className:"flex flex-col gap-2",children:h.map(s=>e.jsxs("span",{className:"flex items-center gap-2.5 w-full min-w-0 pl-2.5 pr-2 py-1 text-xs bg-surface-sunken rounded-full text-text-secondary",children:[e.jsx(se,{className:"w-3 h-3 shrink-0 text-text-tertiary","aria-hidden":!0}),e.jsx(Ke,{to:`/admin/personas/${encodeURIComponent(s.key)}`,className:"flex-1 min-w-0 truncate transition-colors hover:text-accent",title:s.key,children:s.title||s.key}),e.jsxs("span",{className:"shrink-0 text-2xs text-text-tertiary tabular-nums",children:[s.roles.length," role",s.roles.length===1?"":"s"]}),e.jsx("button",{onClick:()=>i.mutate({userId:a.id,key:s.key}),className:"shrink-0 text-text-tertiary hover:text-status-error transition-colors ml-1",title:`Unassign ${s.title||s.key}`,children:"×"})]},s.key))}),u.length>0&&e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("select",{value:m,onChange:s=>f(s.target.value),className:"select text-xs w-full min-w-0","aria-label":"Persona",children:[e.jsx("option",{value:"",children:"Assign a persona..."}),u.map(s=>e.jsx("option",{value:s.key,children:s.title||s.key},s.key))]}),e.jsx("button",{onClick:()=>{m&&n.mutate({userId:a.id,key:m},{onSuccess:()=>f("")})},disabled:!m||n.isPending,className:"btn-primary text-xs shrink-0",children:n.isPending?"...":"Assign"})]}),(n.error||i.error)&&e.jsx("p",{className:"text-2xs text-status-error",children:(n.error||i.error).message})]})})}function We({user:a}){const{data:r}=G(),t=ie(),n=ce(),[i,m]=d.useState(""),[f,h]=d.useState("member"),[u,s]=d.useState(K),j=(r==null?void 0:r.roles)??[],p=(a==null?void 0:a.roles)??[],v=d.useMemo(()=>{const o=new Set(p.map(b=>b.role));return j.filter(b=>!o.has(b))},[j,p]),x=()=>{if(!a||!i.trim())return;const o=L(f==="member"?u:K);t.mutate({userId:a.id,role:i.trim(),type:f,read_scope:o.read_scope,write_scope:o.write_scope},{onSuccess:()=>{m(""),h("member"),s(K)}})},y=o=>{a&&n.mutate({userId:a.id,role:o})};return e.jsxs("div",{className:"border-l border-surface-border pl-6 pt-4 pb-8 min-h-[300px]",children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-4",children:"Role Membership"}),a?e.jsxs("div",{className:"space-y-6",children:[e.jsx("div",{children:e.jsx("p",{className:"text-sm text-text-primary",children:a.display_name||a.external_id})}),e.jsx(Qe,{user:a}),e.jsx(M,{children:e.jsxs("div",{className:"space-y-4",children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary",children:"Roles"}),p.length===0?e.jsx("p",{className:"text-xs text-text-tertiary",children:"No roles assigned."}):e.jsx("div",{className:"flex flex-col gap-2",children:p.map(o=>e.jsxs("span",{className:"flex items-center gap-2.5 w-full min-w-0 pl-2.5 pr-2 py-1 text-xs bg-surface-sunken rounded-full text-text-secondary",children:[e.jsx("span",{className:"flex-1 min-w-0 truncate",title:o.role,children:e.jsx(E,{role:o.role,tone:"inherit"})}),e.jsx("span",{className:"w-14 shrink-0 text-2xs uppercase tracking-wide text-text-tertiary",children:o.type}),o.type==="member"&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"w-px h-3 bg-surface-border shrink-0","aria-hidden":!0}),e.jsx(De,{read:o.read_scope,write:o.write_scope,className:"shrink-0"})]}),o.granted_by_persona&&e.jsx("span",{className:"shrink-0",title:`Granted by persona ${o.granted_by_persona}`,children:e.jsx(se,{className:"w-3 h-3 text-text-tertiary","aria-hidden":!0})}),e.jsx("button",{onClick:()=>y(o.role),className:"shrink-0 text-text-tertiary hover:text-status-error transition-colors ml-1",title:`Remove ${o.role}`,children:"×"})]},o.role))}),v.length>0&&e.jsxs("div",{className:"pt-3 border-t border-surface-border space-y-2",children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary",children:"Add Role"}),e.jsxs("select",{value:i,onChange:o=>m(o.target.value),className:"select text-xs font-mono w-full min-w-0","aria-label":"Role",children:[e.jsx("option",{value:"",children:"Select a role..."}),v.map(o=>e.jsx("option",{value:o,children:o},o))]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("label",{className:"block text-2xs text-text-tertiary mb-1",children:"Type"}),e.jsxs("select",{value:f,onChange:o=>h(o.target.value),className:"select text-xs w-full min-w-0","aria-label":"Role type",children:[e.jsx("option",{value:"member",children:"member"}),e.jsx("option",{value:"admin",children:"admin"}),e.jsx("option",{value:"superadmin",children:"superadmin"})]})]}),f==="member"&&e.jsxs("div",{className:"min-w-0",children:[e.jsx("label",{className:"block text-2xs text-text-tertiary mb-1",children:"Scope"}),e.jsx("select",{value:u,onChange:o=>s(o.target.value),className:"select text-xs w-full min-w-0","aria-label":"Work-surface scope",children:T.map(o=>e.jsx("option",{value:o.value,children:o.label},o.value))})]})]}),e.jsx("div",{className:"flex justify-end pt-1",children:e.jsx("button",{onClick:x,disabled:!i||t.isPending,className:"btn-primary text-xs",children:t.isPending?"...":"Add Role"})}),t.error&&e.jsx("p",{className:"text-2xs text-status-error",children:t.error.message})]})]})}),e.jsx(Ye,{user:a})]}):e.jsx("p",{className:"text-xs text-text-tertiary",children:"Select a user to manage their roles."})]})}function Xe({active:a,onChange:r}){return e.jsx(Ie,{"aria-label":"Account kind",active:a,onChange:r,tabs:[{key:"users",label:"User Accounts",icon:e.jsx(_e,{className:"w-3.5 h-3.5"})},{key:"service-accounts",label:"Service Accounts",icon:e.jsx(Re,{className:"w-3.5 h-3.5"})}]})}const Ze=[{value:"active",label:"Active"},{value:"inactive",label:"Inactive"},{value:"suspended",label:"Suspended"}],et={active:"bg-status-success",inactive:"bg-text-tertiary",suspended:"bg-status-error"};function bt(){const{isBuilder:a}=q(),[r,t]=Te(),n=r.get("tab"),i=a&&n==="service-accounts"?"service-accounts":"users",m=f=>{t(f==="users"?{}:{tab:f})};return e.jsxs("div",{children:[e.jsx(ee,{title:"Accounts",docsHash:"#docs:dashboard.md:accounts",actions:a?e.jsx(Xe,{active:i,onChange:m}):void 0}),i==="users"?e.jsx(tt,{}):e.jsx(Je,{embedded:!0})]})}function tt(){const{isBuilder:a}=q(),{filters:r,setFilter:t,pagination:n}=J({filters:{status:"",search:""}}),i=xe(),[m,f]=d.useState(!1),[h,u]=d.useState(null),[s,j]=d.useState(null),[p,v]=d.useState(null),{data:x,isLoading:y}=me({status:r.status||void 0,search:r.search||void 0,limit:n.pageSize,offset:n.offset}),o=(x==null?void 0:x.total)??0,b=(x==null?void 0:x.users)??[],N=d.useMemo(()=>s?b.find(l=>l.id===s.id)??s:null,[b,s]),k=[{key:"display_name",label:"User",render:l=>e.jsxs("div",{className:"flex items-center gap-2.5",children:[e.jsx("span",{className:`w-2.5 h-2.5 rounded-full dot-ring shrink-0 ${et[l.status]??"bg-status-pending"}`,title:l.status}),e.jsx("span",{className:"text-xs text-text-primary whitespace-nowrap",children:l.display_name||l.external_id})]})},{key:"email",label:"Email",render:l=>l.email?e.jsx("span",{className:"text-xs text-text-secondary whitespace-nowrap",children:l.email}):e.jsx("span",{className:"text-xs text-text-quaternary",children:"—"})},{key:"roles",label:"Roles",render:l=>e.jsx("div",{className:"flex gap-2 flex-wrap",children:(l.roles??[]).map(S=>e.jsx(E,{role:S.role,size:"md"},S.role))})},{key:"created_at",label:"Created",render:l=>e.jsx(V,{date:l.created_at}),className:"w-36 whitespace-nowrap"},...a?[{key:"actions",label:"",render:l=>e.jsxs(Z,{children:[e.jsx(R,{icon:te,title:"Edit user",onClick:()=>u(l)}),e.jsx(R,{icon:F,title:"Delete user",onClick:()=>v(l),colorClass:"text-text-tertiary hover:text-status-error"})]}),className:"w-16 text-right"}]:[]],g=()=>{p&&i.mutate(p.id,{onSuccess:()=>v(null)})};return e.jsxs("div",{children:[a&&e.jsx("div",{className:"flex justify-end mb-4",children:e.jsx("button",{onClick:()=>f(!0),className:"btn-primary text-xs",children:"Add User"})}),e.jsxs(Q,{children:[e.jsx(W,{label:"Search",value:r.search,onChange:l=>t("search",l),placeholder:"name, email, id…"}),e.jsx(X,{label:"Status",value:r.status,onChange:l=>t("status",l),options:Ze})]}),e.jsxs("div",{className:"grid grid-cols-1 @split:grid-cols-[1fr_460px] gap-6 items-start",children:[e.jsxs("div",{className:"overflow-x-clip",children:[e.jsx(H,{columns:k,data:b,keyFn:l=>l.id,isLoading:y,emptyMessage:"No users found",onRowClick:l=>j(l),activeRowKey:(N==null?void 0:N.id)??null}),e.jsx(Y,{page:n.page,totalPages:n.totalPages(o),onPageChange:n.setPage,total:o,pageSize:n.pageSize,onPageSizeChange:n.setPageSize})]}),e.jsx("div",{className:"sticky top-4",children:e.jsx(We,{user:N})})]}),e.jsx(Fe,{open:m,onClose:()=>f(!1)}),e.jsx(Me,{open:!!h,onClose:()=>u(null),user:h}),e.jsx(I,{open:!!p,onClose:()=>v(null),onConfirm:g,title:"Delete User",description:e.jsxs(e.Fragment,{children:["Delete"," ",e.jsx("span",{className:"font-medium text-text-primary",children:(p==null?void 0:p.display_name)||(p==null?void 0:p.external_id)}),"? This action cannot be undone."]}),isPending:i.isPending,error:i.error})]})}export{bt as UsersPage};
2
+ //# sourceMappingURL=index-BT1Ms5Q5.js.map