@hotmeshio/long-tail 0.5.9 → 0.5.11

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 (193) hide show
  1. package/build/api/controlplane.d.ts +1 -0
  2. package/build/api/controlplane.js +1 -0
  3. package/build/api/diagnostics.d.ts +3 -1
  4. package/build/api/diagnostics.js +1 -1
  5. package/build/api/escalations/metadata.js +17 -1
  6. package/build/api/settings.d.ts +3 -2
  7. package/build/api/settings.js +11 -2
  8. package/build/modules/version.d.ts +16 -0
  9. package/build/modules/version.js +34 -0
  10. package/build/routes/controlplane.js +1 -0
  11. package/build/routes/diagnostics.js +18 -10
  12. package/build/services/controlplane/index.js +3 -2
  13. package/build/services/controlplane/stream-messages-sql.d.ts +4 -3
  14. package/build/services/controlplane/stream-messages-sql.js +12 -7
  15. package/build/services/controlplane/types.d.ts +2 -0
  16. package/build/services/diagnostics/index.d.ts +15 -3
  17. package/build/services/diagnostics/index.js +71 -32
  18. package/build/services/diagnostics/patterns.d.ts +13 -3
  19. package/build/services/diagnostics/patterns.js +25 -14
  20. package/build/services/escalation/crud.d.ts +10 -3
  21. package/build/services/escalation/crud.js +6 -1
  22. package/build/services/escalation/sql.d.ts +16 -6
  23. package/build/services/escalation/sql.js +21 -6
  24. package/build/system/mcp-servers/admin/diagnostics.d.ts +9 -3
  25. package/build/system/mcp-servers/admin/diagnostics.js +31 -21
  26. package/build/system/mcp-servers/admin/schemas.d.ts +9 -3
  27. package/build/system/mcp-servers/admin/schemas.js +5 -3
  28. package/build/tsconfig.tsbuildinfo +1 -1
  29. package/build/types/auth.d.ts +1 -1
  30. package/dashboard/dist/assets/{AdminDashboard-0LSslIQ7.js → AdminDashboard-DZpduYdW.js} +2 -2
  31. package/dashboard/dist/assets/{AdminDashboard-0LSslIQ7.js.map → AdminDashboard-DZpduYdW.js.map} +1 -1
  32. package/dashboard/dist/assets/{AgentConfigPage-hqBr1540.js → AgentConfigPage-SFnHMIP6.js} +2 -2
  33. package/dashboard/dist/assets/{AgentConfigPage-hqBr1540.js.map → AgentConfigPage-SFnHMIP6.js.map} +1 -1
  34. package/dashboard/dist/assets/{AgentDetailPage-bnXR1ezD.js → AgentDetailPage-C-2iSaDs.js} +2 -2
  35. package/dashboard/dist/assets/{AgentDetailPage-bnXR1ezD.js.map → AgentDetailPage-C-2iSaDs.js.map} +1 -1
  36. package/dashboard/dist/assets/{AgentsPage-tJIlrnfM.js → AgentsPage-C3FztFd_.js} +2 -2
  37. package/dashboard/dist/assets/{AgentsPage-tJIlrnfM.js.map → AgentsPage-C3FztFd_.js.map} +1 -1
  38. package/dashboard/dist/assets/{AvailableEscalationsPage-B7gEfcw3.js → AvailableEscalationsPage-DIqdBCwe.js} +2 -2
  39. package/dashboard/dist/assets/{AvailableEscalationsPage-B7gEfcw3.js.map → AvailableEscalationsPage-DIqdBCwe.js.map} +1 -1
  40. package/dashboard/dist/assets/{BotPicker-fFE4GAaO.js → BotPicker-Dse2jW4b.js} +2 -2
  41. package/dashboard/dist/assets/{BotPicker-fFE4GAaO.js.map → BotPicker-Dse2jW4b.js.map} +1 -1
  42. package/dashboard/dist/assets/{CapabilitiesPage-DotZ7iQc.js → CapabilitiesPage-DTfKCzBQ.js} +2 -2
  43. package/dashboard/dist/assets/{CapabilitiesPage-DotZ7iQc.js.map → CapabilitiesPage-DTfKCzBQ.js.map} +1 -1
  44. package/dashboard/dist/assets/{CollapsibleSection-D97SYypF.js → CollapsibleSection-8vf38J6K.js} +2 -2
  45. package/dashboard/dist/assets/{CollapsibleSection-D97SYypF.js.map → CollapsibleSection-8vf38J6K.js.map} +1 -1
  46. package/dashboard/dist/assets/{CredentialsPage-C08U6dlv.js → CredentialsPage-7C4M-hrH.js} +2 -2
  47. package/dashboard/dist/assets/{CredentialsPage-C08U6dlv.js.map → CredentialsPage-7C4M-hrH.js.map} +1 -1
  48. package/dashboard/dist/assets/{CronLabel-C2TuCl4h.js → CronLabel-DrGWtaSY.js} +2 -2
  49. package/dashboard/dist/assets/{CronLabel-C2TuCl4h.js.map → CronLabel-DrGWtaSY.js.map} +1 -1
  50. package/dashboard/dist/assets/{CustomDurationPicker-C3zGsESx.js → CustomDurationPicker-Vcmr4LiR.js} +2 -2
  51. package/dashboard/dist/assets/{CustomDurationPicker-C3zGsESx.js.map → CustomDurationPicker-Vcmr4LiR.js.map} +1 -1
  52. package/dashboard/dist/assets/{ElapsedCell-DF4m0cv_.js → ElapsedCell-BNexhR5d.js} +2 -2
  53. package/dashboard/dist/assets/{ElapsedCell-DF4m0cv_.js.map → ElapsedCell-BNexhR5d.js.map} +1 -1
  54. package/dashboard/dist/assets/{EscalationsOverview-blGOYKtJ.js → EscalationsOverview-BI3DEwYP.js} +2 -2
  55. package/dashboard/dist/assets/{EscalationsOverview-blGOYKtJ.js.map → EscalationsOverview-BI3DEwYP.js.map} +1 -1
  56. package/dashboard/dist/assets/EventTable-CwvX_L9t.js +2 -0
  57. package/dashboard/dist/assets/EventTable-CwvX_L9t.js.map +1 -0
  58. package/dashboard/dist/assets/{GraphInvokePage-QVAUHmjI.js → GraphInvokePage-C-3b8WK0.js} +2 -2
  59. package/dashboard/dist/assets/{GraphInvokePage-QVAUHmjI.js.map → GraphInvokePage-C-3b8WK0.js.map} +1 -1
  60. package/dashboard/dist/assets/{HomePage-DvYgvCcO.js → HomePage-BS_-jcHr.js} +2 -2
  61. package/dashboard/dist/assets/{HomePage-DvYgvCcO.js.map → HomePage-BS_-jcHr.js.map} +1 -1
  62. package/dashboard/dist/assets/{ListToolbar-D6tQ3ZG2.js → ListToolbar-BH9rwQVE.js} +2 -2
  63. package/dashboard/dist/assets/{ListToolbar-D6tQ3ZG2.js.map → ListToolbar-BH9rwQVE.js.map} +1 -1
  64. package/dashboard/dist/assets/{McpOverview-BClbGYb8.js → McpOverview-C9iOdE7E.js} +2 -2
  65. package/dashboard/dist/assets/{McpOverview-BClbGYb8.js.map → McpOverview-C9iOdE7E.js.map} +1 -1
  66. package/dashboard/dist/assets/{McpQueryDetailPage-DHjfDRdm.js → McpQueryDetailPage-DMN-yqvJ.js} +3 -3
  67. package/dashboard/dist/assets/{McpQueryDetailPage-DHjfDRdm.js.map → McpQueryDetailPage-DMN-yqvJ.js.map} +1 -1
  68. package/dashboard/dist/assets/{McpQueryPage-qtEuMDrd.js → McpQueryPage-Db1LUKVs.js} +2 -2
  69. package/dashboard/dist/assets/{McpQueryPage-qtEuMDrd.js.map → McpQueryPage-Db1LUKVs.js.map} +1 -1
  70. package/dashboard/dist/assets/McpRunDetailPage-Wb47sRvo.js +2 -0
  71. package/dashboard/dist/assets/{McpRunDetailPage-DRbIZMU2.js.map → McpRunDetailPage-Wb47sRvo.js.map} +1 -1
  72. package/dashboard/dist/assets/{McpRunsPage-CMfwXQ4R.js → McpRunsPage--tgT5uo7.js} +2 -2
  73. package/dashboard/dist/assets/{McpRunsPage-CMfwXQ4R.js.map → McpRunsPage--tgT5uo7.js.map} +1 -1
  74. package/dashboard/dist/assets/{OperatorDashboard-Dq2pfV68.js → OperatorDashboard-BWVUbJkZ.js} +2 -2
  75. package/dashboard/dist/assets/{OperatorDashboard-Dq2pfV68.js.map → OperatorDashboard-BWVUbJkZ.js.map} +1 -1
  76. package/dashboard/dist/assets/{ProcessDetailPage-DjQuNERz.js → ProcessDetailPage-CvPx-h8y.js} +2 -2
  77. package/dashboard/dist/assets/{ProcessDetailPage-DjQuNERz.js.map → ProcessDetailPage-CvPx-h8y.js.map} +1 -1
  78. package/dashboard/dist/assets/{ProcessesListPage-vJimii8-.js → ProcessesListPage-CWiRM_h3.js} +2 -2
  79. package/dashboard/dist/assets/{ProcessesListPage-vJimii8-.js.map → ProcessesListPage-CWiRM_h3.js.map} +1 -1
  80. package/dashboard/dist/assets/{RolesPage-CFCN_mRF.js → RolesPage-W5ZjOHpg.js} +2 -2
  81. package/dashboard/dist/assets/{RolesPage-CFCN_mRF.js.map → RolesPage-W5ZjOHpg.js.map} +1 -1
  82. package/dashboard/dist/assets/{RunAsSelector-sBxAvlRf.js → RunAsSelector-CvxGTNGT.js} +2 -2
  83. package/dashboard/dist/assets/{RunAsSelector-sBxAvlRf.js.map → RunAsSelector-CvxGTNGT.js.map} +1 -1
  84. package/dashboard/dist/assets/StreamMessageDetail-BF0tM0cd.js +2 -0
  85. package/dashboard/dist/assets/StreamMessageDetail-BF0tM0cd.js.map +1 -0
  86. package/dashboard/dist/assets/SwimlaneTimeline-Bv-KHY9s.js +2 -0
  87. package/dashboard/dist/assets/SwimlaneTimeline-Bv-KHY9s.js.map +1 -0
  88. package/dashboard/dist/assets/{TaskDetailPage-CgFN5uWn.js → TaskDetailPage-Bzb_fuLy.js} +2 -2
  89. package/dashboard/dist/assets/{TaskDetailPage-CgFN5uWn.js.map → TaskDetailPage-Bzb_fuLy.js.map} +1 -1
  90. package/dashboard/dist/assets/{TasksListPage-qj25rRZL.js → TasksListPage-CBezWaZL.js} +2 -2
  91. package/dashboard/dist/assets/{TasksListPage-qj25rRZL.js.map → TasksListPage-CBezWaZL.js.map} +1 -1
  92. package/dashboard/dist/assets/{TimeAgo-C7LylVjP.js → TimeAgo-CKHfTzat.js} +2 -2
  93. package/dashboard/dist/assets/{TimeAgo-C7LylVjP.js.map → TimeAgo-CKHfTzat.js.map} +1 -1
  94. package/dashboard/dist/assets/{TimestampCell-CrCtoBlo.js → TimestampCell-Dsje8GH-.js} +2 -2
  95. package/dashboard/dist/assets/{TimestampCell-CrCtoBlo.js.map → TimestampCell-Dsje8GH-.js.map} +1 -1
  96. package/dashboard/dist/assets/{ToolTestPanel-DYGlB-QW.js → ToolTestPanel-3OcG18e5.js} +2 -2
  97. package/dashboard/dist/assets/{ToolTestPanel-DYGlB-QW.js.map → ToolTestPanel-3OcG18e5.js.map} +1 -1
  98. package/dashboard/dist/assets/{TopicDetailPage-DLY6X_R6.js → TopicDetailPage-DCtv91hH.js} +2 -2
  99. package/dashboard/dist/assets/{TopicDetailPage-DLY6X_R6.js.map → TopicDetailPage-DCtv91hH.js.map} +1 -1
  100. package/dashboard/dist/assets/{TopicsPage-C5nOLsLx.js → TopicsPage-DVGSNc_E.js} +2 -2
  101. package/dashboard/dist/assets/{TopicsPage-C5nOLsLx.js.map → TopicsPage-DVGSNc_E.js.map} +1 -1
  102. package/dashboard/dist/assets/{UserName-CgUZyiwm.js → UserName-xHAgkk8M.js} +2 -2
  103. package/dashboard/dist/assets/{UserName-CgUZyiwm.js.map → UserName-xHAgkk8M.js.map} +1 -1
  104. package/dashboard/dist/assets/WorkflowExecutionPage-CWNxsS8a.js +2 -0
  105. package/dashboard/dist/assets/{WorkflowExecutionPage-CDr5CTM2.js.map → WorkflowExecutionPage-CWNxsS8a.js.map} +1 -1
  106. package/dashboard/dist/assets/{WorkflowsDashboard-tCBP0i0Y.js → WorkflowsDashboard-M13lIaw7.js} +2 -2
  107. package/dashboard/dist/assets/{WorkflowsDashboard-tCBP0i0Y.js.map → WorkflowsDashboard-M13lIaw7.js.map} +1 -1
  108. package/dashboard/dist/assets/{WorkflowsOverview-CaMeZwde.js → WorkflowsOverview-e7jWSj_n.js} +2 -2
  109. package/dashboard/dist/assets/{WorkflowsOverview-CaMeZwde.js.map → WorkflowsOverview-e7jWSj_n.js.map} +1 -1
  110. package/dashboard/dist/assets/{YamlWorkflowDetailPage-C3uyCiIX.js → YamlWorkflowDetailPage-CdAeam76.js} +2 -2
  111. package/dashboard/dist/assets/{YamlWorkflowDetailPage-C3uyCiIX.js.map → YamlWorkflowDetailPage-CdAeam76.js.map} +1 -1
  112. package/dashboard/dist/assets/{YamlWorkflowsPage-DRnYgsvA.js → YamlWorkflowsPage-S_gKs2Di.js} +2 -2
  113. package/dashboard/dist/assets/{YamlWorkflowsPage-DRnYgsvA.js.map → YamlWorkflowsPage-S_gKs2Di.js.map} +1 -1
  114. package/dashboard/dist/assets/{agents-HMkTc425.js → agents-JE4aL07D.js} +2 -2
  115. package/dashboard/dist/assets/{agents-HMkTc425.js.map → agents-JE4aL07D.js.map} +1 -1
  116. package/dashboard/dist/assets/{bots-CDe2jXNx.js → bots-cAzKkDtQ.js} +2 -2
  117. package/dashboard/dist/assets/{bots-CDe2jXNx.js.map → bots-cAzKkDtQ.js.map} +1 -1
  118. package/dashboard/dist/assets/{capabilities-DhnM7Ztb.js → capabilities-RBFXLAXF.js} +2 -2
  119. package/dashboard/dist/assets/{capabilities-DhnM7Ztb.js.map → capabilities-RBFXLAXF.js.map} +1 -1
  120. package/dashboard/dist/assets/{controlplane-BwIJ9ZC_.js → controlplane-DGhv3rwI.js} +2 -2
  121. package/dashboard/dist/assets/{controlplane-BwIJ9ZC_.js.map → controlplane-DGhv3rwI.js.map} +1 -1
  122. package/dashboard/dist/assets/{escalation-columns-BKqSywVA.js → escalation-columns-DqTkKbCv.js} +2 -2
  123. package/dashboard/dist/assets/{escalation-columns-BKqSywVA.js.map → escalation-columns-DqTkKbCv.js.map} +1 -1
  124. package/dashboard/dist/assets/{escalation-Djk5XKmX.js → escalation-ne7dIaPa.js} +2 -2
  125. package/dashboard/dist/assets/{escalation-Djk5XKmX.js.map → escalation-ne7dIaPa.js.map} +1 -1
  126. package/dashboard/dist/assets/{index-DRIJM1L-.js → index-BTqhAT6p.js} +2 -2
  127. package/dashboard/dist/assets/{index-DRIJM1L-.js.map → index-BTqhAT6p.js.map} +1 -1
  128. package/dashboard/dist/assets/{index-BW-fIquS.js → index-BbJuC9kg.js} +2 -2
  129. package/dashboard/dist/assets/{index-BW-fIquS.js.map → index-BbJuC9kg.js.map} +1 -1
  130. package/dashboard/dist/assets/{index-mEQ6kCnt.js → index-C2l4GcZ7.js} +2 -2
  131. package/dashboard/dist/assets/{index-mEQ6kCnt.js.map → index-C2l4GcZ7.js.map} +1 -1
  132. package/dashboard/dist/assets/{index-BYpWOUEe.js → index-CByjpYlU.js} +2 -2
  133. package/dashboard/dist/assets/{index-BYpWOUEe.js.map → index-CByjpYlU.js.map} +1 -1
  134. package/dashboard/dist/assets/{index-rUST2YsO.js → index-CEpw_Fh8.js} +2 -2
  135. package/dashboard/dist/assets/{index-rUST2YsO.js.map → index-CEpw_Fh8.js.map} +1 -1
  136. package/dashboard/dist/assets/{index-CPIYW81T.js → index-CQDn-bLr.js} +2 -2
  137. package/dashboard/dist/assets/{index-CPIYW81T.js.map → index-CQDn-bLr.js.map} +1 -1
  138. package/dashboard/dist/assets/{index-DBi9Q9Hw.js → index-CgyucK0e.js} +2 -2
  139. package/dashboard/dist/assets/{index-DBi9Q9Hw.js.map → index-CgyucK0e.js.map} +1 -1
  140. package/dashboard/dist/assets/index-ClvYSNZd.css +1 -0
  141. package/dashboard/dist/assets/{index-E2hQ8DIi.js → index-CucXk58o.js} +2 -2
  142. package/dashboard/dist/assets/{index-E2hQ8DIi.js.map → index-CucXk58o.js.map} +1 -1
  143. package/dashboard/dist/assets/{index-BFQ2t-p1.js → index-DPJW96d2.js} +21 -21
  144. package/dashboard/dist/assets/index-DPJW96d2.js.map +1 -0
  145. package/dashboard/dist/assets/index-DeZhNCf5.js +2 -0
  146. package/dashboard/dist/assets/index-DeZhNCf5.js.map +1 -0
  147. package/dashboard/dist/assets/{index-BNkpns_E.js → index-DgzgRTNg.js} +2 -2
  148. package/dashboard/dist/assets/{index-BNkpns_E.js.map → index-DgzgRTNg.js.map} +1 -1
  149. package/dashboard/dist/assets/{index-Cydgj_Co.js → index-Do8Xp3pa.js} +2 -2
  150. package/dashboard/dist/assets/{index-Cydgj_Co.js.map → index-Do8Xp3pa.js.map} +1 -1
  151. package/dashboard/dist/assets/{index-Dhy2PVAw.js → index-QxAYCJ1S.js} +2 -2
  152. package/dashboard/dist/assets/{index-Dhy2PVAw.js.map → index-QxAYCJ1S.js.map} +1 -1
  153. package/dashboard/dist/assets/{knowledge-jQE3dBVi.js → knowledge-DzRpsm3D.js} +2 -2
  154. package/dashboard/dist/assets/{knowledge-jQE3dBVi.js.map → knowledge-DzRpsm3D.js.map} +1 -1
  155. package/dashboard/dist/assets/{mcp-DtEGfZiz.js → mcp-B1lc6nL4.js} +2 -2
  156. package/dashboard/dist/assets/{mcp-DtEGfZiz.js.map → mcp-B1lc6nL4.js.map} +1 -1
  157. package/dashboard/dist/assets/{mcp-query-CiTLVuDC.js → mcp-query-CXuweaN3.js} +2 -2
  158. package/dashboard/dist/assets/{mcp-query-CiTLVuDC.js.map → mcp-query-CXuweaN3.js.map} +1 -1
  159. package/dashboard/dist/assets/{pipelines-ClNdzuUK.js → pipelines-D4VLWDvu.js} +2 -2
  160. package/dashboard/dist/assets/{pipelines-ClNdzuUK.js.map → pipelines-D4VLWDvu.js.map} +1 -1
  161. package/dashboard/dist/assets/{roles-BmHbRaPT.js → roles-CSpHRRu8.js} +2 -2
  162. package/dashboard/dist/assets/{roles-BmHbRaPT.js.map → roles-CSpHRRu8.js.map} +1 -1
  163. package/dashboard/dist/assets/{tasks-BPONxLcq.js → tasks-CWUsKhM4.js} +2 -2
  164. package/dashboard/dist/assets/{tasks-BPONxLcq.js.map → tasks-CWUsKhM4.js.map} +1 -1
  165. package/dashboard/dist/assets/{topics-XREPRxwo.js → topics-BXwstrzB.js} +2 -2
  166. package/dashboard/dist/assets/{topics-XREPRxwo.js.map → topics-BXwstrzB.js.map} +1 -1
  167. package/dashboard/dist/assets/{useEventHooks-M7SaEfel.js → useEventHooks-CjygrbYy.js} +2 -2
  168. package/dashboard/dist/assets/{useEventHooks-M7SaEfel.js.map → useEventHooks-CjygrbYy.js.map} +1 -1
  169. package/dashboard/dist/assets/{useNamespace-BQHGkdBv.js → useNamespace-CsepDyR5.js} +2 -2
  170. package/dashboard/dist/assets/{useNamespace-BQHGkdBv.js.map → useNamespace-CsepDyR5.js.map} +1 -1
  171. package/dashboard/dist/assets/{useYamlActivityEvents-B7JtUGSE.js → useYamlActivityEvents-gWIG6akB.js} +2 -2
  172. package/dashboard/dist/assets/{useYamlActivityEvents-B7JtUGSE.js.map → useYamlActivityEvents-gWIG6akB.js.map} +1 -1
  173. package/dashboard/dist/assets/{users-BpjSNhQe.js → users-DvhHbR0R.js} +2 -2
  174. package/dashboard/dist/assets/{users-BpjSNhQe.js.map → users-DvhHbR0R.js.map} +1 -1
  175. package/dashboard/dist/assets/{workflows-k4jE0ECC.js → workflows-C7Cam2Ok.js} +2 -2
  176. package/dashboard/dist/assets/{workflows-k4jE0ECC.js.map → workflows-C7Cam2Ok.js.map} +1 -1
  177. package/dashboard/dist/assets/{yaml-workflows-DpviSLEL.js → yaml-workflows-ChUOE22W.js} +2 -2
  178. package/dashboard/dist/assets/{yaml-workflows-DpviSLEL.js.map → yaml-workflows-ChUOE22W.js.map} +1 -1
  179. package/dashboard/dist/index.html +2 -2
  180. package/docs/api/mcp/admin.md +94 -1
  181. package/docs/hitl-guide.md +48 -0
  182. package/docs/mcp.md +102 -0
  183. package/package.json +1 -1
  184. package/dashboard/dist/assets/EventTable-DzrMH-ux.js +0 -2
  185. package/dashboard/dist/assets/EventTable-DzrMH-ux.js.map +0 -1
  186. package/dashboard/dist/assets/McpRunDetailPage-DRbIZMU2.js +0 -2
  187. package/dashboard/dist/assets/SwimlaneTimeline-2Eet4OOL.js +0 -2
  188. package/dashboard/dist/assets/SwimlaneTimeline-2Eet4OOL.js.map +0 -1
  189. package/dashboard/dist/assets/WorkflowExecutionPage-CDr5CTM2.js +0 -2
  190. package/dashboard/dist/assets/index-BFQ2t-p1.js.map +0 -1
  191. package/dashboard/dist/assets/index-DSki_Ub6.css +0 -1
  192. package/dashboard/dist/assets/index-u08vQUaw.js +0 -2
  193. package/dashboard/dist/assets/index-u08vQUaw.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index-rUST2YsO.js","sources":["../../src/pages/admin/users/CreateUserModal.tsx","../../src/pages/admin/users/EditUserModal.tsx","../../src/pages/admin/bots/CreateBotModal.tsx","../../src/pages/admin/bots/EditBotModal.tsx","../../src/pages/admin/bots/BotDetailPanel.tsx","../../src/pages/admin/bots/BotsPage.tsx","../../src/pages/admin/users/RolePanel.tsx","../../src/pages/admin/users/AccountTabToggle.tsx","../../src/pages/admin/users/UsersPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useCreateUser } from '../../../api/users';\nimport { Modal } from '../../../components/common/modal/Modal';\n\nexport function CreateUserModal({\n open,\n onClose,\n}: {\n open: boolean;\n onClose: () => void;\n}) {\n const createUser = useCreateUser();\n const [form, setForm] = useState({\n external_id: '',\n email: '',\n display_name: '',\n password: '',\n });\n\n const [prevOpen, setPrevOpen] = useState(open);\n if (open !== prevOpen) {\n setPrevOpen(open);\n if (open) setForm({ external_id: '', email: '', display_name: '', password: '' });\n }\n\n const handleCreate = () => {\n if (!form.external_id.trim()) return;\n createUser.mutate(\n {\n external_id: form.external_id.trim(),\n email: form.email.trim() || undefined,\n display_name: form.display_name.trim() || undefined,\n password: form.password || undefined,\n },\n { onSuccess: onClose },\n );\n };\n\n const set = (field: string, value: string) =>\n setForm((f) => ({ ...f, [field]: value }));\n\n return (\n <Modal open={open} onClose={onClose} title=\"Create User\">\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n External ID (required)\n </label>\n <input\n type=\"text\"\n value={form.external_id}\n onChange={(e) => set('external_id', e.target.value)}\n placeholder=\"e.g., john.doe\"\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Display Name\n </label>\n <input\n type=\"text\"\n value={form.display_name}\n onChange={(e) => set('display_name', e.target.value)}\n placeholder=\"John Doe\"\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Email\n </label>\n <input\n type=\"text\"\n value={form.email}\n onChange={(e) => set('email', e.target.value)}\n placeholder=\"john@example.com\"\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Password\n </label>\n <input\n type=\"password\"\n value={form.password}\n onChange={(e) => set('password', e.target.value)}\n placeholder=\"Leave blank for no password\"\n className=\"input text-xs w-full\"\n />\n </div>\n\n {createUser.error && (\n <p className=\"text-xs text-status-error\">{(createUser.error as Error).message}</p>\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={onClose} className=\"btn-secondary text-xs\">\n Cancel\n </button>\n <button\n onClick={handleCreate}\n disabled={!form.external_id.trim() || createUser.isPending}\n className=\"btn-primary text-xs\"\n >\n {createUser.isPending ? 'Creating...' : 'Create'}\n </button>\n </div>\n </div>\n </Modal>\n );\n}\n","import { useState } from 'react';\nimport { useUpdateUser } from '../../../api/users';\nimport { Modal } from '../../../components/common/modal/Modal';\nimport type { LTUserRecord } from '../../../api/types';\n\nexport function EditUserModal({\n open,\n onClose,\n user,\n}: {\n open: boolean;\n onClose: () => void;\n user: LTUserRecord | null;\n}) {\n const updateUser = useUpdateUser();\n const [form, setForm] = useState({\n display_name: '',\n email: '',\n status: 'active' as string,\n });\n\n const [prevUser, setPrevUser] = useState(user);\n if (user !== prevUser) {\n setPrevUser(user);\n if (user) {\n setForm({\n display_name: user.display_name ?? '',\n email: user.email ?? '',\n status: user.status,\n });\n }\n }\n\n const handleSave = () => {\n if (!user) return;\n updateUser.mutate(\n {\n id: user.id,\n display_name: form.display_name.trim() || undefined,\n email: form.email.trim() || undefined,\n status: form.status,\n },\n { onSuccess: onClose },\n );\n };\n\n return (\n <Modal\n open={open}\n onClose={onClose}\n title={`Edit — ${user?.display_name || user?.external_id || ''}`}\n >\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Display Name\n </label>\n <input\n type=\"text\"\n value={form.display_name}\n onChange={(e) => setForm((f) => ({ ...f, display_name: e.target.value }))}\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Email\n </label>\n <input\n type=\"text\"\n value={form.email}\n onChange={(e) => setForm((f) => ({ ...f, email: e.target.value }))}\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Status\n </label>\n <select\n value={form.status}\n onChange={(e) => setForm((f) => ({ ...f, status: e.target.value }))}\n className=\"select text-xs w-full\"\n >\n <option value=\"active\">Active</option>\n <option value=\"inactive\">Inactive</option>\n <option value=\"suspended\">Suspended</option>\n </select>\n </div>\n\n {updateUser.error && (\n <p className=\"text-xs text-status-error\">{(updateUser.error as Error).message}</p>\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={onClose} className=\"btn-secondary text-xs\">\n Cancel\n </button>\n <button\n onClick={handleSave}\n disabled={updateUser.isPending}\n className=\"btn-primary text-xs\"\n >\n {updateUser.isPending ? 'Saving...' : 'Save'}\n </button>\n </div>\n </div>\n </Modal>\n );\n}\n","import { useState } from 'react';\nimport { useCreateBot } from '../../../api/bots';\nimport { Modal } from '../../../components/common/modal/Modal';\n\nexport function CreateBotModal({\n open,\n onClose,\n}: {\n open: boolean;\n onClose: () => void;\n}) {\n const createBot = useCreateBot();\n const [form, setForm] = useState({\n name: '',\n display_name: '',\n description: '',\n });\n\n const [prevOpen, setPrevOpen] = useState(open);\n if (open !== prevOpen) {\n setPrevOpen(open);\n if (open) setForm({ name: '', display_name: '', description: '' });\n }\n\n const handleCreate = () => {\n if (!form.name.trim()) return;\n createBot.mutate(\n {\n name: form.name.trim(),\n display_name: form.display_name.trim() || undefined,\n description: form.description.trim() || undefined,\n },\n { onSuccess: onClose },\n );\n };\n\n const set = (field: string, value: string) =>\n setForm((f) => ({ ...f, [field]: value }));\n\n return (\n <Modal open={open} onClose={onClose} title=\"Create Service Account\">\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Name (required)\n </label>\n <input\n type=\"text\"\n value={form.name}\n onChange={(e) => set('name', e.target.value.replace(/\\s+/g, '-').toLowerCase())}\n placeholder=\"e.g., ci-bot\"\n className=\"input text-xs w-full font-mono\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Display Name\n </label>\n <input\n type=\"text\"\n value={form.display_name}\n onChange={(e) => set('display_name', e.target.value)}\n placeholder=\"CI Bot\"\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Description\n </label>\n <input\n type=\"text\"\n value={form.description}\n onChange={(e) => set('description', e.target.value)}\n placeholder=\"Runs scheduled workflows\"\n className=\"input text-xs w-full\"\n />\n </div>\n\n {createBot.error && (\n <p className=\"text-xs text-status-error\">{(createBot.error as Error).message}</p>\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={onClose} className=\"btn-secondary text-xs\">\n Cancel\n </button>\n <button\n onClick={handleCreate}\n disabled={!form.name.trim() || createBot.isPending}\n className=\"btn-primary text-xs\"\n >\n {createBot.isPending ? 'Creating...' : 'Create'}\n </button>\n </div>\n </div>\n </Modal>\n );\n}\n","import { useState } from 'react';\nimport { useUpdateBot } from '../../../api/bots';\nimport { Modal } from '../../../components/common/modal/Modal';\nimport type { BotRecord } from '../../../api/types';\n\nexport function EditBotModal({\n open,\n onClose,\n bot,\n}: {\n open: boolean;\n onClose: () => void;\n bot: BotRecord | null;\n}) {\n const updateBot = useUpdateBot();\n const [form, setForm] = useState({\n display_name: '',\n description: '',\n status: 'active' as string,\n });\n\n const [prevBot, setPrevBot] = useState(bot);\n if (bot !== prevBot) {\n setPrevBot(bot);\n if (bot) {\n setForm({\n display_name: bot.display_name ?? '',\n description: bot.description ?? '',\n status: bot.status,\n });\n }\n }\n\n const handleSave = () => {\n if (!bot) return;\n updateBot.mutate(\n {\n id: bot.id,\n display_name: form.display_name.trim() || undefined,\n description: form.description.trim() || undefined,\n status: form.status,\n },\n { onSuccess: onClose },\n );\n };\n\n return (\n <Modal\n open={open}\n onClose={onClose}\n title={`Edit — ${bot?.display_name || bot?.external_id || ''}`}\n >\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Display Name\n </label>\n <input\n type=\"text\"\n value={form.display_name}\n onChange={(e) => setForm((f) => ({ ...f, display_name: e.target.value }))}\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Description\n </label>\n <input\n type=\"text\"\n value={form.description}\n onChange={(e) => setForm((f) => ({ ...f, description: e.target.value }))}\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Status\n </label>\n <select\n value={form.status}\n onChange={(e) => setForm((f) => ({ ...f, status: e.target.value }))}\n className=\"select text-xs w-full\"\n >\n <option value=\"active\">Active</option>\n <option value=\"inactive\">Inactive</option>\n <option value=\"suspended\">Suspended</option>\n </select>\n </div>\n\n {updateBot.error && (\n <p className=\"text-xs text-status-error\">{(updateBot.error as Error).message}</p>\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={onClose} className=\"btn-secondary text-xs\">\n Cancel\n </button>\n <button\n onClick={handleSave}\n disabled={updateBot.isPending}\n className=\"btn-primary text-xs\"\n >\n {updateBot.isPending ? 'Saving...' : 'Save'}\n </button>\n </div>\n </div>\n </Modal>\n );\n}\n","import { useState, useMemo } from 'react';\nimport { Trash2, Key, Plus, Copy, Check } from 'lucide-react';\nimport {\n useBotApiKeys,\n useCreateBotApiKey,\n useRevokeBotApiKey,\n useAddBotRole,\n useRemoveBotRole,\n} from '../../../api/bots';\nimport { useRoles } from '../../../api/roles';\nimport { ConfirmDeleteModal } from '../../../components/common/modal/ConfirmDeleteModal';\nimport { RolePill } from '../../../components/common/display/RolePill';\nimport { TimeAgo } from '../../../components/common/display/TimeAgo';\nimport type { BotRecord, BotApiKeyRecord, LTRoleType } from '../../../api/types';\n\nfunction ApiKeysSection({ botId }: { botId: string }) {\n const { data } = useBotApiKeys(botId);\n const createKey = useCreateBotApiKey();\n const revokeKey = useRevokeBotApiKey();\n\n const [newKeyName, setNewKeyName] = useState('');\n const [selectedScope, setSelectedScope] = useState<'read' | 'full'>('read');\n const [generatedKey, setGeneratedKey] = useState<string | null>(null);\n const [copied, setCopied] = useState(false);\n const [confirmRevoke, setConfirmRevoke] = useState<BotApiKeyRecord | null>(null);\n\n const keys = data?.keys ?? [];\n\n const SCOPE_PRESETS = {\n read: { label: 'Read only', scopes: ['mcp:read'], hint: 'Discovery and monitoring — read-safe tools only' },\n full: { label: 'Full access', scopes: ['mcp:read', 'mcp:full'], hint: 'All tools — can modify state' },\n } as const;\n\n const handleGenerate = () => {\n if (!newKeyName.trim()) return;\n createKey.mutate(\n { botId, name: newKeyName.trim(), scopes: SCOPE_PRESETS[selectedScope].scopes as unknown as string[] },\n {\n onSuccess: (result: any) => {\n setGeneratedKey(result.rawKey);\n setNewKeyName('');\n },\n },\n );\n };\n\n const handleCopy = () => {\n if (!generatedKey) return;\n navigator.clipboard.writeText(generatedKey);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const handleRevoke = () => {\n if (!confirmRevoke) return;\n revokeKey.mutate(\n { botId, keyId: confirmRevoke.id },\n { onSuccess: () => setConfirmRevoke(null) },\n );\n };\n\n return (\n <div>\n <p className=\"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-3\">\n API Keys\n </p>\n\n {generatedKey && (\n <div className=\"mb-3 p-3 bg-status-success/10 border border-status-success/30 rounded-md\">\n <p className=\"text-[10px] font-semibold text-status-success mb-1\">\n Key generated — copy now, it won't be shown again\n </p>\n <div className=\"flex items-center gap-2\">\n <code className=\"text-[11px] font-mono text-text-primary bg-surface-sunken px-2 py-1 rounded flex-1 overflow-hidden text-ellipsis\">\n {generatedKey}\n </code>\n <button\n onClick={handleCopy}\n className=\"text-text-tertiary hover:text-text-primary shrink-0\"\n title=\"Copy to clipboard\"\n >\n {copied ? <Check className=\"w-3.5 h-3.5 text-status-success\" /> : <Copy className=\"w-3.5 h-3.5\" />}\n </button>\n </div>\n </div>\n )}\n\n {keys.length === 0 ? (\n <p className=\"text-xs text-text-tertiary mb-3\">No API keys.</p>\n ) : (\n <div className=\"space-y-1.5 mb-3\">\n {keys.map((k) => (\n <div\n key={k.id}\n className=\"group/key flex items-center justify-between px-2.5 py-1.5 bg-surface-sunken rounded text-xs\"\n >\n <div className=\"flex items-center gap-2 flex-wrap\">\n <Key className=\"w-3 h-3 text-text-tertiary\" />\n <span className=\"text-text-primary font-mono\">{k.name}</span>\n {(k.scopes ?? []).map((s: string) => (\n <span key={s} className={`px-1.5 py-0.5 rounded text-[9px] font-mono ${s.includes('full') ? 'bg-status-warning/15 text-status-warning' : 'bg-accent/10 text-accent'}`}>\n {s}\n </span>\n ))}\n {k.last_used_at && (\n <span className=\"text-[10px] text-text-tertiary\">\n used <TimeAgo date={k.last_used_at} />\n </span>\n )}\n </div>\n <button\n onClick={() => setConfirmRevoke(k)}\n className=\"opacity-0 group-hover/key:opacity-100 transition-opacity text-text-tertiary hover:text-status-error\"\n title=\"Revoke key\"\n >\n <Trash2 className=\"w-3 h-3\" />\n </button>\n </div>\n ))}\n </div>\n )}\n\n <div className=\"flex items-center gap-2\">\n <input\n type=\"text\"\n value={newKeyName}\n onChange={(e) => setNewKeyName(e.target.value)}\n placeholder=\"Key name...\"\n className=\"input text-xs flex-1 font-mono\"\n />\n <div className=\"flex rounded-md border border-surface-border overflow-hidden shrink-0\">\n {(Object.entries(SCOPE_PRESETS) as [keyof typeof SCOPE_PRESETS, typeof SCOPE_PRESETS[keyof typeof SCOPE_PRESETS]][]).map(([key, preset]) => (\n <button\n key={key}\n type=\"button\"\n onClick={() => setSelectedScope(key)}\n title={preset.hint}\n className={`px-2.5 py-1 text-[10px] font-medium transition-colors ${\n selectedScope === key\n ? 'bg-accent text-white'\n : 'bg-surface text-text-secondary hover:bg-surface-hover'\n }`}\n >\n {preset.label}\n </button>\n ))}\n </div>\n <button\n onClick={handleGenerate}\n disabled={!newKeyName.trim() || createKey.isPending}\n className=\"btn-primary text-xs inline-flex items-center gap-1\"\n >\n <Plus className=\"w-3 h-3\" />\n {createKey.isPending ? '...' : 'Generate'}\n </button>\n </div>\n {createKey.error && (\n <p className=\"text-[10px] text-status-error mt-1\">{(createKey.error as Error).message}</p>\n )}\n\n <ConfirmDeleteModal\n open={!!confirmRevoke}\n onClose={() => setConfirmRevoke(null)}\n onConfirm={handleRevoke}\n title=\"Revoke API Key\"\n description={\n <>\n Revoke API key{' '}\n <span className=\"font-medium text-text-primary font-mono\">\n {confirmRevoke?.name}\n </span>\n ? This bot will no longer be able to authenticate with this key.\n </>\n }\n isPending={revokeKey.isPending}\n error={revokeKey.error as Error | null}\n />\n </div>\n );\n}\n\nfunction RolesSection({ bot }: { bot: BotRecord }) {\n const { data: allRolesData } = useRoles();\n const addRole = useAddBotRole();\n const removeRole = useRemoveBotRole();\n const [newRole, setNewRole] = useState('');\n const [newType, setNewType] = useState<LTRoleType>('member');\n\n const allRoles = allRolesData?.roles ?? [];\n const currentRoles = bot.roles ?? [];\n\n const available = useMemo(() => {\n const assigned = new Set(currentRoles.map((r) => r.role));\n return allRoles.filter((r) => !assigned.has(r));\n }, [allRoles, currentRoles]);\n\n const handleAdd = () => {\n if (!newRole.trim()) return;\n addRole.mutate(\n { botId: bot.id, role: newRole.trim(), type: newType },\n { onSuccess: () => { setNewRole(''); setNewType('member'); } },\n );\n };\n\n const handleRemove = (role: string) => {\n removeRole.mutate({ botId: bot.id, role });\n };\n\n return (\n <div>\n <p className=\"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-3\">\n Roles\n </p>\n\n {currentRoles.length === 0 ? (\n <p className=\"text-xs text-text-tertiary mb-3\">No roles assigned.</p>\n ) : (\n <div className=\"flex flex-wrap gap-2 mb-3\">\n {currentRoles.map((r) => (\n <span\n key={r.role}\n className=\"inline-flex items-center gap-1.5 px-2.5 py-1 text-xs bg-surface-sunken rounded-full text-text-secondary\"\n >\n <RolePill role={r.role} />\n <span className=\"text-[9px] text-text-tertiary\">{r.type}</span>\n <button\n onClick={() => handleRemove(r.role)}\n className=\"text-text-tertiary hover:text-status-error transition-colors ml-0.5\"\n title={`Remove ${r.role}`}\n >\n &times;\n </button>\n </span>\n ))}\n </div>\n )}\n\n {available.length > 0 && (\n <div className=\"flex items-center gap-2\">\n <select\n value={newRole}\n onChange={(e) => setNewRole(e.target.value)}\n className=\"select text-xs font-mono flex-1\"\n >\n <option value=\"\">Select a role...</option>\n {available.map((r) => (\n <option key={r} value={r}>{r}</option>\n ))}\n </select>\n <select\n value={newType}\n onChange={(e) => setNewType(e.target.value as LTRoleType)}\n className=\"select text-xs w-24\"\n >\n <option value=\"member\">member</option>\n <option value=\"admin\">admin</option>\n <option value=\"superadmin\">superadmin</option>\n </select>\n <button\n onClick={handleAdd}\n disabled={!newRole || addRole.isPending}\n className=\"btn-primary text-xs\"\n >\n {addRole.isPending ? '...' : 'Add'}\n </button>\n </div>\n )}\n {addRole.error && (\n <p className=\"text-[10px] text-status-error mt-1\">{(addRole.error as Error).message}</p>\n )}\n </div>\n );\n}\n\nexport function BotDetailPanel({ bot }: { bot: BotRecord | null }) {\n if (!bot) {\n return (\n <div className=\"border-l border-surface-border pl-6 pt-4 min-h-[300px]\">\n <p className=\"text-xs text-text-tertiary\">\n Select a service account to manage its API keys and roles.\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"border-l border-surface-border pl-6 pt-4 min-h-[300px] space-y-6\">\n <div>\n <p className=\"text-sm text-text-primary\">{bot.display_name || bot.external_id}</p>\n {bot.description && (\n <p className=\"text-xs text-text-tertiary mt-0.5\">{bot.description}</p>\n )}\n </div>\n\n <ApiKeysSection botId={bot.id} />\n <RolesSection bot={bot} />\n </div>\n );\n}\n","import { useState, useMemo } from 'react';\nimport { Pencil, Trash2 } from 'lucide-react';\nimport { useBots, useDeleteBot } from '../../../api/bots';\nimport { useFilterParams } from '../../../hooks/useFilterParams';\nimport { DataTable, type Column } from '../../../components/common/data/DataTable';\nimport { StickyPagination } from '../../../components/common/data/StickyPagination';\nimport { ConfirmDeleteModal } from '../../../components/common/modal/ConfirmDeleteModal';\nimport { RowAction, RowActionGroup } from '../../../components/common/layout/RowActions';\nimport { PageHeader } from '../../../components/common/layout/PageHeader';\nimport { RolePill } from '../../../components/common/display/RolePill';\nimport { TimestampCell } from '../../../components/common/display/TimestampCell';\nimport type { BotRecord } from '../../../api/types';\nimport { CreateBotModal } from './CreateBotModal';\nimport { EditBotModal } from './EditBotModal';\nimport { BotDetailPanel } from './BotDetailPanel';\n\nconst statusDot: Record<string, string> = {\n active: 'bg-status-success',\n inactive: 'bg-text-tertiary',\n suspended: 'bg-status-error',\n};\n\nexport function BotsPage({ embedded = false }: { embedded?: boolean }) {\n const { pagination } = useFilterParams({ filters: {} });\n const deleteBot = useDeleteBot();\n\n const [showCreate, setShowCreate] = useState(false);\n const [editingBot, setEditingBot] = useState<BotRecord | null>(null);\n const [selectedBot, setSelectedBot] = useState<BotRecord | null>(null);\n const [confirmDelete, setConfirmDelete] = useState<BotRecord | null>(null);\n\n const { data, isLoading } = useBots({\n limit: pagination.pageSize,\n offset: pagination.offset,\n });\n\n const total = data?.total ?? 0;\n const bots = data?.bots ?? [];\n\n const activeBot = useMemo(() => {\n if (!selectedBot) return null;\n return bots.find((b) => b.id === selectedBot.id) ?? selectedBot;\n }, [bots, selectedBot]);\n\n const columns: Column<BotRecord>[] = [\n {\n key: 'display_name',\n label: 'Service Account',\n render: (row) => (\n <div className=\"flex items-center gap-2.5\">\n <span\n className={`w-2 h-2 rounded-full shrink-0 ${statusDot[row.status] ?? 'bg-status-pending'}`}\n title={row.status}\n />\n <div>\n <p className=\"text-sm text-text-primary\">\n {row.display_name || row.external_id}\n </p>\n {row.description && (\n <p className=\"text-xs text-text-tertiary\">{row.description}</p>\n )}\n </div>\n </div>\n ),\n },\n {\n key: 'roles',\n label: 'Roles',\n render: (row) => (\n <div className=\"flex gap-1 flex-wrap\">\n {(row.roles ?? []).map((r) => (\n <RolePill key={r.role} role={r.role} />\n ))}\n </div>\n ),\n },\n {\n key: 'created_at',\n label: 'Created',\n render: (row) => <TimestampCell date={row.created_at} />,\n className: 'w-44',\n },\n {\n key: 'actions',\n label: '',\n render: (row) => (\n <RowActionGroup>\n <RowAction\n icon={Pencil}\n title=\"Edit service account\"\n onClick={() => setEditingBot(row)}\n />\n <RowAction\n icon={Trash2}\n title=\"Delete service account\"\n onClick={() => setConfirmDelete(row)}\n colorClass=\"text-text-tertiary hover:text-status-error\"\n />\n </RowActionGroup>\n ),\n className: 'w-16 text-right',\n },\n ];\n\n const handleDelete = () => {\n if (!confirmDelete) return;\n deleteBot.mutate(confirmDelete.id, {\n onSuccess: () => {\n setConfirmDelete(null);\n if (selectedBot?.id === confirmDelete.id) setSelectedBot(null);\n },\n });\n };\n\n return (\n <div>\n {embedded ? (\n <div className=\"flex justify-end mb-4\">\n <button onClick={() => setShowCreate(true)} className=\"btn-primary text-xs\">\n Add Service Account\n </button>\n </div>\n ) : (\n <PageHeader\n title=\"Service Accounts\"\n actions={\n <button onClick={() => setShowCreate(true)} className=\"btn-primary text-xs\">\n Add Service Account\n </button>\n }\n />\n )}\n\n <div className=\"grid grid-cols-1 lg:grid-cols-[1fr_360px] gap-6\">\n <div className=\"overflow-x-clip\">\n <DataTable\n columns={columns}\n data={bots}\n keyFn={(row) => row.id}\n isLoading={isLoading}\n emptyMessage=\"No service accounts yet\"\n onRowClick={(row) => setSelectedBot(row)}\n activeRowKey={activeBot?.id ?? null}\n />\n\n <StickyPagination\n page={pagination.page}\n totalPages={pagination.totalPages(total)}\n onPageChange={pagination.setPage}\n total={total}\n pageSize={pagination.pageSize}\n onPageSizeChange={pagination.setPageSize}\n />\n </div>\n\n <BotDetailPanel bot={activeBot} />\n </div>\n\n <CreateBotModal open={showCreate} onClose={() => setShowCreate(false)} />\n\n <EditBotModal\n open={!!editingBot}\n onClose={() => setEditingBot(null)}\n bot={editingBot}\n />\n\n <ConfirmDeleteModal\n open={!!confirmDelete}\n onClose={() => setConfirmDelete(null)}\n onConfirm={handleDelete}\n title=\"Delete Service Account\"\n description={\n <>\n Delete{' '}\n <span className=\"font-medium text-text-primary\">\n {confirmDelete?.display_name || confirmDelete?.external_id}\n </span>\n ? This will also revoke all API keys. This action cannot be undone.\n </>\n }\n isPending={deleteBot.isPending}\n error={deleteBot.error as Error | null}\n />\n </div>\n );\n}\n","import { useState, useMemo } from 'react';\nimport { useRoles } from '../../../api/roles';\nimport { useAddUserRole, useRemoveUserRole } from '../../../api/users';\nimport type { LTUserRecord, LTRoleType } from '../../../api/types';\nimport { RolePill } from '../../../components/common/display/RolePill';\n\nexport function RolePanel({ user }: { user: LTUserRecord | null }) {\n const { data: allRolesData } = useRoles();\n const addRole = useAddUserRole();\n const removeRole = useRemoveUserRole();\n const [newRole, setNewRole] = useState('');\n const [newType, setNewType] = useState<LTRoleType>('member');\n\n const allRoles = allRolesData?.roles ?? [];\n const currentRoles = user?.roles ?? [];\n\n const available = useMemo(() => {\n const assigned = new Set(currentRoles.map((r) => r.role));\n return allRoles.filter((r) => !assigned.has(r));\n }, [allRoles, currentRoles]);\n\n const handleAdd = () => {\n if (!user || !newRole.trim()) return;\n addRole.mutate(\n { userId: user.id, role: newRole.trim(), type: newType },\n { onSuccess: () => { setNewRole(''); setNewType('member'); } },\n );\n };\n\n const handleRemove = (role: string) => {\n if (!user) return;\n removeRole.mutate({ userId: user.id, role });\n };\n\n return (\n <div className=\"border-l border-surface-border pl-6 pt-4 min-h-[300px]\">\n <p className=\"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-4\">\n Role Membership\n </p>\n\n {!user ? (\n <p className=\"text-xs text-text-tertiary\">\n Select a user to manage their roles.\n </p>\n ) : (\n <div className=\"space-y-4\">\n <div>\n <p className=\"text-sm text-text-primary\">{user.display_name || user.external_id}</p>\n <p className=\"text-[10px] text-text-tertiary mt-0.5\">Member of:</p>\n </div>\n\n {currentRoles.length === 0 ? (\n <p className=\"text-xs text-text-tertiary\">No roles assigned.</p>\n ) : (\n <div className=\"flex flex-wrap gap-2\">\n {currentRoles.map((r) => (\n <span\n key={r.role}\n className=\"inline-flex items-center gap-1.5 px-2.5 py-1 text-xs bg-surface-sunken rounded-full text-text-secondary\"\n >\n <RolePill role={r.role} />\n <span className=\"text-[9px] text-text-tertiary\">{r.type}</span>\n <button\n onClick={() => handleRemove(r.role)}\n className=\"text-text-tertiary hover:text-status-error transition-colors ml-0.5\"\n title={`Remove ${r.role}`}\n >\n &times;\n </button>\n </span>\n ))}\n </div>\n )}\n\n {available.length > 0 && (\n <div className=\"pt-3 border-t border-surface-border\">\n <p className=\"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-2\">\n Add Role\n </p>\n <div className=\"flex items-center gap-2\">\n <select\n value={newRole}\n onChange={(e) => setNewRole(e.target.value)}\n className=\"select text-xs font-mono flex-1\"\n >\n <option value=\"\">Select a role...</option>\n {available.map((r) => (\n <option key={r} value={r}>{r}</option>\n ))}\n </select>\n <select\n value={newType}\n onChange={(e) => setNewType(e.target.value as LTRoleType)}\n className=\"select text-xs w-24\"\n >\n <option value=\"member\">member</option>\n <option value=\"admin\">admin</option>\n <option value=\"superadmin\">superadmin</option>\n </select>\n <button\n onClick={handleAdd}\n disabled={!newRole || addRole.isPending}\n className=\"btn-primary text-xs\"\n >\n {addRole.isPending ? '...' : 'Add'}\n </button>\n </div>\n {addRole.error && (\n <p className=\"text-[10px] text-status-error mt-1\">{(addRole.error as Error).message}</p>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import { User, Bot } from 'lucide-react';\n\nexport type AccountTab = 'users' | 'service-accounts';\n\nexport function AccountTabToggle({ active, onChange }: { active: AccountTab; onChange: (t: AccountTab) => void }) {\n const btn = (tab: AccountTab, icon: React.ReactNode, label: string) => (\n <button\n onClick={() => onChange(tab)}\n className={`flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md transition-colors ${\n active === tab\n ? 'bg-accent/10 text-accent font-medium'\n : 'text-text-tertiary hover:text-text-secondary hover:bg-surface-hover'\n }`}\n >\n {icon}\n {label}\n </button>\n );\n\n return (\n <div className=\"flex gap-1 p-0.5 bg-surface-sunken rounded-lg w-fit\">\n {btn('users', <User className=\"w-3.5 h-3.5\" />, 'User Accounts')}\n {btn('service-accounts', <Bot className=\"w-3.5 h-3.5\" />, 'Service Accounts')}\n </div>\n );\n}\n","import { useState, useMemo } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Pencil, Trash2 } from 'lucide-react';\nimport { useAccess } from '../../../hooks/useAccess';\nimport { useUsers, useDeleteUser } from '../../../api/users';\nimport { useFilterParams } from '../../../hooks/useFilterParams';\nimport { DataTable, type Column } from '../../../components/common/data/DataTable';\nimport { StickyPagination } from '../../../components/common/data/StickyPagination';\nimport { FilterBar, FilterSelect } from '../../../components/common/data/FilterBar';\nimport { TimestampCell } from '../../../components/common/display/TimestampCell';\nimport { ConfirmDeleteModal } from '../../../components/common/modal/ConfirmDeleteModal';\nimport { RowAction, RowActionGroup } from '../../../components/common/layout/RowActions';\nimport type { LTUserRecord } from '../../../api/types';\nimport { PageHeader } from '../../../components/common/layout/PageHeader';\nimport { RolePill } from '../../../components/common/display/RolePill';\nimport { CreateUserModal } from './CreateUserModal';\nimport { EditUserModal } from './EditUserModal';\nimport { BotsPage } from '../bots/BotsPage';\nimport { RolePanel } from './RolePanel';\nimport { AccountTabToggle, type AccountTab } from './AccountTabToggle';\n\nconst statusOptions = [\n { value: 'active', label: 'Active' },\n { value: 'inactive', label: 'Inactive' },\n { value: 'suspended', label: 'Suspended' },\n];\n\nconst statusDot: Record<string, string> = {\n active: 'bg-status-success',\n inactive: 'bg-text-tertiary',\n suspended: 'bg-status-error',\n};\n\nexport function UsersPage() {\n const { isBuilder } = useAccess();\n const [searchParams, setSearchParams] = useSearchParams();\n const tabParam = searchParams.get('tab');\n const activeTab: AccountTab = (isBuilder && tabParam === 'service-accounts') ? 'service-accounts' : 'users';\n\n const handleTabChange = (tab: AccountTab) => {\n if (tab === 'users') {\n setSearchParams({});\n } else {\n setSearchParams({ tab });\n }\n };\n\n return (\n <div>\n <PageHeader\n title=\"Accounts\"\n docsHash=\"#docs:dashboard.md:accounts\"\n actions={isBuilder ? <AccountTabToggle active={activeTab} onChange={handleTabChange} /> : undefined}\n />\n {activeTab === 'users' ? <UserAccountsPanel /> : <BotsPage embedded />}\n </div>\n );\n}\n\nfunction UserAccountsPanel() {\n const { isBuilder } = useAccess();\n const { filters, setFilter, pagination } = useFilterParams({\n filters: { status: '' },\n });\n const deleteUser = useDeleteUser();\n\n const [showCreate, setShowCreate] = useState(false);\n const [editingUser, setEditingUser] = useState<LTUserRecord | null>(null);\n const [selectedUser, setSelectedUser] = useState<LTUserRecord | null>(null);\n const [confirmDelete, setConfirmDelete] = useState<LTUserRecord | null>(null);\n\n const { data, isLoading } = useUsers({\n status: filters.status || undefined,\n limit: pagination.pageSize,\n offset: pagination.offset,\n });\n\n const total = data?.total ?? 0;\n const users = data?.users ?? [];\n\n const activeUser = useMemo(() => {\n if (!selectedUser) return null;\n return users.find((u) => u.id === selectedUser.id) ?? selectedUser;\n }, [users, selectedUser]);\n\n const columns: Column<LTUserRecord>[] = [\n {\n key: 'display_name',\n label: 'User',\n render: (row) => (\n <div className=\"flex items-center gap-2.5\">\n <span\n className={`w-2 h-2 rounded-full shrink-0 ${statusDot[row.status] ?? 'bg-status-pending'}`}\n title={row.status}\n />\n <div>\n <p className=\"text-sm text-text-primary\">\n {row.display_name || row.external_id}\n </p>\n {row.email && (\n <p className=\"text-xs text-text-tertiary\">{row.email}</p>\n )}\n </div>\n </div>\n ),\n },\n {\n key: 'roles',\n label: 'Roles',\n render: (row) => (\n <div className=\"flex gap-1 flex-wrap\">\n {(row.roles ?? []).map((r) => (\n <RolePill key={r.role} role={r.role} />\n ))}\n </div>\n ),\n },\n {\n key: 'created_at',\n label: 'Created',\n render: (row) => <TimestampCell date={row.created_at} />,\n className: 'w-44',\n },\n ...(isBuilder ? [{\n key: 'actions' as const,\n label: '',\n render: (row: LTUserRecord) => (\n <RowActionGroup>\n <RowAction\n icon={Pencil}\n title=\"Edit user\"\n onClick={() => setEditingUser(row)}\n />\n <RowAction\n icon={Trash2}\n title=\"Delete user\"\n onClick={() => setConfirmDelete(row)}\n colorClass=\"text-text-tertiary hover:text-status-error\"\n />\n </RowActionGroup>\n ),\n className: 'w-16 text-right',\n }] : []),\n ];\n\n const handleDelete = () => {\n if (!confirmDelete) return;\n deleteUser.mutate(confirmDelete.id, {\n onSuccess: () => setConfirmDelete(null),\n });\n };\n\n return (\n <div>\n {isBuilder && (\n <div className=\"flex justify-end mb-4\">\n <button onClick={() => setShowCreate(true)} className=\"btn-primary text-xs\">\n Add User\n </button>\n </div>\n )}\n\n <FilterBar>\n <FilterSelect\n label=\"Status\"\n value={filters.status}\n onChange={(v) => setFilter('status', v)}\n options={statusOptions}\n />\n </FilterBar>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-[1fr_320px] gap-6\">\n {/* Left — users table */}\n <div className=\"overflow-x-clip\">\n <DataTable\n columns={columns}\n data={users}\n keyFn={(row) => row.id}\n isLoading={isLoading}\n emptyMessage=\"No users found\"\n onRowClick={(row) => setSelectedUser(row)}\n activeRowKey={activeUser?.id ?? null}\n />\n\n <StickyPagination\n page={pagination.page}\n totalPages={pagination.totalPages(total)}\n onPageChange={pagination.setPage}\n total={total}\n pageSize={pagination.pageSize}\n onPageSizeChange={pagination.setPageSize}\n />\n </div>\n\n {/* Right — role management panel */}\n <RolePanel user={activeUser} />\n </div>\n\n <CreateUserModal open={showCreate} onClose={() => setShowCreate(false)} />\n\n <EditUserModal\n open={!!editingUser}\n onClose={() => setEditingUser(null)}\n user={editingUser}\n />\n\n <ConfirmDeleteModal\n open={!!confirmDelete}\n onClose={() => setConfirmDelete(null)}\n onConfirm={handleDelete}\n title=\"Delete User\"\n description={\n <>\n Delete{' '}\n <span className=\"font-medium text-text-primary\">\n {confirmDelete?.display_name || confirmDelete?.external_id}\n </span>\n ? This action cannot be undone.\n </>\n }\n isPending={deleteUser.isPending}\n error={deleteUser.error as Error | null}\n />\n </div>\n );\n}\n"],"names":["CreateUserModal","open","onClose","createUser","useCreateUser","form","setForm","useState","prevOpen","setPrevOpen","handleCreate","set","field","value","f","jsx","Modal","jsxs","e","EditUserModal","user","updateUser","useUpdateUser","prevUser","setPrevUser","handleSave","CreateBotModal","createBot","useCreateBot","EditBotModal","bot","updateBot","useUpdateBot","prevBot","setPrevBot","ApiKeysSection","botId","data","useBotApiKeys","createKey","useCreateBotApiKey","revokeKey","useRevokeBotApiKey","newKeyName","setNewKeyName","selectedScope","setSelectedScope","generatedKey","setGeneratedKey","copied","setCopied","confirmRevoke","setConfirmRevoke","keys","SCOPE_PRESETS","handleGenerate","result","handleCopy","handleRevoke","Check","Copy","k","Key","s","TimeAgo","Trash2","key","preset","Plus","ConfirmDeleteModal","Fragment","RolesSection","allRolesData","useRoles","addRole","useAddBotRole","removeRole","useRemoveBotRole","newRole","setNewRole","newType","setNewType","allRoles","currentRoles","available","useMemo","assigned","r","handleAdd","handleRemove","role","RolePill","BotDetailPanel","statusDot","BotsPage","embedded","pagination","useFilterParams","deleteBot","useDeleteBot","showCreate","setShowCreate","editingBot","setEditingBot","selectedBot","setSelectedBot","confirmDelete","setConfirmDelete","isLoading","useBots","total","bots","activeBot","b","columns","row","TimestampCell","RowActionGroup","RowAction","Pencil","handleDelete","PageHeader","DataTable","StickyPagination","RolePanel","useAddUserRole","useRemoveUserRole","AccountTabToggle","active","onChange","btn","tab","icon","label","User","Bot","statusOptions","UsersPage","isBuilder","useAccess","searchParams","setSearchParams","useSearchParams","tabParam","activeTab","handleTabChange","UserAccountsPanel","filters","setFilter","deleteUser","useDeleteUser","editingUser","setEditingUser","selectedUser","setSelectedUser","useUsers","users","activeUser","u","FilterBar","FilterSelect","v"],"mappings":"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"}
1
+ {"version":3,"file":"index-CEpw_Fh8.js","sources":["../../src/pages/admin/users/CreateUserModal.tsx","../../src/pages/admin/users/EditUserModal.tsx","../../src/pages/admin/bots/CreateBotModal.tsx","../../src/pages/admin/bots/EditBotModal.tsx","../../src/pages/admin/bots/BotDetailPanel.tsx","../../src/pages/admin/bots/BotsPage.tsx","../../src/pages/admin/users/RolePanel.tsx","../../src/pages/admin/users/AccountTabToggle.tsx","../../src/pages/admin/users/UsersPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useCreateUser } from '../../../api/users';\nimport { Modal } from '../../../components/common/modal/Modal';\n\nexport function CreateUserModal({\n open,\n onClose,\n}: {\n open: boolean;\n onClose: () => void;\n}) {\n const createUser = useCreateUser();\n const [form, setForm] = useState({\n external_id: '',\n email: '',\n display_name: '',\n password: '',\n });\n\n const [prevOpen, setPrevOpen] = useState(open);\n if (open !== prevOpen) {\n setPrevOpen(open);\n if (open) setForm({ external_id: '', email: '', display_name: '', password: '' });\n }\n\n const handleCreate = () => {\n if (!form.external_id.trim()) return;\n createUser.mutate(\n {\n external_id: form.external_id.trim(),\n email: form.email.trim() || undefined,\n display_name: form.display_name.trim() || undefined,\n password: form.password || undefined,\n },\n { onSuccess: onClose },\n );\n };\n\n const set = (field: string, value: string) =>\n setForm((f) => ({ ...f, [field]: value }));\n\n return (\n <Modal open={open} onClose={onClose} title=\"Create User\">\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n External ID (required)\n </label>\n <input\n type=\"text\"\n value={form.external_id}\n onChange={(e) => set('external_id', e.target.value)}\n placeholder=\"e.g., john.doe\"\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Display Name\n </label>\n <input\n type=\"text\"\n value={form.display_name}\n onChange={(e) => set('display_name', e.target.value)}\n placeholder=\"John Doe\"\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Email\n </label>\n <input\n type=\"text\"\n value={form.email}\n onChange={(e) => set('email', e.target.value)}\n placeholder=\"john@example.com\"\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Password\n </label>\n <input\n type=\"password\"\n value={form.password}\n onChange={(e) => set('password', e.target.value)}\n placeholder=\"Leave blank for no password\"\n className=\"input text-xs w-full\"\n />\n </div>\n\n {createUser.error && (\n <p className=\"text-xs text-status-error\">{(createUser.error as Error).message}</p>\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={onClose} className=\"btn-secondary text-xs\">\n Cancel\n </button>\n <button\n onClick={handleCreate}\n disabled={!form.external_id.trim() || createUser.isPending}\n className=\"btn-primary text-xs\"\n >\n {createUser.isPending ? 'Creating...' : 'Create'}\n </button>\n </div>\n </div>\n </Modal>\n );\n}\n","import { useState } from 'react';\nimport { useUpdateUser } from '../../../api/users';\nimport { Modal } from '../../../components/common/modal/Modal';\nimport type { LTUserRecord } from '../../../api/types';\n\nexport function EditUserModal({\n open,\n onClose,\n user,\n}: {\n open: boolean;\n onClose: () => void;\n user: LTUserRecord | null;\n}) {\n const updateUser = useUpdateUser();\n const [form, setForm] = useState({\n display_name: '',\n email: '',\n status: 'active' as string,\n });\n\n const [prevUser, setPrevUser] = useState(user);\n if (user !== prevUser) {\n setPrevUser(user);\n if (user) {\n setForm({\n display_name: user.display_name ?? '',\n email: user.email ?? '',\n status: user.status,\n });\n }\n }\n\n const handleSave = () => {\n if (!user) return;\n updateUser.mutate(\n {\n id: user.id,\n display_name: form.display_name.trim() || undefined,\n email: form.email.trim() || undefined,\n status: form.status,\n },\n { onSuccess: onClose },\n );\n };\n\n return (\n <Modal\n open={open}\n onClose={onClose}\n title={`Edit — ${user?.display_name || user?.external_id || ''}`}\n >\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Display Name\n </label>\n <input\n type=\"text\"\n value={form.display_name}\n onChange={(e) => setForm((f) => ({ ...f, display_name: e.target.value }))}\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Email\n </label>\n <input\n type=\"text\"\n value={form.email}\n onChange={(e) => setForm((f) => ({ ...f, email: e.target.value }))}\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Status\n </label>\n <select\n value={form.status}\n onChange={(e) => setForm((f) => ({ ...f, status: e.target.value }))}\n className=\"select text-xs w-full\"\n >\n <option value=\"active\">Active</option>\n <option value=\"inactive\">Inactive</option>\n <option value=\"suspended\">Suspended</option>\n </select>\n </div>\n\n {updateUser.error && (\n <p className=\"text-xs text-status-error\">{(updateUser.error as Error).message}</p>\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={onClose} className=\"btn-secondary text-xs\">\n Cancel\n </button>\n <button\n onClick={handleSave}\n disabled={updateUser.isPending}\n className=\"btn-primary text-xs\"\n >\n {updateUser.isPending ? 'Saving...' : 'Save'}\n </button>\n </div>\n </div>\n </Modal>\n );\n}\n","import { useState } from 'react';\nimport { useCreateBot } from '../../../api/bots';\nimport { Modal } from '../../../components/common/modal/Modal';\n\nexport function CreateBotModal({\n open,\n onClose,\n}: {\n open: boolean;\n onClose: () => void;\n}) {\n const createBot = useCreateBot();\n const [form, setForm] = useState({\n name: '',\n display_name: '',\n description: '',\n });\n\n const [prevOpen, setPrevOpen] = useState(open);\n if (open !== prevOpen) {\n setPrevOpen(open);\n if (open) setForm({ name: '', display_name: '', description: '' });\n }\n\n const handleCreate = () => {\n if (!form.name.trim()) return;\n createBot.mutate(\n {\n name: form.name.trim(),\n display_name: form.display_name.trim() || undefined,\n description: form.description.trim() || undefined,\n },\n { onSuccess: onClose },\n );\n };\n\n const set = (field: string, value: string) =>\n setForm((f) => ({ ...f, [field]: value }));\n\n return (\n <Modal open={open} onClose={onClose} title=\"Create Service Account\">\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Name (required)\n </label>\n <input\n type=\"text\"\n value={form.name}\n onChange={(e) => set('name', e.target.value.replace(/\\s+/g, '-').toLowerCase())}\n placeholder=\"e.g., ci-bot\"\n className=\"input text-xs w-full font-mono\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Display Name\n </label>\n <input\n type=\"text\"\n value={form.display_name}\n onChange={(e) => set('display_name', e.target.value)}\n placeholder=\"CI Bot\"\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Description\n </label>\n <input\n type=\"text\"\n value={form.description}\n onChange={(e) => set('description', e.target.value)}\n placeholder=\"Runs scheduled workflows\"\n className=\"input text-xs w-full\"\n />\n </div>\n\n {createBot.error && (\n <p className=\"text-xs text-status-error\">{(createBot.error as Error).message}</p>\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={onClose} className=\"btn-secondary text-xs\">\n Cancel\n </button>\n <button\n onClick={handleCreate}\n disabled={!form.name.trim() || createBot.isPending}\n className=\"btn-primary text-xs\"\n >\n {createBot.isPending ? 'Creating...' : 'Create'}\n </button>\n </div>\n </div>\n </Modal>\n );\n}\n","import { useState } from 'react';\nimport { useUpdateBot } from '../../../api/bots';\nimport { Modal } from '../../../components/common/modal/Modal';\nimport type { BotRecord } from '../../../api/types';\n\nexport function EditBotModal({\n open,\n onClose,\n bot,\n}: {\n open: boolean;\n onClose: () => void;\n bot: BotRecord | null;\n}) {\n const updateBot = useUpdateBot();\n const [form, setForm] = useState({\n display_name: '',\n description: '',\n status: 'active' as string,\n });\n\n const [prevBot, setPrevBot] = useState(bot);\n if (bot !== prevBot) {\n setPrevBot(bot);\n if (bot) {\n setForm({\n display_name: bot.display_name ?? '',\n description: bot.description ?? '',\n status: bot.status,\n });\n }\n }\n\n const handleSave = () => {\n if (!bot) return;\n updateBot.mutate(\n {\n id: bot.id,\n display_name: form.display_name.trim() || undefined,\n description: form.description.trim() || undefined,\n status: form.status,\n },\n { onSuccess: onClose },\n );\n };\n\n return (\n <Modal\n open={open}\n onClose={onClose}\n title={`Edit — ${bot?.display_name || bot?.external_id || ''}`}\n >\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Display Name\n </label>\n <input\n type=\"text\"\n value={form.display_name}\n onChange={(e) => setForm((f) => ({ ...f, display_name: e.target.value }))}\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Description\n </label>\n <input\n type=\"text\"\n value={form.description}\n onChange={(e) => setForm((f) => ({ ...f, description: e.target.value }))}\n className=\"input text-xs w-full\"\n />\n </div>\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1\">\n Status\n </label>\n <select\n value={form.status}\n onChange={(e) => setForm((f) => ({ ...f, status: e.target.value }))}\n className=\"select text-xs w-full\"\n >\n <option value=\"active\">Active</option>\n <option value=\"inactive\">Inactive</option>\n <option value=\"suspended\">Suspended</option>\n </select>\n </div>\n\n {updateBot.error && (\n <p className=\"text-xs text-status-error\">{(updateBot.error as Error).message}</p>\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={onClose} className=\"btn-secondary text-xs\">\n Cancel\n </button>\n <button\n onClick={handleSave}\n disabled={updateBot.isPending}\n className=\"btn-primary text-xs\"\n >\n {updateBot.isPending ? 'Saving...' : 'Save'}\n </button>\n </div>\n </div>\n </Modal>\n );\n}\n","import { useState, useMemo } from 'react';\nimport { Trash2, Key, Plus, Copy, Check } from 'lucide-react';\nimport {\n useBotApiKeys,\n useCreateBotApiKey,\n useRevokeBotApiKey,\n useAddBotRole,\n useRemoveBotRole,\n} from '../../../api/bots';\nimport { useRoles } from '../../../api/roles';\nimport { ConfirmDeleteModal } from '../../../components/common/modal/ConfirmDeleteModal';\nimport { RolePill } from '../../../components/common/display/RolePill';\nimport { TimeAgo } from '../../../components/common/display/TimeAgo';\nimport type { BotRecord, BotApiKeyRecord, LTRoleType } from '../../../api/types';\n\nfunction ApiKeysSection({ botId }: { botId: string }) {\n const { data } = useBotApiKeys(botId);\n const createKey = useCreateBotApiKey();\n const revokeKey = useRevokeBotApiKey();\n\n const [newKeyName, setNewKeyName] = useState('');\n const [selectedScope, setSelectedScope] = useState<'read' | 'full'>('read');\n const [generatedKey, setGeneratedKey] = useState<string | null>(null);\n const [copied, setCopied] = useState(false);\n const [confirmRevoke, setConfirmRevoke] = useState<BotApiKeyRecord | null>(null);\n\n const keys = data?.keys ?? [];\n\n const SCOPE_PRESETS = {\n read: { label: 'Read only', scopes: ['mcp:read'], hint: 'Discovery and monitoring — read-safe tools only' },\n full: { label: 'Full access', scopes: ['mcp:read', 'mcp:full'], hint: 'All tools — can modify state' },\n } as const;\n\n const handleGenerate = () => {\n if (!newKeyName.trim()) return;\n createKey.mutate(\n { botId, name: newKeyName.trim(), scopes: SCOPE_PRESETS[selectedScope].scopes as unknown as string[] },\n {\n onSuccess: (result: any) => {\n setGeneratedKey(result.rawKey);\n setNewKeyName('');\n },\n },\n );\n };\n\n const handleCopy = () => {\n if (!generatedKey) return;\n navigator.clipboard.writeText(generatedKey);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const handleRevoke = () => {\n if (!confirmRevoke) return;\n revokeKey.mutate(\n { botId, keyId: confirmRevoke.id },\n { onSuccess: () => setConfirmRevoke(null) },\n );\n };\n\n return (\n <div>\n <p className=\"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-3\">\n API Keys\n </p>\n\n {generatedKey && (\n <div className=\"mb-3 p-3 bg-status-success/10 border border-status-success/30 rounded-md\">\n <p className=\"text-[10px] font-semibold text-status-success mb-1\">\n Key generated — copy now, it won't be shown again\n </p>\n <div className=\"flex items-center gap-2\">\n <code className=\"text-[11px] font-mono text-text-primary bg-surface-sunken px-2 py-1 rounded flex-1 overflow-hidden text-ellipsis\">\n {generatedKey}\n </code>\n <button\n onClick={handleCopy}\n className=\"text-text-tertiary hover:text-text-primary shrink-0\"\n title=\"Copy to clipboard\"\n >\n {copied ? <Check className=\"w-3.5 h-3.5 text-status-success\" /> : <Copy className=\"w-3.5 h-3.5\" />}\n </button>\n </div>\n </div>\n )}\n\n {keys.length === 0 ? (\n <p className=\"text-xs text-text-tertiary mb-3\">No API keys.</p>\n ) : (\n <div className=\"space-y-1.5 mb-3\">\n {keys.map((k) => (\n <div\n key={k.id}\n className=\"group/key flex items-center justify-between px-2.5 py-1.5 bg-surface-sunken rounded text-xs\"\n >\n <div className=\"flex items-center gap-2 flex-wrap\">\n <Key className=\"w-3 h-3 text-text-tertiary\" />\n <span className=\"text-text-primary font-mono\">{k.name}</span>\n {(k.scopes ?? []).map((s: string) => (\n <span key={s} className={`px-1.5 py-0.5 rounded text-[9px] font-mono ${s.includes('full') ? 'bg-status-warning/15 text-status-warning' : 'bg-accent/10 text-accent'}`}>\n {s}\n </span>\n ))}\n {k.last_used_at && (\n <span className=\"text-[10px] text-text-tertiary\">\n used <TimeAgo date={k.last_used_at} />\n </span>\n )}\n </div>\n <button\n onClick={() => setConfirmRevoke(k)}\n className=\"opacity-0 group-hover/key:opacity-100 transition-opacity text-text-tertiary hover:text-status-error\"\n title=\"Revoke key\"\n >\n <Trash2 className=\"w-3 h-3\" />\n </button>\n </div>\n ))}\n </div>\n )}\n\n <div className=\"flex items-center gap-2\">\n <input\n type=\"text\"\n value={newKeyName}\n onChange={(e) => setNewKeyName(e.target.value)}\n placeholder=\"Key name...\"\n className=\"input text-xs flex-1 font-mono\"\n />\n <div className=\"flex rounded-md border border-surface-border overflow-hidden shrink-0\">\n {(Object.entries(SCOPE_PRESETS) as [keyof typeof SCOPE_PRESETS, typeof SCOPE_PRESETS[keyof typeof SCOPE_PRESETS]][]).map(([key, preset]) => (\n <button\n key={key}\n type=\"button\"\n onClick={() => setSelectedScope(key)}\n title={preset.hint}\n className={`px-2.5 py-1 text-[10px] font-medium transition-colors ${\n selectedScope === key\n ? 'bg-accent text-white'\n : 'bg-surface text-text-secondary hover:bg-surface-hover'\n }`}\n >\n {preset.label}\n </button>\n ))}\n </div>\n <button\n onClick={handleGenerate}\n disabled={!newKeyName.trim() || createKey.isPending}\n className=\"btn-primary text-xs inline-flex items-center gap-1\"\n >\n <Plus className=\"w-3 h-3\" />\n {createKey.isPending ? '...' : 'Generate'}\n </button>\n </div>\n {createKey.error && (\n <p className=\"text-[10px] text-status-error mt-1\">{(createKey.error as Error).message}</p>\n )}\n\n <ConfirmDeleteModal\n open={!!confirmRevoke}\n onClose={() => setConfirmRevoke(null)}\n onConfirm={handleRevoke}\n title=\"Revoke API Key\"\n description={\n <>\n Revoke API key{' '}\n <span className=\"font-medium text-text-primary font-mono\">\n {confirmRevoke?.name}\n </span>\n ? This bot will no longer be able to authenticate with this key.\n </>\n }\n isPending={revokeKey.isPending}\n error={revokeKey.error as Error | null}\n />\n </div>\n );\n}\n\nfunction RolesSection({ bot }: { bot: BotRecord }) {\n const { data: allRolesData } = useRoles();\n const addRole = useAddBotRole();\n const removeRole = useRemoveBotRole();\n const [newRole, setNewRole] = useState('');\n const [newType, setNewType] = useState<LTRoleType>('member');\n\n const allRoles = allRolesData?.roles ?? [];\n const currentRoles = bot.roles ?? [];\n\n const available = useMemo(() => {\n const assigned = new Set(currentRoles.map((r) => r.role));\n return allRoles.filter((r) => !assigned.has(r));\n }, [allRoles, currentRoles]);\n\n const handleAdd = () => {\n if (!newRole.trim()) return;\n addRole.mutate(\n { botId: bot.id, role: newRole.trim(), type: newType },\n { onSuccess: () => { setNewRole(''); setNewType('member'); } },\n );\n };\n\n const handleRemove = (role: string) => {\n removeRole.mutate({ botId: bot.id, role });\n };\n\n return (\n <div>\n <p className=\"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-3\">\n Roles\n </p>\n\n {currentRoles.length === 0 ? (\n <p className=\"text-xs text-text-tertiary mb-3\">No roles assigned.</p>\n ) : (\n <div className=\"flex flex-wrap gap-2 mb-3\">\n {currentRoles.map((r) => (\n <span\n key={r.role}\n className=\"inline-flex items-center gap-1.5 px-2.5 py-1 text-xs bg-surface-sunken rounded-full text-text-secondary\"\n >\n <RolePill role={r.role} />\n <span className=\"text-[9px] text-text-tertiary\">{r.type}</span>\n <button\n onClick={() => handleRemove(r.role)}\n className=\"text-text-tertiary hover:text-status-error transition-colors ml-0.5\"\n title={`Remove ${r.role}`}\n >\n &times;\n </button>\n </span>\n ))}\n </div>\n )}\n\n {available.length > 0 && (\n <div className=\"flex items-center gap-2\">\n <select\n value={newRole}\n onChange={(e) => setNewRole(e.target.value)}\n className=\"select text-xs font-mono flex-1\"\n >\n <option value=\"\">Select a role...</option>\n {available.map((r) => (\n <option key={r} value={r}>{r}</option>\n ))}\n </select>\n <select\n value={newType}\n onChange={(e) => setNewType(e.target.value as LTRoleType)}\n className=\"select text-xs w-24\"\n >\n <option value=\"member\">member</option>\n <option value=\"admin\">admin</option>\n <option value=\"superadmin\">superadmin</option>\n </select>\n <button\n onClick={handleAdd}\n disabled={!newRole || addRole.isPending}\n className=\"btn-primary text-xs\"\n >\n {addRole.isPending ? '...' : 'Add'}\n </button>\n </div>\n )}\n {addRole.error && (\n <p className=\"text-[10px] text-status-error mt-1\">{(addRole.error as Error).message}</p>\n )}\n </div>\n );\n}\n\nexport function BotDetailPanel({ bot }: { bot: BotRecord | null }) {\n if (!bot) {\n return (\n <div className=\"border-l border-surface-border pl-6 pt-4 min-h-[300px]\">\n <p className=\"text-xs text-text-tertiary\">\n Select a service account to manage its API keys and roles.\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"border-l border-surface-border pl-6 pt-4 min-h-[300px] space-y-6\">\n <div>\n <p className=\"text-sm text-text-primary\">{bot.display_name || bot.external_id}</p>\n {bot.description && (\n <p className=\"text-xs text-text-tertiary mt-0.5\">{bot.description}</p>\n )}\n </div>\n\n <ApiKeysSection botId={bot.id} />\n <RolesSection bot={bot} />\n </div>\n );\n}\n","import { useState, useMemo } from 'react';\nimport { Pencil, Trash2 } from 'lucide-react';\nimport { useBots, useDeleteBot } from '../../../api/bots';\nimport { useFilterParams } from '../../../hooks/useFilterParams';\nimport { DataTable, type Column } from '../../../components/common/data/DataTable';\nimport { StickyPagination } from '../../../components/common/data/StickyPagination';\nimport { ConfirmDeleteModal } from '../../../components/common/modal/ConfirmDeleteModal';\nimport { RowAction, RowActionGroup } from '../../../components/common/layout/RowActions';\nimport { PageHeader } from '../../../components/common/layout/PageHeader';\nimport { RolePill } from '../../../components/common/display/RolePill';\nimport { TimestampCell } from '../../../components/common/display/TimestampCell';\nimport type { BotRecord } from '../../../api/types';\nimport { CreateBotModal } from './CreateBotModal';\nimport { EditBotModal } from './EditBotModal';\nimport { BotDetailPanel } from './BotDetailPanel';\n\nconst statusDot: Record<string, string> = {\n active: 'bg-status-success',\n inactive: 'bg-text-tertiary',\n suspended: 'bg-status-error',\n};\n\nexport function BotsPage({ embedded = false }: { embedded?: boolean }) {\n const { pagination } = useFilterParams({ filters: {} });\n const deleteBot = useDeleteBot();\n\n const [showCreate, setShowCreate] = useState(false);\n const [editingBot, setEditingBot] = useState<BotRecord | null>(null);\n const [selectedBot, setSelectedBot] = useState<BotRecord | null>(null);\n const [confirmDelete, setConfirmDelete] = useState<BotRecord | null>(null);\n\n const { data, isLoading } = useBots({\n limit: pagination.pageSize,\n offset: pagination.offset,\n });\n\n const total = data?.total ?? 0;\n const bots = data?.bots ?? [];\n\n const activeBot = useMemo(() => {\n if (!selectedBot) return null;\n return bots.find((b) => b.id === selectedBot.id) ?? selectedBot;\n }, [bots, selectedBot]);\n\n const columns: Column<BotRecord>[] = [\n {\n key: 'display_name',\n label: 'Service Account',\n render: (row) => (\n <div className=\"flex items-center gap-2.5\">\n <span\n className={`w-2 h-2 rounded-full shrink-0 ${statusDot[row.status] ?? 'bg-status-pending'}`}\n title={row.status}\n />\n <div>\n <p className=\"text-sm text-text-primary\">\n {row.display_name || row.external_id}\n </p>\n {row.description && (\n <p className=\"text-xs text-text-tertiary\">{row.description}</p>\n )}\n </div>\n </div>\n ),\n },\n {\n key: 'roles',\n label: 'Roles',\n render: (row) => (\n <div className=\"flex gap-1 flex-wrap\">\n {(row.roles ?? []).map((r) => (\n <RolePill key={r.role} role={r.role} />\n ))}\n </div>\n ),\n },\n {\n key: 'created_at',\n label: 'Created',\n render: (row) => <TimestampCell date={row.created_at} />,\n className: 'w-44',\n },\n {\n key: 'actions',\n label: '',\n render: (row) => (\n <RowActionGroup>\n <RowAction\n icon={Pencil}\n title=\"Edit service account\"\n onClick={() => setEditingBot(row)}\n />\n <RowAction\n icon={Trash2}\n title=\"Delete service account\"\n onClick={() => setConfirmDelete(row)}\n colorClass=\"text-text-tertiary hover:text-status-error\"\n />\n </RowActionGroup>\n ),\n className: 'w-16 text-right',\n },\n ];\n\n const handleDelete = () => {\n if (!confirmDelete) return;\n deleteBot.mutate(confirmDelete.id, {\n onSuccess: () => {\n setConfirmDelete(null);\n if (selectedBot?.id === confirmDelete.id) setSelectedBot(null);\n },\n });\n };\n\n return (\n <div>\n {embedded ? (\n <div className=\"flex justify-end mb-4\">\n <button onClick={() => setShowCreate(true)} className=\"btn-primary text-xs\">\n Add Service Account\n </button>\n </div>\n ) : (\n <PageHeader\n title=\"Service Accounts\"\n actions={\n <button onClick={() => setShowCreate(true)} className=\"btn-primary text-xs\">\n Add Service Account\n </button>\n }\n />\n )}\n\n <div className=\"grid grid-cols-1 lg:grid-cols-[1fr_360px] gap-6\">\n <div className=\"overflow-x-clip\">\n <DataTable\n columns={columns}\n data={bots}\n keyFn={(row) => row.id}\n isLoading={isLoading}\n emptyMessage=\"No service accounts yet\"\n onRowClick={(row) => setSelectedBot(row)}\n activeRowKey={activeBot?.id ?? null}\n />\n\n <StickyPagination\n page={pagination.page}\n totalPages={pagination.totalPages(total)}\n onPageChange={pagination.setPage}\n total={total}\n pageSize={pagination.pageSize}\n onPageSizeChange={pagination.setPageSize}\n />\n </div>\n\n <BotDetailPanel bot={activeBot} />\n </div>\n\n <CreateBotModal open={showCreate} onClose={() => setShowCreate(false)} />\n\n <EditBotModal\n open={!!editingBot}\n onClose={() => setEditingBot(null)}\n bot={editingBot}\n />\n\n <ConfirmDeleteModal\n open={!!confirmDelete}\n onClose={() => setConfirmDelete(null)}\n onConfirm={handleDelete}\n title=\"Delete Service Account\"\n description={\n <>\n Delete{' '}\n <span className=\"font-medium text-text-primary\">\n {confirmDelete?.display_name || confirmDelete?.external_id}\n </span>\n ? This will also revoke all API keys. This action cannot be undone.\n </>\n }\n isPending={deleteBot.isPending}\n error={deleteBot.error as Error | null}\n />\n </div>\n );\n}\n","import { useState, useMemo } from 'react';\nimport { useRoles } from '../../../api/roles';\nimport { useAddUserRole, useRemoveUserRole } from '../../../api/users';\nimport type { LTUserRecord, LTRoleType } from '../../../api/types';\nimport { RolePill } from '../../../components/common/display/RolePill';\n\nexport function RolePanel({ user }: { user: LTUserRecord | null }) {\n const { data: allRolesData } = useRoles();\n const addRole = useAddUserRole();\n const removeRole = useRemoveUserRole();\n const [newRole, setNewRole] = useState('');\n const [newType, setNewType] = useState<LTRoleType>('member');\n\n const allRoles = allRolesData?.roles ?? [];\n const currentRoles = user?.roles ?? [];\n\n const available = useMemo(() => {\n const assigned = new Set(currentRoles.map((r) => r.role));\n return allRoles.filter((r) => !assigned.has(r));\n }, [allRoles, currentRoles]);\n\n const handleAdd = () => {\n if (!user || !newRole.trim()) return;\n addRole.mutate(\n { userId: user.id, role: newRole.trim(), type: newType },\n { onSuccess: () => { setNewRole(''); setNewType('member'); } },\n );\n };\n\n const handleRemove = (role: string) => {\n if (!user) return;\n removeRole.mutate({ userId: user.id, role });\n };\n\n return (\n <div className=\"border-l border-surface-border pl-6 pt-4 min-h-[300px]\">\n <p className=\"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-4\">\n Role Membership\n </p>\n\n {!user ? (\n <p className=\"text-xs text-text-tertiary\">\n Select a user to manage their roles.\n </p>\n ) : (\n <div className=\"space-y-4\">\n <div>\n <p className=\"text-sm text-text-primary\">{user.display_name || user.external_id}</p>\n <p className=\"text-[10px] text-text-tertiary mt-0.5\">Member of:</p>\n </div>\n\n {currentRoles.length === 0 ? (\n <p className=\"text-xs text-text-tertiary\">No roles assigned.</p>\n ) : (\n <div className=\"flex flex-wrap gap-2\">\n {currentRoles.map((r) => (\n <span\n key={r.role}\n className=\"inline-flex items-center gap-1.5 px-2.5 py-1 text-xs bg-surface-sunken rounded-full text-text-secondary\"\n >\n <RolePill role={r.role} />\n <span className=\"text-[9px] text-text-tertiary\">{r.type}</span>\n <button\n onClick={() => handleRemove(r.role)}\n className=\"text-text-tertiary hover:text-status-error transition-colors ml-0.5\"\n title={`Remove ${r.role}`}\n >\n &times;\n </button>\n </span>\n ))}\n </div>\n )}\n\n {available.length > 0 && (\n <div className=\"pt-3 border-t border-surface-border\">\n <p className=\"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-2\">\n Add Role\n </p>\n <div className=\"flex items-center gap-2\">\n <select\n value={newRole}\n onChange={(e) => setNewRole(e.target.value)}\n className=\"select text-xs font-mono flex-1\"\n >\n <option value=\"\">Select a role...</option>\n {available.map((r) => (\n <option key={r} value={r}>{r}</option>\n ))}\n </select>\n <select\n value={newType}\n onChange={(e) => setNewType(e.target.value as LTRoleType)}\n className=\"select text-xs w-24\"\n >\n <option value=\"member\">member</option>\n <option value=\"admin\">admin</option>\n <option value=\"superadmin\">superadmin</option>\n </select>\n <button\n onClick={handleAdd}\n disabled={!newRole || addRole.isPending}\n className=\"btn-primary text-xs\"\n >\n {addRole.isPending ? '...' : 'Add'}\n </button>\n </div>\n {addRole.error && (\n <p className=\"text-[10px] text-status-error mt-1\">{(addRole.error as Error).message}</p>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import { User, Bot } from 'lucide-react';\n\nexport type AccountTab = 'users' | 'service-accounts';\n\nexport function AccountTabToggle({ active, onChange }: { active: AccountTab; onChange: (t: AccountTab) => void }) {\n const btn = (tab: AccountTab, icon: React.ReactNode, label: string) => (\n <button\n onClick={() => onChange(tab)}\n className={`flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md transition-colors ${\n active === tab\n ? 'bg-accent/10 text-accent font-medium'\n : 'text-text-tertiary hover:text-text-secondary hover:bg-surface-hover'\n }`}\n >\n {icon}\n {label}\n </button>\n );\n\n return (\n <div className=\"flex gap-1 p-0.5 bg-surface-sunken rounded-lg w-fit\">\n {btn('users', <User className=\"w-3.5 h-3.5\" />, 'User Accounts')}\n {btn('service-accounts', <Bot className=\"w-3.5 h-3.5\" />, 'Service Accounts')}\n </div>\n );\n}\n","import { useState, useMemo } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Pencil, Trash2 } from 'lucide-react';\nimport { useAccess } from '../../../hooks/useAccess';\nimport { useUsers, useDeleteUser } from '../../../api/users';\nimport { useFilterParams } from '../../../hooks/useFilterParams';\nimport { DataTable, type Column } from '../../../components/common/data/DataTable';\nimport { StickyPagination } from '../../../components/common/data/StickyPagination';\nimport { FilterBar, FilterSelect } from '../../../components/common/data/FilterBar';\nimport { TimestampCell } from '../../../components/common/display/TimestampCell';\nimport { ConfirmDeleteModal } from '../../../components/common/modal/ConfirmDeleteModal';\nimport { RowAction, RowActionGroup } from '../../../components/common/layout/RowActions';\nimport type { LTUserRecord } from '../../../api/types';\nimport { PageHeader } from '../../../components/common/layout/PageHeader';\nimport { RolePill } from '../../../components/common/display/RolePill';\nimport { CreateUserModal } from './CreateUserModal';\nimport { EditUserModal } from './EditUserModal';\nimport { BotsPage } from '../bots/BotsPage';\nimport { RolePanel } from './RolePanel';\nimport { AccountTabToggle, type AccountTab } from './AccountTabToggle';\n\nconst statusOptions = [\n { value: 'active', label: 'Active' },\n { value: 'inactive', label: 'Inactive' },\n { value: 'suspended', label: 'Suspended' },\n];\n\nconst statusDot: Record<string, string> = {\n active: 'bg-status-success',\n inactive: 'bg-text-tertiary',\n suspended: 'bg-status-error',\n};\n\nexport function UsersPage() {\n const { isBuilder } = useAccess();\n const [searchParams, setSearchParams] = useSearchParams();\n const tabParam = searchParams.get('tab');\n const activeTab: AccountTab = (isBuilder && tabParam === 'service-accounts') ? 'service-accounts' : 'users';\n\n const handleTabChange = (tab: AccountTab) => {\n if (tab === 'users') {\n setSearchParams({});\n } else {\n setSearchParams({ tab });\n }\n };\n\n return (\n <div>\n <PageHeader\n title=\"Accounts\"\n docsHash=\"#docs:dashboard.md:accounts\"\n actions={isBuilder ? <AccountTabToggle active={activeTab} onChange={handleTabChange} /> : undefined}\n />\n {activeTab === 'users' ? <UserAccountsPanel /> : <BotsPage embedded />}\n </div>\n );\n}\n\nfunction UserAccountsPanel() {\n const { isBuilder } = useAccess();\n const { filters, setFilter, pagination } = useFilterParams({\n filters: { status: '' },\n });\n const deleteUser = useDeleteUser();\n\n const [showCreate, setShowCreate] = useState(false);\n const [editingUser, setEditingUser] = useState<LTUserRecord | null>(null);\n const [selectedUser, setSelectedUser] = useState<LTUserRecord | null>(null);\n const [confirmDelete, setConfirmDelete] = useState<LTUserRecord | null>(null);\n\n const { data, isLoading } = useUsers({\n status: filters.status || undefined,\n limit: pagination.pageSize,\n offset: pagination.offset,\n });\n\n const total = data?.total ?? 0;\n const users = data?.users ?? [];\n\n const activeUser = useMemo(() => {\n if (!selectedUser) return null;\n return users.find((u) => u.id === selectedUser.id) ?? selectedUser;\n }, [users, selectedUser]);\n\n const columns: Column<LTUserRecord>[] = [\n {\n key: 'display_name',\n label: 'User',\n render: (row) => (\n <div className=\"flex items-center gap-2.5\">\n <span\n className={`w-2 h-2 rounded-full shrink-0 ${statusDot[row.status] ?? 'bg-status-pending'}`}\n title={row.status}\n />\n <div>\n <p className=\"text-sm text-text-primary\">\n {row.display_name || row.external_id}\n </p>\n {row.email && (\n <p className=\"text-xs text-text-tertiary\">{row.email}</p>\n )}\n </div>\n </div>\n ),\n },\n {\n key: 'roles',\n label: 'Roles',\n render: (row) => (\n <div className=\"flex gap-1 flex-wrap\">\n {(row.roles ?? []).map((r) => (\n <RolePill key={r.role} role={r.role} />\n ))}\n </div>\n ),\n },\n {\n key: 'created_at',\n label: 'Created',\n render: (row) => <TimestampCell date={row.created_at} />,\n className: 'w-44',\n },\n ...(isBuilder ? [{\n key: 'actions' as const,\n label: '',\n render: (row: LTUserRecord) => (\n <RowActionGroup>\n <RowAction\n icon={Pencil}\n title=\"Edit user\"\n onClick={() => setEditingUser(row)}\n />\n <RowAction\n icon={Trash2}\n title=\"Delete user\"\n onClick={() => setConfirmDelete(row)}\n colorClass=\"text-text-tertiary hover:text-status-error\"\n />\n </RowActionGroup>\n ),\n className: 'w-16 text-right',\n }] : []),\n ];\n\n const handleDelete = () => {\n if (!confirmDelete) return;\n deleteUser.mutate(confirmDelete.id, {\n onSuccess: () => setConfirmDelete(null),\n });\n };\n\n return (\n <div>\n {isBuilder && (\n <div className=\"flex justify-end mb-4\">\n <button onClick={() => setShowCreate(true)} className=\"btn-primary text-xs\">\n Add User\n </button>\n </div>\n )}\n\n <FilterBar>\n <FilterSelect\n label=\"Status\"\n value={filters.status}\n onChange={(v) => setFilter('status', v)}\n options={statusOptions}\n />\n </FilterBar>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-[1fr_320px] gap-6\">\n {/* Left — users table */}\n <div className=\"overflow-x-clip\">\n <DataTable\n columns={columns}\n data={users}\n keyFn={(row) => row.id}\n isLoading={isLoading}\n emptyMessage=\"No users found\"\n onRowClick={(row) => setSelectedUser(row)}\n activeRowKey={activeUser?.id ?? null}\n />\n\n <StickyPagination\n page={pagination.page}\n totalPages={pagination.totalPages(total)}\n onPageChange={pagination.setPage}\n total={total}\n pageSize={pagination.pageSize}\n onPageSizeChange={pagination.setPageSize}\n />\n </div>\n\n {/* Right — role management panel */}\n <RolePanel user={activeUser} />\n </div>\n\n <CreateUserModal open={showCreate} onClose={() => setShowCreate(false)} />\n\n <EditUserModal\n open={!!editingUser}\n onClose={() => setEditingUser(null)}\n user={editingUser}\n />\n\n <ConfirmDeleteModal\n open={!!confirmDelete}\n onClose={() => setConfirmDelete(null)}\n onConfirm={handleDelete}\n title=\"Delete User\"\n description={\n <>\n Delete{' '}\n <span className=\"font-medium text-text-primary\">\n {confirmDelete?.display_name || confirmDelete?.external_id}\n </span>\n ? This action cannot be undone.\n </>\n }\n isPending={deleteUser.isPending}\n error={deleteUser.error as Error | null}\n />\n </div>\n );\n}\n"],"names":["CreateUserModal","open","onClose","createUser","useCreateUser","form","setForm","useState","prevOpen","setPrevOpen","handleCreate","set","field","value","f","jsx","Modal","jsxs","e","EditUserModal","user","updateUser","useUpdateUser","prevUser","setPrevUser","handleSave","CreateBotModal","createBot","useCreateBot","EditBotModal","bot","updateBot","useUpdateBot","prevBot","setPrevBot","ApiKeysSection","botId","data","useBotApiKeys","createKey","useCreateBotApiKey","revokeKey","useRevokeBotApiKey","newKeyName","setNewKeyName","selectedScope","setSelectedScope","generatedKey","setGeneratedKey","copied","setCopied","confirmRevoke","setConfirmRevoke","keys","SCOPE_PRESETS","handleGenerate","result","handleCopy","handleRevoke","Check","Copy","k","Key","s","TimeAgo","Trash2","key","preset","Plus","ConfirmDeleteModal","Fragment","RolesSection","allRolesData","useRoles","addRole","useAddBotRole","removeRole","useRemoveBotRole","newRole","setNewRole","newType","setNewType","allRoles","currentRoles","available","useMemo","assigned","r","handleAdd","handleRemove","role","RolePill","BotDetailPanel","statusDot","BotsPage","embedded","pagination","useFilterParams","deleteBot","useDeleteBot","showCreate","setShowCreate","editingBot","setEditingBot","selectedBot","setSelectedBot","confirmDelete","setConfirmDelete","isLoading","useBots","total","bots","activeBot","b","columns","row","TimestampCell","RowActionGroup","RowAction","Pencil","handleDelete","PageHeader","DataTable","StickyPagination","RolePanel","useAddUserRole","useRemoveUserRole","AccountTabToggle","active","onChange","btn","tab","icon","label","User","Bot","statusOptions","UsersPage","isBuilder","useAccess","searchParams","setSearchParams","useSearchParams","tabParam","activeTab","handleTabChange","UserAccountsPanel","filters","setFilter","deleteUser","useDeleteUser","editingUser","setEditingUser","selectedUser","setSelectedUser","useUsers","users","activeUser","u","FilterBar","FilterSelect","v"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{a as n,j as t}from"./vendor-query-B2UbickB.js";import{g as h}from"./workflows-k4jE0ECC.js";import{D as g}from"./DataTable-D9yuBv0w.js";import{F as y,b as j}from"./FilterBar-Ck4K4rzu.js";import{R as q,a as u}from"./RowActions-Dg-Fsm5O.js";import{u as C}from"./useFilterParams-x-Dg0Vgz.js";import{P as R}from"./PageHeader-Bnt2iQQa.js";import{T as b}from"./TaskQueuePill-CUsofm0X.js";import{W as _}from"./WorkflowPill-F1oKUzmc.js";import{ad as v,ag as N,m as I}from"./vendor-icons-Dj2F0Jrb.js";import{c as P}from"./vendor-react-CXumBFUA.js";import"./index-BFQ2t-p1.js";import"./EmptyState-BcsfPq9T.js";function H(){const r=P(),{data:c,isLoading:m}=h(),{filters:s,setFilter:i}=C({filters:{search:"",queue:""}}),[a,p]=n.useState(s.search);n.useEffect(()=>{if(a===s.search)return;const e=setTimeout(()=>i("search",a),300);return()=>clearTimeout(e)},[a,i,s.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(s.search){const l=s.search.toLowerCase();e=e.filter(w=>w.name.toLowerCase().includes(l))}return s.queue&&(e=e.filter(l=>l.task_queue===s.queue)),e},[o,s]),k=[{key:"name",label:"Workflow",render:e=>t.jsx(_,{type:e.name})},{key:"task_queue",label:"Queue",render:e=>t.jsx(b,{queue:e.task_queue}),className:"whitespace-nowrap"},{key:"registered",label:"Status",render:e=>e.registered?t.jsxs("span",{className:"inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] font-medium bg-accent/10 text-accent",children:[t.jsx(v,{className:"w-3 h-3"}),"Certified"]}):t.jsx("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-surface-sunken text-text-tertiary",children:"Durable"}),className:"whitespace-nowrap"},{key:"actions",label:"",render:e=>t.jsx(q,{children:e.registered?t.jsx(u,{icon:N,title:"View config",onClick:()=>r(`/workflows/registry/${encodeURIComponent(e.name)}`)}):t.jsx(u,{icon:I,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 t.jsxs("div",{children:[t.jsx(R,{title:"Workers",docsHash:"#docs:dashboard.md:task-queues"}),t.jsxs(y,{children:[t.jsx("input",{type:"text",placeholder:"Search workers...",value:a,onChange:e=>p(e.target.value),className:"input text-[11px] py-1 px-2 w-56"}),t.jsx(j,{label:"Queue",value:s.queue,onChange:e=>i("queue",e),options:d.map(e=>({value:e,label:e}))})]}),t.jsx(g,{columns:k,data:f,keyFn:e=>e.name,onRowClick:x,isLoading:m,emptyMessage:"No active workers"})]})}export{H as WorkersPage};
2
- //# sourceMappingURL=index-CPIYW81T.js.map
1
+ import{a as n,j as t}from"./vendor-query-B2UbickB.js";import{g as h}from"./workflows-C7Cam2Ok.js";import{D as g}from"./DataTable-D9yuBv0w.js";import{F as y,b as j}from"./FilterBar-Ck4K4rzu.js";import{R as q,a as u}from"./RowActions-Dg-Fsm5O.js";import{u as C}from"./useFilterParams-x-Dg0Vgz.js";import{P as R}from"./PageHeader-Bnt2iQQa.js";import{T as b}from"./TaskQueuePill-CUsofm0X.js";import{W as _}from"./WorkflowPill-F1oKUzmc.js";import{ad as v,ag as N,m as I}from"./vendor-icons-Dj2F0Jrb.js";import{c as P}from"./vendor-react-CXumBFUA.js";import"./index-DPJW96d2.js";import"./EmptyState-BcsfPq9T.js";function H(){const r=P(),{data:c,isLoading:m}=h(),{filters:s,setFilter:i}=C({filters:{search:"",queue:""}}),[a,p]=n.useState(s.search);n.useEffect(()=>{if(a===s.search)return;const e=setTimeout(()=>i("search",a),300);return()=>clearTimeout(e)},[a,i,s.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(s.search){const l=s.search.toLowerCase();e=e.filter(w=>w.name.toLowerCase().includes(l))}return s.queue&&(e=e.filter(l=>l.task_queue===s.queue)),e},[o,s]),k=[{key:"name",label:"Workflow",render:e=>t.jsx(_,{type:e.name})},{key:"task_queue",label:"Queue",render:e=>t.jsx(b,{queue:e.task_queue}),className:"whitespace-nowrap"},{key:"registered",label:"Status",render:e=>e.registered?t.jsxs("span",{className:"inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] font-medium bg-accent/10 text-accent",children:[t.jsx(v,{className:"w-3 h-3"}),"Certified"]}):t.jsx("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-surface-sunken text-text-tertiary",children:"Durable"}),className:"whitespace-nowrap"},{key:"actions",label:"",render:e=>t.jsx(q,{children:e.registered?t.jsx(u,{icon:N,title:"View config",onClick:()=>r(`/workflows/registry/${encodeURIComponent(e.name)}`)}):t.jsx(u,{icon:I,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 t.jsxs("div",{children:[t.jsx(R,{title:"Workers",docsHash:"#docs:dashboard.md:task-queues"}),t.jsxs(y,{children:[t.jsx("input",{type:"text",placeholder:"Search workers...",value:a,onChange:e=>p(e.target.value),className:"input text-[11px] py-1 px-2 w-56"}),t.jsx(j,{label:"Queue",value:s.queue,onChange:e=>i("queue",e),options:d.map(e=>({value:e,label:e}))})]}),t.jsx(g,{columns:k,data:f,keyFn:e=>e.name,onRowClick:x,isLoading:m,emptyMessage:"No active workers"})]})}export{H as WorkersPage};
2
+ //# sourceMappingURL=index-CQDn-bLr.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-CPIYW81T.js","sources":["../../src/pages/workflows/workers/WorkersPage.tsx"],"sourcesContent":["import { 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), 300);\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-[10px] 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-[10px] 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-[11px] 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","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-CQDn-bLr.js","sources":["../../src/pages/workflows/workers/WorkersPage.tsx"],"sourcesContent":["import { 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), 300);\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-[10px] 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-[10px] 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-[11px] 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","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 p,j as e}from"./vendor-query-B2UbickB.js";import{u as L,a as M,b as D,c as I}from"./mcp-DtEGfZiz.js";import{E as R}from"./EmptyState-BcsfPq9T.js";import{C as z}from"./ConfirmDeleteModal-D9_1b4MW.js";import{P as k}from"./PageHeader-Bnt2iQQa.js";import{F,a as q,b as P}from"./FilterBar-Ck4K4rzu.js";import{S as _}from"./StickyPagination-BWhFSr2d.js";import{u as $}from"./useFilterParams-x-Dg0Vgz.js";import{S as A,T as B}from"./ToolTestPanel-DYGlB-QW.js";import{R as O,a as b}from"./RowActions-Dg-Fsm5O.js";import{S as H}from"./StatusBadge-Bl3FXVmF.js";import{T as J}from"./ToolPill-DjvedZSn.js";import{p as G,al as Q,am as U,Q as W,q as V,P as X}from"./vendor-icons-Dj2F0Jrb.js";import{c as Y}from"./vendor-react-CXumBFUA.js";import"./index-BFQ2t-p1.js";import"./Modal-CSrxpXeM.js";import"./RunAsSelector-sBxAvlRf.js";import"./BotPicker-fFE4GAaO.js";import"./bots-CDe2jXNx.js";import"./helpers-DzO-OGPe.js";function Z(s){const[t,a]=p.useState(()=>{try{const o=localStorage.getItem(s);if(o){const u=JSON.parse(o);if(Array.isArray(u))return new Set(u)}}catch{}return new Set}),i=p.useCallback(o=>{try{localStorage.setItem(s,JSON.stringify([...o]))}catch{}},[s]),n=p.useCallback(o=>{a(u=>{const x=new Set(u);return x.has(o)?x.delete(o):x.add(o),i(x),x})},[i]),m=p.useCallback(o=>t.has(o),[t]);return{expandedIds:t,toggle:n,isExpanded:m}}function K(s){var t,a;return!!((t=s.metadata)!=null&&t.builtin)||!!((a=s.transport_config)!=null&&a.builtin)}function ee(s,t){var n;if(!t)return!0;const a=t.toLowerCase();return s.name.toLowerCase().includes(a)||(n=s.description)!=null&&n.toLowerCase().includes(a)||(s.tags??[]).some(m=>m.toLowerCase().includes(a))?!0:(s.tool_manifest??[]).some(m=>{var o;return m.name.toLowerCase().includes(a)||((o=m.description)==null?void 0:o.toLowerCase().includes(a))})}function te(s,t){if(!t)return s;const a=t.toLowerCase();return s.filter(i=>{var n;return i.name.toLowerCase().includes(a)||((n=i.description)==null?void 0:n.toLowerCase().includes(a))})}function se({server:s,expanded:t,onToggle:a,onEdit:i,onDelete:n,onTryTool:m,connect:o,disconnect:u,visibleTools:x}){const l=s.tool_manifest??[],f=K(s),g=s.tags??[];return e.jsxs(e.Fragment,{children:[e.jsxs("tr",{onClick:l.length>0?a:void 0,className:`group/row border-b border-surface-border/50 transition-colors duration-100 ${l.length>0?"cursor-pointer row-hover":""}`,children:[e.jsx("td",{className:"px-6 py-2.5",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:`transition-transform duration-150 ${t?"rotate-90":""} ${l.length===0?"opacity-0":"text-text-tertiary"}`,children:e.jsx(G,{size:14})}),e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx(A,{name:s.name,serverId:s.id,short:!1}),l.length>0&&e.jsx("sup",{className:"text-[9px] font-normal text-accent/70",children:l.length})]}),g.length>0&&e.jsxs("div",{className:"flex gap-1 ml-auto shrink-0",children:[g.slice(0,3).map(c=>e.jsx("span",{className:"inline-block px-1.5 py-0 text-[9px] text-text-tertiary bg-surface-sunken rounded",children:c},c)),g.length>3&&e.jsx("span",{className:"text-[9px] text-text-quaternary",title:g.slice(3).join(", "),children:"…"})]})]})}),e.jsx("td",{className:"px-4 py-2.5 w-28 whitespace-nowrap",children:e.jsx(H,{status:s.status})}),e.jsx("td",{className:"px-4 py-2.5 w-16",children:e.jsxs(O,{children:[!f&&(s.status==="connected"?e.jsx(b,{icon:Q,title:"Disconnect server",onClick:()=>u.mutate(s.id)}):e.jsx(b,{icon:U,title:"Connect server",onClick:()=>o.mutate(s.id),colorClass:"text-text-tertiary hover:text-status-success"})),e.jsx(b,{icon:W,title:"Edit server",onClick:i}),!f&&e.jsx(b,{icon:V,title:"Delete server",onClick:n,colorClass:"text-text-tertiary hover:text-status-error"})]})})]}),t&&x.map(c=>e.jsxs("tr",{onClick:()=>m(c),className:"group/row cursor-pointer hover:bg-surface-hover/50 transition-colors border-b border-surface-border/15",children:[e.jsxs("td",{className:"pl-14 pr-6 py-2.5",children:[e.jsx(J,{name:c.name,size:"md"}),c.description&&e.jsx("p",{className:"text-[11px] leading-snug text-text-quaternary mt-0.5",children:c.description})]}),e.jsx("td",{className:"px-4 py-2.5 w-28"}),e.jsx("td",{className:"px-4 py-2.5 w-16",children:e.jsx("div",{className:"flex items-center justify-end",children:e.jsx("button",{onClick:h=>{h.stopPropagation(),m(c)},className:"opacity-0 group-hover/row:opacity-100 transition-opacity text-text-tertiary hover:text-accent",title:"Try tool",children:e.jsx(X,{className:"w-3.5 h-3.5",strokeWidth:1.5})})})})]},c.name))]})}function Se(){const s=Y(),{filters:t,setFilter:a,pagination:i}=$({filters:{status:"",search:"",tag:""}}),{data:n,isLoading:m}=L({status:t.status||void 0,search:t.search||void 0,tags:t.tag||void 0}),o=M(),u=D(),x=I(),[l,f]=p.useState(null),{expandedIds:g,toggle:c}=Z("lt:expanded:mcp-servers"),[h,w]=p.useState(null),j=(n==null?void 0:n.servers)??[],y=(n==null?void 0:n.total)??0,T=p.useMemo(()=>{const r=new Set;for(const d of j)for(const C of d.tags??[])r.add(C);return[...r].sort().map(d=>({value:d,label:d}))},[j]),v=p.useMemo(()=>t.search?j.filter(r=>ee(r,t.search)):j,[j,t.search]);p.useEffect(()=>{if(!t.search)return;const r=t.search.toLowerCase();for(const d of v)(d.tool_manifest??[]).some(S=>{var N;return S.name.toLowerCase().includes(r)||((N=S.description)==null?void 0:N.toLowerCase().includes(r))})&&!g.has(d.id)&&c(d.id)},[t.search,v]);const E=()=>{l&&x.mutate(l.id,{onSuccess:()=>f(null)})};return m?e.jsxs("div",{children:[e.jsx(k,{title:"Servers & Tools"}),e.jsx("div",{className:"animate-pulse space-y-0",children:Array.from({length:5}).map((r,d)=>e.jsx("div",{className:"h-14 border-b last:border-b-0 px-6 flex items-center",children:e.jsx("div",{className:"h-3 bg-surface-sunken rounded w-full"})},d))})]}):e.jsxs("div",{children:[e.jsx(k,{title:"Servers & Tools",docsHash:"#docs:dashboard.md:mcp-server-tools",actions:e.jsx("button",{onClick:()=>s("/mcp/servers/new"),className:"btn-primary text-xs",children:"Register Server"})}),e.jsx("p",{className:"text-sm text-text-secondary mb-6 max-w-2xl leading-relaxed",children:"Registered MCP servers and their available tools. Each server exposes tools that can be used by the MCP Tool Designer."}),e.jsxs(F,{children:[e.jsx(q,{label:"Search",value:t.search,onChange:r=>a("search",r),placeholder:"Server or tool name..."}),e.jsx(P,{label:"Tag",value:t.tag,onChange:r=>a("tag",r),options:T}),e.jsx(P,{label:"Status",value:t.status,onChange:r=>a("status",r),options:[{value:"registered",label:"Registered"},{value:"connected",label:"Connected"},{value:"error",label:"Error"},{value:"disconnected",label:"Disconnected"}]})]}),e.jsxs("div",{className:"flex gap-0 ",children:[e.jsxs("div",{className:`${h?"flex-1 min-w-0":"w-full"} transition-all`,children:[v.length===0?e.jsx(R,{title:"No servers found"}):e.jsxs("table",{className:"w-full",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b",children:[e.jsx("th",{className:"sticky top-[2.75rem] z-10 bg-surface px-6 py-3 text-left text-[10px] font-semibold uppercase tracking-widest text-text-tertiary",children:"Server / Tool"}),e.jsx("th",{className:"sticky top-[2.75rem] z-10 bg-surface px-4 py-3 text-left text-[10px] font-semibold uppercase tracking-widest text-text-tertiary w-28",children:"Status"}),e.jsx("th",{className:"sticky top-[2.75rem] z-10 bg-surface w-16"})]})}),e.jsx("tbody",{children:v.map(r=>e.jsx(se,{server:r,expanded:g.has(r.id),onToggle:()=>c(r.id),onEdit:()=>s(`/mcp/servers/${r.id}`),onDelete:()=>f(r),onTryTool:d=>w({serverId:r.id,serverName:r.name,tool:d}),connect:o,disconnect:u,visibleTools:te(r.tool_manifest??[],t.search)},r.id))})]}),e.jsx(_,{page:i.page,totalPages:i.totalPages(y),onPageChange:i.setPage,total:y,pageSize:i.pageSize,onPageSizeChange:i.setPageSize})]}),h&&e.jsx("div",{className:"w-[380px] shrink-0 sticky top-0 max-h-screen overflow-y-auto",children:e.jsx(B,{serverId:h.serverId,serverName:h.serverName,tool:h.tool,onClose:()=>w(null)})})]}),e.jsx(z,{open:!!l,onClose:()=>f(null),onConfirm:E,title:"Delete MCP Server",description:e.jsxs(e.Fragment,{children:["Delete"," ",e.jsx("span",{className:"font-medium text-text-primary",children:l==null?void 0:l.name}),"? This will remove the server registration."]}),isPending:x.isPending,error:x.error})]})}export{Se as McpServersPage};
2
- //# sourceMappingURL=index-DBi9Q9Hw.js.map
1
+ import{a as p,j as e}from"./vendor-query-B2UbickB.js";import{u as L,a as M,b as D,c as I}from"./mcp-B1lc6nL4.js";import{E as R}from"./EmptyState-BcsfPq9T.js";import{C as z}from"./ConfirmDeleteModal-D9_1b4MW.js";import{P as k}from"./PageHeader-Bnt2iQQa.js";import{F,a as q,b as P}from"./FilterBar-Ck4K4rzu.js";import{S as _}from"./StickyPagination-BWhFSr2d.js";import{u as $}from"./useFilterParams-x-Dg0Vgz.js";import{S as A,T as B}from"./ToolTestPanel-3OcG18e5.js";import{R as O,a as b}from"./RowActions-Dg-Fsm5O.js";import{S as H}from"./StatusBadge-Bl3FXVmF.js";import{T as J}from"./ToolPill-DjvedZSn.js";import{p as G,al as Q,am as U,Q as W,q as V,P as X}from"./vendor-icons-Dj2F0Jrb.js";import{c as Y}from"./vendor-react-CXumBFUA.js";import"./index-DPJW96d2.js";import"./Modal-CSrxpXeM.js";import"./RunAsSelector-CvxGTNGT.js";import"./BotPicker-Dse2jW4b.js";import"./bots-cAzKkDtQ.js";import"./helpers-DzO-OGPe.js";function Z(s){const[t,a]=p.useState(()=>{try{const o=localStorage.getItem(s);if(o){const u=JSON.parse(o);if(Array.isArray(u))return new Set(u)}}catch{}return new Set}),i=p.useCallback(o=>{try{localStorage.setItem(s,JSON.stringify([...o]))}catch{}},[s]),n=p.useCallback(o=>{a(u=>{const x=new Set(u);return x.has(o)?x.delete(o):x.add(o),i(x),x})},[i]),m=p.useCallback(o=>t.has(o),[t]);return{expandedIds:t,toggle:n,isExpanded:m}}function K(s){var t,a;return!!((t=s.metadata)!=null&&t.builtin)||!!((a=s.transport_config)!=null&&a.builtin)}function ee(s,t){var n;if(!t)return!0;const a=t.toLowerCase();return s.name.toLowerCase().includes(a)||(n=s.description)!=null&&n.toLowerCase().includes(a)||(s.tags??[]).some(m=>m.toLowerCase().includes(a))?!0:(s.tool_manifest??[]).some(m=>{var o;return m.name.toLowerCase().includes(a)||((o=m.description)==null?void 0:o.toLowerCase().includes(a))})}function te(s,t){if(!t)return s;const a=t.toLowerCase();return s.filter(i=>{var n;return i.name.toLowerCase().includes(a)||((n=i.description)==null?void 0:n.toLowerCase().includes(a))})}function se({server:s,expanded:t,onToggle:a,onEdit:i,onDelete:n,onTryTool:m,connect:o,disconnect:u,visibleTools:x}){const l=s.tool_manifest??[],f=K(s),g=s.tags??[];return e.jsxs(e.Fragment,{children:[e.jsxs("tr",{onClick:l.length>0?a:void 0,className:`group/row border-b border-surface-border/50 transition-colors duration-100 ${l.length>0?"cursor-pointer row-hover":""}`,children:[e.jsx("td",{className:"px-6 py-2.5",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:`transition-transform duration-150 ${t?"rotate-90":""} ${l.length===0?"opacity-0":"text-text-tertiary"}`,children:e.jsx(G,{size:14})}),e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx(A,{name:s.name,serverId:s.id,short:!1}),l.length>0&&e.jsx("sup",{className:"text-[9px] font-normal text-accent/70",children:l.length})]}),g.length>0&&e.jsxs("div",{className:"flex gap-1 ml-auto shrink-0",children:[g.slice(0,3).map(c=>e.jsx("span",{className:"inline-block px-1.5 py-0 text-[9px] text-text-tertiary bg-surface-sunken rounded",children:c},c)),g.length>3&&e.jsx("span",{className:"text-[9px] text-text-quaternary",title:g.slice(3).join(", "),children:"…"})]})]})}),e.jsx("td",{className:"px-4 py-2.5 w-28 whitespace-nowrap",children:e.jsx(H,{status:s.status})}),e.jsx("td",{className:"px-4 py-2.5 w-16",children:e.jsxs(O,{children:[!f&&(s.status==="connected"?e.jsx(b,{icon:Q,title:"Disconnect server",onClick:()=>u.mutate(s.id)}):e.jsx(b,{icon:U,title:"Connect server",onClick:()=>o.mutate(s.id),colorClass:"text-text-tertiary hover:text-status-success"})),e.jsx(b,{icon:W,title:"Edit server",onClick:i}),!f&&e.jsx(b,{icon:V,title:"Delete server",onClick:n,colorClass:"text-text-tertiary hover:text-status-error"})]})})]}),t&&x.map(c=>e.jsxs("tr",{onClick:()=>m(c),className:"group/row cursor-pointer hover:bg-surface-hover/50 transition-colors border-b border-surface-border/15",children:[e.jsxs("td",{className:"pl-14 pr-6 py-2.5",children:[e.jsx(J,{name:c.name,size:"md"}),c.description&&e.jsx("p",{className:"text-[11px] leading-snug text-text-quaternary mt-0.5",children:c.description})]}),e.jsx("td",{className:"px-4 py-2.5 w-28"}),e.jsx("td",{className:"px-4 py-2.5 w-16",children:e.jsx("div",{className:"flex items-center justify-end",children:e.jsx("button",{onClick:h=>{h.stopPropagation(),m(c)},className:"opacity-0 group-hover/row:opacity-100 transition-opacity text-text-tertiary hover:text-accent",title:"Try tool",children:e.jsx(X,{className:"w-3.5 h-3.5",strokeWidth:1.5})})})})]},c.name))]})}function Se(){const s=Y(),{filters:t,setFilter:a,pagination:i}=$({filters:{status:"",search:"",tag:""}}),{data:n,isLoading:m}=L({status:t.status||void 0,search:t.search||void 0,tags:t.tag||void 0}),o=M(),u=D(),x=I(),[l,f]=p.useState(null),{expandedIds:g,toggle:c}=Z("lt:expanded:mcp-servers"),[h,w]=p.useState(null),j=(n==null?void 0:n.servers)??[],y=(n==null?void 0:n.total)??0,T=p.useMemo(()=>{const r=new Set;for(const d of j)for(const C of d.tags??[])r.add(C);return[...r].sort().map(d=>({value:d,label:d}))},[j]),v=p.useMemo(()=>t.search?j.filter(r=>ee(r,t.search)):j,[j,t.search]);p.useEffect(()=>{if(!t.search)return;const r=t.search.toLowerCase();for(const d of v)(d.tool_manifest??[]).some(S=>{var N;return S.name.toLowerCase().includes(r)||((N=S.description)==null?void 0:N.toLowerCase().includes(r))})&&!g.has(d.id)&&c(d.id)},[t.search,v]);const E=()=>{l&&x.mutate(l.id,{onSuccess:()=>f(null)})};return m?e.jsxs("div",{children:[e.jsx(k,{title:"Servers & Tools"}),e.jsx("div",{className:"animate-pulse space-y-0",children:Array.from({length:5}).map((r,d)=>e.jsx("div",{className:"h-14 border-b last:border-b-0 px-6 flex items-center",children:e.jsx("div",{className:"h-3 bg-surface-sunken rounded w-full"})},d))})]}):e.jsxs("div",{children:[e.jsx(k,{title:"Servers & Tools",docsHash:"#docs:dashboard.md:mcp-server-tools",actions:e.jsx("button",{onClick:()=>s("/mcp/servers/new"),className:"btn-primary text-xs",children:"Register Server"})}),e.jsx("p",{className:"text-sm text-text-secondary mb-6 max-w-2xl leading-relaxed",children:"Registered MCP servers and their available tools. Each server exposes tools that can be used by the MCP Tool Designer."}),e.jsxs(F,{children:[e.jsx(q,{label:"Search",value:t.search,onChange:r=>a("search",r),placeholder:"Server or tool name..."}),e.jsx(P,{label:"Tag",value:t.tag,onChange:r=>a("tag",r),options:T}),e.jsx(P,{label:"Status",value:t.status,onChange:r=>a("status",r),options:[{value:"registered",label:"Registered"},{value:"connected",label:"Connected"},{value:"error",label:"Error"},{value:"disconnected",label:"Disconnected"}]})]}),e.jsxs("div",{className:"flex gap-0 ",children:[e.jsxs("div",{className:`${h?"flex-1 min-w-0":"w-full"} transition-all`,children:[v.length===0?e.jsx(R,{title:"No servers found"}):e.jsxs("table",{className:"w-full",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b",children:[e.jsx("th",{className:"sticky top-[2.75rem] z-10 bg-surface px-6 py-3 text-left text-[10px] font-semibold uppercase tracking-widest text-text-tertiary",children:"Server / Tool"}),e.jsx("th",{className:"sticky top-[2.75rem] z-10 bg-surface px-4 py-3 text-left text-[10px] font-semibold uppercase tracking-widest text-text-tertiary w-28",children:"Status"}),e.jsx("th",{className:"sticky top-[2.75rem] z-10 bg-surface w-16"})]})}),e.jsx("tbody",{children:v.map(r=>e.jsx(se,{server:r,expanded:g.has(r.id),onToggle:()=>c(r.id),onEdit:()=>s(`/mcp/servers/${r.id}`),onDelete:()=>f(r),onTryTool:d=>w({serverId:r.id,serverName:r.name,tool:d}),connect:o,disconnect:u,visibleTools:te(r.tool_manifest??[],t.search)},r.id))})]}),e.jsx(_,{page:i.page,totalPages:i.totalPages(y),onPageChange:i.setPage,total:y,pageSize:i.pageSize,onPageSizeChange:i.setPageSize})]}),h&&e.jsx("div",{className:"w-[380px] shrink-0 sticky top-0 max-h-screen overflow-y-auto",children:e.jsx(B,{serverId:h.serverId,serverName:h.serverName,tool:h.tool,onClose:()=>w(null)})})]}),e.jsx(z,{open:!!l,onClose:()=>f(null),onConfirm:E,title:"Delete MCP Server",description:e.jsxs(e.Fragment,{children:["Delete"," ",e.jsx("span",{className:"font-medium text-text-primary",children:l==null?void 0:l.name}),"? This will remove the server registration."]}),isPending:x.isPending,error:x.error})]})}export{Se as McpServersPage};
2
+ //# sourceMappingURL=index-CgyucK0e.js.map