@hotmeshio/long-tail 0.7.2 → 0.7.4

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 (164) hide show
  1. package/dashboard/dist/assets/{AdminDashboard-rZDVS2G_.js → AdminDashboard-C9eE1VEp.js} +2 -2
  2. package/dashboard/dist/assets/{AdminDashboard-rZDVS2G_.js.map → AdminDashboard-C9eE1VEp.js.map} +1 -1
  3. package/dashboard/dist/assets/{AgentConfigPage-CbyyCjCT.js → AgentConfigPage-Ba8QfXM2.js} +2 -2
  4. package/dashboard/dist/assets/{AgentConfigPage-CbyyCjCT.js.map → AgentConfigPage-Ba8QfXM2.js.map} +1 -1
  5. package/dashboard/dist/assets/{AgentDetailPage-DMeHvidT.js → AgentDetailPage-DVmec0CP.js} +2 -2
  6. package/dashboard/dist/assets/{AgentDetailPage-DMeHvidT.js.map → AgentDetailPage-DVmec0CP.js.map} +1 -1
  7. package/dashboard/dist/assets/{AgentsPage-C8fKLxh-.js → AgentsPage-DNiCYMh3.js} +2 -2
  8. package/dashboard/dist/assets/{AgentsPage-C8fKLxh-.js.map → AgentsPage-DNiCYMh3.js.map} +1 -1
  9. package/dashboard/dist/assets/{AvailableEscalationsPage-CUHcybKU.js → AvailableEscalationsPage-gDIF8ocC.js} +2 -2
  10. package/dashboard/dist/assets/{AvailableEscalationsPage-CUHcybKU.js.map → AvailableEscalationsPage-gDIF8ocC.js.map} +1 -1
  11. package/dashboard/dist/assets/{BotPicker-DGhniNcy.js → BotPicker-3wBcBavT.js} +2 -2
  12. package/dashboard/dist/assets/{BotPicker-DGhniNcy.js.map → BotPicker-3wBcBavT.js.map} +1 -1
  13. package/dashboard/dist/assets/{CapabilitiesPage-ClfuW4ya.js → CapabilitiesPage-WoPkND2y.js} +2 -2
  14. package/dashboard/dist/assets/{CapabilitiesPage-ClfuW4ya.js.map → CapabilitiesPage-WoPkND2y.js.map} +1 -1
  15. package/dashboard/dist/assets/{CollapsibleSection-DnECdKEY.js → CollapsibleSection-Cx99mqNN.js} +2 -2
  16. package/dashboard/dist/assets/{CollapsibleSection-DnECdKEY.js.map → CollapsibleSection-Cx99mqNN.js.map} +1 -1
  17. package/dashboard/dist/assets/{CredentialsPage-DdZ-jyyc.js → CredentialsPage-DbNaoPbF.js} +2 -2
  18. package/dashboard/dist/assets/{CredentialsPage-DdZ-jyyc.js.map → CredentialsPage-DbNaoPbF.js.map} +1 -1
  19. package/dashboard/dist/assets/{CronLabel-CymxLvY0.js → CronLabel-DLW4_Zg4.js} +2 -2
  20. package/dashboard/dist/assets/{CronLabel-CymxLvY0.js.map → CronLabel-DLW4_Zg4.js.map} +1 -1
  21. package/dashboard/dist/assets/{CustomDurationPicker-8JHvVWD2.js → CustomDurationPicker-BRUFjkiu.js} +2 -2
  22. package/dashboard/dist/assets/{CustomDurationPicker-8JHvVWD2.js.map → CustomDurationPicker-BRUFjkiu.js.map} +1 -1
  23. package/dashboard/dist/assets/{ElapsedCell-BRZfw_Af.js → ElapsedCell-BtmDQaym.js} +2 -2
  24. package/dashboard/dist/assets/{ElapsedCell-BRZfw_Af.js.map → ElapsedCell-BtmDQaym.js.map} +1 -1
  25. package/dashboard/dist/assets/EscalationSchemaPage-Bm4yBEGN.js +9 -0
  26. package/dashboard/dist/assets/EscalationSchemaPage-Bm4yBEGN.js.map +1 -0
  27. package/dashboard/dist/assets/{EscalationsOverview-CiQO3ntf.js → EscalationsOverview-B3xZwTQA.js} +2 -2
  28. package/dashboard/dist/assets/{EscalationsOverview-CiQO3ntf.js.map → EscalationsOverview-B3xZwTQA.js.map} +1 -1
  29. package/dashboard/dist/assets/{EventTable-CLuAbba_.js → EventTable-Bh9FKXLI.js} +2 -2
  30. package/dashboard/dist/assets/{EventTable-CLuAbba_.js.map → EventTable-Bh9FKXLI.js.map} +1 -1
  31. package/dashboard/dist/assets/{GraphInvokePage-BFRi6Nny.js → GraphInvokePage-ov_ANlaE.js} +2 -2
  32. package/dashboard/dist/assets/{GraphInvokePage-BFRi6Nny.js.map → GraphInvokePage-ov_ANlaE.js.map} +1 -1
  33. package/dashboard/dist/assets/{HomePage-m1pnxilb.js → HomePage-D0DV6izb.js} +2 -2
  34. package/dashboard/dist/assets/{HomePage-m1pnxilb.js.map → HomePage-D0DV6izb.js.map} +1 -1
  35. package/dashboard/dist/assets/{ListToolbar-D4Y-M7wN.js → ListToolbar-FpcvqNkN.js} +2 -2
  36. package/dashboard/dist/assets/{ListToolbar-D4Y-M7wN.js.map → ListToolbar-FpcvqNkN.js.map} +1 -1
  37. package/dashboard/dist/assets/{McpOverview-mfJpETsW.js → McpOverview-DcuRiAff.js} +2 -2
  38. package/dashboard/dist/assets/{McpOverview-mfJpETsW.js.map → McpOverview-DcuRiAff.js.map} +1 -1
  39. package/dashboard/dist/assets/{McpQueryDetailPage-Cb99vI7v.js → McpQueryDetailPage-BcYl67KP.js} +2 -2
  40. package/dashboard/dist/assets/{McpQueryDetailPage-Cb99vI7v.js.map → McpQueryDetailPage-BcYl67KP.js.map} +1 -1
  41. package/dashboard/dist/assets/{McpQueryPage-CKKOxks0.js → McpQueryPage-C3GDzqZM.js} +2 -2
  42. package/dashboard/dist/assets/{McpQueryPage-CKKOxks0.js.map → McpQueryPage-C3GDzqZM.js.map} +1 -1
  43. package/dashboard/dist/assets/{McpRunDetailPage-CyTbHs0J.js → McpRunDetailPage-SzOyhDBW.js} +2 -2
  44. package/dashboard/dist/assets/{McpRunDetailPage-CyTbHs0J.js.map → McpRunDetailPage-SzOyhDBW.js.map} +1 -1
  45. package/dashboard/dist/assets/{McpRunsPage-MIwmK-Ky.js → McpRunsPage-BwgB6mRV.js} +2 -2
  46. package/dashboard/dist/assets/{McpRunsPage-MIwmK-Ky.js.map → McpRunsPage-BwgB6mRV.js.map} +1 -1
  47. package/dashboard/dist/assets/{OperationsPage-DPesph0U.js → OperationsPage-BCr21p8I.js} +2 -2
  48. package/dashboard/dist/assets/{OperationsPage-DPesph0U.js.map → OperationsPage-BCr21p8I.js.map} +1 -1
  49. package/dashboard/dist/assets/{OperatorDashboard-K1gzULr7.js → OperatorDashboard-DSXh-yYw.js} +2 -2
  50. package/dashboard/dist/assets/{OperatorDashboard-K1gzULr7.js.map → OperatorDashboard-DSXh-yYw.js.map} +1 -1
  51. package/dashboard/dist/assets/{ProcessDetailPage-DBIrY6Vd.js → ProcessDetailPage-iIB1rwEt.js} +2 -2
  52. package/dashboard/dist/assets/{ProcessDetailPage-DBIrY6Vd.js.map → ProcessDetailPage-iIB1rwEt.js.map} +1 -1
  53. package/dashboard/dist/assets/{ProcessesListPage-CrLGDCAD.js → ProcessesListPage-BrqWR2zr.js} +2 -2
  54. package/dashboard/dist/assets/{ProcessesListPage-CrLGDCAD.js.map → ProcessesListPage-BrqWR2zr.js.map} +1 -1
  55. package/dashboard/dist/assets/RoleDetailPage-DS37tJhq.js +11 -0
  56. package/dashboard/dist/assets/RoleDetailPage-DS37tJhq.js.map +1 -0
  57. package/dashboard/dist/assets/RolesPage-Bzp9FhAl.js +2 -0
  58. package/dashboard/dist/assets/{RolesPage-B0ZgjB2V.js.map → RolesPage-Bzp9FhAl.js.map} +1 -1
  59. package/dashboard/dist/assets/{RunAsSelector-DA0h41ml.js → RunAsSelector-DXbHRxQs.js} +2 -2
  60. package/dashboard/dist/assets/{RunAsSelector-DA0h41ml.js.map → RunAsSelector-DXbHRxQs.js.map} +1 -1
  61. package/dashboard/dist/assets/{StickyPagination-t5B71hwd.js → StickyPagination-D8XuMSWD.js} +2 -2
  62. package/dashboard/dist/assets/{StickyPagination-t5B71hwd.js.map → StickyPagination-D8XuMSWD.js.map} +1 -1
  63. package/dashboard/dist/assets/{StreamMessageDetail-CYFnZsYA.js → StreamMessageDetail-D5v95pmz.js} +2 -2
  64. package/dashboard/dist/assets/{StreamMessageDetail-CYFnZsYA.js.map → StreamMessageDetail-D5v95pmz.js.map} +1 -1
  65. package/dashboard/dist/assets/{SwimlaneTimeline-CY18gBek.js → SwimlaneTimeline-CUEf2R5R.js} +2 -2
  66. package/dashboard/dist/assets/{SwimlaneTimeline-CY18gBek.js.map → SwimlaneTimeline-CUEf2R5R.js.map} +1 -1
  67. package/dashboard/dist/assets/{TaskDetailPage-B9owzuhV.js → TaskDetailPage-BJvKNwEe.js} +2 -2
  68. package/dashboard/dist/assets/{TaskDetailPage-B9owzuhV.js.map → TaskDetailPage-BJvKNwEe.js.map} +1 -1
  69. package/dashboard/dist/assets/{TasksListPage-Dlsu7cWG.js → TasksListPage-CM7BWh_h.js} +2 -2
  70. package/dashboard/dist/assets/{TasksListPage-Dlsu7cWG.js.map → TasksListPage-CM7BWh_h.js.map} +1 -1
  71. package/dashboard/dist/assets/{TimeAgo-CSzifQXB.js → TimeAgo-D1K7xKq5.js} +2 -2
  72. package/dashboard/dist/assets/{TimeAgo-CSzifQXB.js.map → TimeAgo-D1K7xKq5.js.map} +1 -1
  73. package/dashboard/dist/assets/{TimestampCell-CIxgN57O.js → TimestampCell-7G0echgP.js} +2 -2
  74. package/dashboard/dist/assets/{TimestampCell-CIxgN57O.js.map → TimestampCell-7G0echgP.js.map} +1 -1
  75. package/dashboard/dist/assets/{ToolTestPanel-Bw844EW3.js → ToolTestPanel-LxuJvURK.js} +2 -2
  76. package/dashboard/dist/assets/{ToolTestPanel-Bw844EW3.js.map → ToolTestPanel-LxuJvURK.js.map} +1 -1
  77. package/dashboard/dist/assets/{TopicDetailPage-HuDx2oAW.js → TopicDetailPage-JvAX6rrR.js} +2 -2
  78. package/dashboard/dist/assets/{TopicDetailPage-HuDx2oAW.js.map → TopicDetailPage-JvAX6rrR.js.map} +1 -1
  79. package/dashboard/dist/assets/{TopicsPage-CAG0RhAK.js → TopicsPage-tFT2AcTz.js} +2 -2
  80. package/dashboard/dist/assets/{TopicsPage-CAG0RhAK.js.map → TopicsPage-tFT2AcTz.js.map} +1 -1
  81. package/dashboard/dist/assets/{UserName-CoGYeig8.js → UserName-Djz0nmaZ.js} +2 -2
  82. package/dashboard/dist/assets/{UserName-CoGYeig8.js.map → UserName-Djz0nmaZ.js.map} +1 -1
  83. package/dashboard/dist/assets/{WorkflowExecutionPage-Dhb9EWgI.js → WorkflowExecutionPage-f53hilbI.js} +2 -2
  84. package/dashboard/dist/assets/{WorkflowExecutionPage-Dhb9EWgI.js.map → WorkflowExecutionPage-f53hilbI.js.map} +1 -1
  85. package/dashboard/dist/assets/{WorkflowsDashboard-bJ6Zebfv.js → WorkflowsDashboard-DM9Xe665.js} +2 -2
  86. package/dashboard/dist/assets/{WorkflowsDashboard-bJ6Zebfv.js.map → WorkflowsDashboard-DM9Xe665.js.map} +1 -1
  87. package/dashboard/dist/assets/{WorkflowsOverview-B8262fVx.js → WorkflowsOverview-CUGSrx9N.js} +2 -2
  88. package/dashboard/dist/assets/{WorkflowsOverview-B8262fVx.js.map → WorkflowsOverview-CUGSrx9N.js.map} +1 -1
  89. package/dashboard/dist/assets/{YamlWorkflowDetailPage-DhW3q2cO.js → YamlWorkflowDetailPage-B1_yqxAw.js} +2 -2
  90. package/dashboard/dist/assets/{YamlWorkflowDetailPage-DhW3q2cO.js.map → YamlWorkflowDetailPage-B1_yqxAw.js.map} +1 -1
  91. package/dashboard/dist/assets/{YamlWorkflowsPage-C8hBjSn_.js → YamlWorkflowsPage-NtGvqiu7.js} +2 -2
  92. package/dashboard/dist/assets/{YamlWorkflowsPage-C8hBjSn_.js.map → YamlWorkflowsPage-NtGvqiu7.js.map} +1 -1
  93. package/dashboard/dist/assets/{agents-j2YErVp4.js → agents-tML6AjDj.js} +2 -2
  94. package/dashboard/dist/assets/{agents-j2YErVp4.js.map → agents-tML6AjDj.js.map} +1 -1
  95. package/dashboard/dist/assets/{bots-CD8Bl5pL.js → bots-Cb0WTwhY.js} +2 -2
  96. package/dashboard/dist/assets/{bots-CD8Bl5pL.js.map → bots-Cb0WTwhY.js.map} +1 -1
  97. package/dashboard/dist/assets/{capabilities-Dz190EAa.js → capabilities-BGZogsi_.js} +2 -2
  98. package/dashboard/dist/assets/{capabilities-Dz190EAa.js.map → capabilities-BGZogsi_.js.map} +1 -1
  99. package/dashboard/dist/assets/{controlplane-CkUHGPA3.js → controlplane-B7VJTlZD.js} +2 -2
  100. package/dashboard/dist/assets/{controlplane-CkUHGPA3.js.map → controlplane-B7VJTlZD.js.map} +1 -1
  101. package/dashboard/dist/assets/{escalation-BXTwi4J1.js → escalation-Bl-SQV_u.js} +2 -2
  102. package/dashboard/dist/assets/{escalation-BXTwi4J1.js.map → escalation-Bl-SQV_u.js.map} +1 -1
  103. package/dashboard/dist/assets/{escalation-columns-GxxwSbDk.js → escalation-columns-BlJOswRx.js} +2 -2
  104. package/dashboard/dist/assets/{escalation-columns-GxxwSbDk.js.map → escalation-columns-BlJOswRx.js.map} +1 -1
  105. package/dashboard/dist/assets/{index-NfVWOFbF.js → index--WeZDfeN.js} +2 -2
  106. package/dashboard/dist/assets/{index-NfVWOFbF.js.map → index--WeZDfeN.js.map} +1 -1
  107. package/dashboard/dist/assets/{index-BK3PVYcd.js → index-0o71lRuY.js} +2 -2
  108. package/dashboard/dist/assets/{index-BK3PVYcd.js.map → index-0o71lRuY.js.map} +1 -1
  109. package/dashboard/dist/assets/{index-DGKgXObc.js → index-3A_5CL81.js} +2 -2
  110. package/dashboard/dist/assets/{index-DGKgXObc.js.map → index-3A_5CL81.js.map} +1 -1
  111. package/dashboard/dist/assets/{index-DTrcYOM2.js → index-BorpZbZA.js} +2 -2
  112. package/dashboard/dist/assets/{index-DTrcYOM2.js.map → index-BorpZbZA.js.map} +1 -1
  113. package/dashboard/dist/assets/{index-BkwsJ-0v.js → index-CBv3UxF2.js} +2 -2
  114. package/dashboard/dist/assets/{index-BkwsJ-0v.js.map → index-CBv3UxF2.js.map} +1 -1
  115. package/dashboard/dist/assets/{index-CkL8bpdH.js → index-D0-8byNu.js} +2 -2
  116. package/dashboard/dist/assets/{index-CkL8bpdH.js.map → index-D0-8byNu.js.map} +1 -1
  117. package/dashboard/dist/assets/{index-qT7eB_Hk.js → index-DcbEIXit.js} +2 -2
  118. package/dashboard/dist/assets/{index-qT7eB_Hk.js.map → index-DcbEIXit.js.map} +1 -1
  119. package/dashboard/dist/assets/{index-YliQ4kW_.js → index-DfDfJivY.js} +2 -2
  120. package/dashboard/dist/assets/{index-YliQ4kW_.js.map → index-DfDfJivY.js.map} +1 -1
  121. package/dashboard/dist/assets/{index-D-7W2AHB.js → index-Dgw1KKpq.js} +3 -3
  122. package/dashboard/dist/assets/{index-D-7W2AHB.js.map → index-Dgw1KKpq.js.map} +1 -1
  123. package/dashboard/dist/assets/{index-CoGkgm9-.js → index-Il_g7kw5.js} +2 -2
  124. package/dashboard/dist/assets/{index-CoGkgm9-.js.map → index-Il_g7kw5.js.map} +1 -1
  125. package/dashboard/dist/assets/{index-CaMVn0kW.js → index-SCrD3l-K.js} +2 -2
  126. package/dashboard/dist/assets/{index-CaMVn0kW.js.map → index-SCrD3l-K.js.map} +1 -1
  127. package/dashboard/dist/assets/{index-n-lZY5S6.js → index-TiKh2Ctj.js} +2 -2
  128. package/dashboard/dist/assets/{index-n-lZY5S6.js.map → index-TiKh2Ctj.js.map} +1 -1
  129. package/dashboard/dist/assets/{index-eLRh-2NW.js → index-e97M6GoI.js} +2 -2
  130. package/dashboard/dist/assets/{index-eLRh-2NW.js.map → index-e97M6GoI.js.map} +1 -1
  131. package/dashboard/dist/assets/{knowledge-CSAbLtk7.js → knowledge-CDzw4E6q.js} +2 -2
  132. package/dashboard/dist/assets/{knowledge-CSAbLtk7.js.map → knowledge-CDzw4E6q.js.map} +1 -1
  133. package/dashboard/dist/assets/{mcp-D0Ha3aEo.js → mcp-D_-NQtnG.js} +2 -2
  134. package/dashboard/dist/assets/{mcp-D0Ha3aEo.js.map → mcp-D_-NQtnG.js.map} +1 -1
  135. package/dashboard/dist/assets/{mcp-query-BySmvmuS.js → mcp-query-BqZXdf9A.js} +2 -2
  136. package/dashboard/dist/assets/{mcp-query-BySmvmuS.js.map → mcp-query-BqZXdf9A.js.map} +1 -1
  137. package/dashboard/dist/assets/{pipelines-DiqWgxJd.js → pipelines-CNLhgj8b.js} +2 -2
  138. package/dashboard/dist/assets/{pipelines-DiqWgxJd.js.map → pipelines-CNLhgj8b.js.map} +1 -1
  139. package/dashboard/dist/assets/{roles-BdtnzLsL.js → roles-CFD2eYap.js} +2 -2
  140. package/dashboard/dist/assets/{roles-BdtnzLsL.js.map → roles-CFD2eYap.js.map} +1 -1
  141. package/dashboard/dist/assets/{tasks-DYCUi5nZ.js → tasks-DcSvF636.js} +2 -2
  142. package/dashboard/dist/assets/{tasks-DYCUi5nZ.js.map → tasks-DcSvF636.js.map} +1 -1
  143. package/dashboard/dist/assets/{topics-CA7i8ymr.js → topics-DI8TFSZv.js} +2 -2
  144. package/dashboard/dist/assets/{topics-CA7i8ymr.js.map → topics-DI8TFSZv.js.map} +1 -1
  145. package/dashboard/dist/assets/{useEventHooks-SfWdyc5L.js → useEventHooks-DcIgMDh3.js} +2 -2
  146. package/dashboard/dist/assets/{useEventHooks-SfWdyc5L.js.map → useEventHooks-DcIgMDh3.js.map} +1 -1
  147. package/dashboard/dist/assets/{useNamespace-CZUsk5Vv.js → useNamespace-C88ZxGoX.js} +2 -2
  148. package/dashboard/dist/assets/{useNamespace-CZUsk5Vv.js.map → useNamespace-C88ZxGoX.js.map} +1 -1
  149. package/dashboard/dist/assets/{useYamlActivityEvents-DKQ5dREx.js → useYamlActivityEvents-D2-yVjJ7.js} +2 -2
  150. package/dashboard/dist/assets/{useYamlActivityEvents-DKQ5dREx.js.map → useYamlActivityEvents-D2-yVjJ7.js.map} +1 -1
  151. package/dashboard/dist/assets/{users-BxKf5dAX.js → users-C0WV36X8.js} +2 -2
  152. package/dashboard/dist/assets/{users-BxKf5dAX.js.map → users-C0WV36X8.js.map} +1 -1
  153. package/dashboard/dist/assets/{workflows-DNPQ-j-7.js → workflows-CkPv7xk-.js} +2 -2
  154. package/dashboard/dist/assets/{workflows-DNPQ-j-7.js.map → workflows-CkPv7xk-.js.map} +1 -1
  155. package/dashboard/dist/assets/{yaml-workflows-CA8BrFxc.js → yaml-workflows-BjrMQLTK.js} +2 -2
  156. package/dashboard/dist/assets/{yaml-workflows-CA8BrFxc.js.map → yaml-workflows-BjrMQLTK.js.map} +1 -1
  157. package/dashboard/dist/index.html +1 -1
  158. package/docs/dashboard.md +65 -23
  159. package/package.json +2 -2
  160. package/dashboard/dist/assets/EscalationSchemaPage-Do2iPKUl.js +0 -9
  161. package/dashboard/dist/assets/EscalationSchemaPage-Do2iPKUl.js.map +0 -1
  162. package/dashboard/dist/assets/RoleDetailPage-7j6Mk780.js +0 -11
  163. package/dashboard/dist/assets/RoleDetailPage-7j6Mk780.js.map +0 -1
  164. package/dashboard/dist/assets/RolesPage-B0ZgjB2V.js +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"workflows-DNPQ-j-7.js","sources":["../../src/api/workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { ActiveWorker, CronScheduleEntry, DiscoveredWorkflow, LTJob, LTWorkflowConfig, WorkflowExecution } from './types';\n\nexport function useActiveWorkers() {\n return useQuery<ActiveWorker[]>({\n queryKey: ['activeWorkers'],\n queryFn: async () => {\n const res = await apiFetch<{ workers: ActiveWorker[] }>('/workflows/workers');\n return res.workers;\n },\n });\n}\n\nexport function useDiscoveredWorkflows() {\n return useQuery<DiscoveredWorkflow[]>({\n queryKey: ['discoveredWorkflows'],\n queryFn: async () => {\n const res = await apiFetch<{ workflows: DiscoveredWorkflow[] }>('/workflows/discovered');\n return res.workflows;\n },\n });\n}\n\nexport function useWorkflowConfigs() {\n return useQuery<LTWorkflowConfig[]>({\n queryKey: ['workflowConfigs'],\n queryFn: async () => {\n const res = await apiFetch<{ workflows: LTWorkflowConfig[] }>('/workflows/config');\n return res.workflows;\n },\n });\n}\n\nexport function useCronStatus() {\n return useQuery<CronScheduleEntry[]>({\n queryKey: ['cronStatus'],\n queryFn: async () => {\n const res = await apiFetch<{ schedules: CronScheduleEntry[] }>('/workflows/cron/status');\n return res.schedules;\n },\n });\n}\n\nexport function useWorkflowExecution(workflowId: string) {\n return useQuery<WorkflowExecution>({\n queryKey: ['workflowExecution', workflowId],\n queryFn: () =>\n apiFetch(`/workflow-states/${workflowId}/execution`),\n enabled: !!workflowId,\n });\n}\n\nexport function useWorkflowState(workflowId: string) {\n return useQuery<{ workflow_id: string; state: Record<string, unknown> }>({\n queryKey: ['workflowState', workflowId],\n queryFn: () => apiFetch(`/workflow-states/${workflowId}/state`),\n enabled: !!workflowId,\n });\n}\n\nexport function useJobs(filters: {\n limit?: number;\n offset?: number;\n entity?: string;\n search?: string;\n status?: string;\n sort_by?: string;\n order?: string;\n registered?: string;\n namespace?: string;\n}, options?: { enabled?: boolean }) {\n const params = new URLSearchParams();\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n if (filters.entity) params.set('entity', filters.entity);\n if (filters.search) params.set('search', filters.search);\n if (filters.status) params.set('status', filters.status);\n if (filters.sort_by) params.set('sort_by', filters.sort_by);\n if (filters.order) params.set('order', filters.order);\n if (filters.registered) params.set('registered', filters.registered);\n if (filters.namespace) params.set('namespace', filters.namespace);\n\n return useQuery<{ jobs: LTJob[]; total: number }>({\n queryKey: ['jobs', filters],\n queryFn: () => apiFetch(`/workflow-states/jobs?${params}`),\n enabled: options?.enabled ?? true,\n });\n}\n\nexport function useTerminateWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (workflowId: string) =>\n apiFetch(`/workflows/${workflowId}/terminate`, { method: 'POST' }),\n onSuccess: (_data, workflowId) => {\n queryClient.invalidateQueries({ queryKey: ['workflowExecution', workflowId], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['jobs'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpsertWorkflowConfig() {\n const queryClient = useQueryClient();\n return useMutation<\n LTWorkflowConfig,\n Error,\n {\n workflow_type: string;\n description?: string | null;\n\n invocable?: boolean;\n task_queue?: string | null;\n default_role?: string;\n roles?: string[];\n invocation_roles?: string[];\n consumes?: string[];\n envelope_schema?: Record<string, unknown> | null;\n resolver_schema?: Record<string, unknown> | null;\n cron_schedule?: string | null;\n execute_as?: string | null;\n }\n >({\n mutationFn: ({ workflow_type, ...body }) =>\n apiFetch(`/workflows/${encodeURIComponent(workflow_type)}/config`, {\n method: 'PUT',\n body: JSON.stringify(body),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['workflowConfigs'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteWorkflowConfig() {\n const queryClient = useQueryClient();\n return useMutation<{ deleted: boolean; workflow_type: string }, Error, string>({\n mutationFn: (workflowType) =>\n apiFetch(`/workflows/${encodeURIComponent(workflowType)}/config`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['workflowConfigs'], refetchType: 'all' });\n },\n });\n}\n\nexport function useSetCronSchedule() {\n const queryClient = useQueryClient();\n return useMutation<\n LTWorkflowConfig,\n Error,\n { config: LTWorkflowConfig; cron_schedule: string | null; envelope_schema?: Record<string, unknown> | null }\n >({\n mutationFn: ({ config, cron_schedule, envelope_schema }) =>\n apiFetch(`/workflows/${encodeURIComponent(config.workflow_type)}/config`, {\n method: 'PUT',\n body: JSON.stringify({\n ...config,\n cron_schedule,\n ...(envelope_schema !== undefined ? { envelope_schema } : {}),\n }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['workflowConfigs'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['cronStatus'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeWorkflow() {\n const queryClient = useQueryClient();\n return useMutation<\n { workflowId: string; message: string },\n Error,\n { workflowType: string; data: Record<string, unknown>; metadata?: Record<string, unknown>; execute_as?: string }\n >({\n mutationFn: ({ workflowType, data, metadata, execute_as }) =>\n apiFetch(`/workflows/${workflowType}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, metadata, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['tasks'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['jobs'], refetchType: 'all' });\n },\n });\n}\n"],"names":["useActiveWorkers","useQuery","apiFetch","useDiscoveredWorkflows","useWorkflowConfigs","useCronStatus","useWorkflowExecution","workflowId","useJobs","filters","options","params","useTerminateWorkflow","queryClient","useQueryClient","useMutation","_data","useUpsertWorkflowConfig","workflow_type","body","useDeleteWorkflowConfig","workflowType","useInvokeWorkflow","data","metadata","execute_as"],"mappings":"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"}
1
+ {"version":3,"file":"workflows-CkPv7xk-.js","sources":["../../src/api/workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { ActiveWorker, CronScheduleEntry, DiscoveredWorkflow, LTJob, LTWorkflowConfig, WorkflowExecution } from './types';\n\nexport function useActiveWorkers() {\n return useQuery<ActiveWorker[]>({\n queryKey: ['activeWorkers'],\n queryFn: async () => {\n const res = await apiFetch<{ workers: ActiveWorker[] }>('/workflows/workers');\n return res.workers;\n },\n });\n}\n\nexport function useDiscoveredWorkflows() {\n return useQuery<DiscoveredWorkflow[]>({\n queryKey: ['discoveredWorkflows'],\n queryFn: async () => {\n const res = await apiFetch<{ workflows: DiscoveredWorkflow[] }>('/workflows/discovered');\n return res.workflows;\n },\n });\n}\n\nexport function useWorkflowConfigs() {\n return useQuery<LTWorkflowConfig[]>({\n queryKey: ['workflowConfigs'],\n queryFn: async () => {\n const res = await apiFetch<{ workflows: LTWorkflowConfig[] }>('/workflows/config');\n return res.workflows;\n },\n });\n}\n\nexport function useCronStatus() {\n return useQuery<CronScheduleEntry[]>({\n queryKey: ['cronStatus'],\n queryFn: async () => {\n const res = await apiFetch<{ schedules: CronScheduleEntry[] }>('/workflows/cron/status');\n return res.schedules;\n },\n });\n}\n\nexport function useWorkflowExecution(workflowId: string) {\n return useQuery<WorkflowExecution>({\n queryKey: ['workflowExecution', workflowId],\n queryFn: () =>\n apiFetch(`/workflow-states/${workflowId}/execution`),\n enabled: !!workflowId,\n });\n}\n\nexport function useWorkflowState(workflowId: string) {\n return useQuery<{ workflow_id: string; state: Record<string, unknown> }>({\n queryKey: ['workflowState', workflowId],\n queryFn: () => apiFetch(`/workflow-states/${workflowId}/state`),\n enabled: !!workflowId,\n });\n}\n\nexport function useJobs(filters: {\n limit?: number;\n offset?: number;\n entity?: string;\n search?: string;\n status?: string;\n sort_by?: string;\n order?: string;\n registered?: string;\n namespace?: string;\n}, options?: { enabled?: boolean }) {\n const params = new URLSearchParams();\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n if (filters.entity) params.set('entity', filters.entity);\n if (filters.search) params.set('search', filters.search);\n if (filters.status) params.set('status', filters.status);\n if (filters.sort_by) params.set('sort_by', filters.sort_by);\n if (filters.order) params.set('order', filters.order);\n if (filters.registered) params.set('registered', filters.registered);\n if (filters.namespace) params.set('namespace', filters.namespace);\n\n return useQuery<{ jobs: LTJob[]; total: number }>({\n queryKey: ['jobs', filters],\n queryFn: () => apiFetch(`/workflow-states/jobs?${params}`),\n enabled: options?.enabled ?? true,\n });\n}\n\nexport function useTerminateWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (workflowId: string) =>\n apiFetch(`/workflows/${workflowId}/terminate`, { method: 'POST' }),\n onSuccess: (_data, workflowId) => {\n queryClient.invalidateQueries({ queryKey: ['workflowExecution', workflowId], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['jobs'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpsertWorkflowConfig() {\n const queryClient = useQueryClient();\n return useMutation<\n LTWorkflowConfig,\n Error,\n {\n workflow_type: string;\n description?: string | null;\n\n invocable?: boolean;\n task_queue?: string | null;\n default_role?: string;\n roles?: string[];\n invocation_roles?: string[];\n consumes?: string[];\n envelope_schema?: Record<string, unknown> | null;\n resolver_schema?: Record<string, unknown> | null;\n cron_schedule?: string | null;\n execute_as?: string | null;\n }\n >({\n mutationFn: ({ workflow_type, ...body }) =>\n apiFetch(`/workflows/${encodeURIComponent(workflow_type)}/config`, {\n method: 'PUT',\n body: JSON.stringify(body),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['workflowConfigs'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteWorkflowConfig() {\n const queryClient = useQueryClient();\n return useMutation<{ deleted: boolean; workflow_type: string }, Error, string>({\n mutationFn: (workflowType) =>\n apiFetch(`/workflows/${encodeURIComponent(workflowType)}/config`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['workflowConfigs'], refetchType: 'all' });\n },\n });\n}\n\nexport function useSetCronSchedule() {\n const queryClient = useQueryClient();\n return useMutation<\n LTWorkflowConfig,\n Error,\n { config: LTWorkflowConfig; cron_schedule: string | null; envelope_schema?: Record<string, unknown> | null }\n >({\n mutationFn: ({ config, cron_schedule, envelope_schema }) =>\n apiFetch(`/workflows/${encodeURIComponent(config.workflow_type)}/config`, {\n method: 'PUT',\n body: JSON.stringify({\n ...config,\n cron_schedule,\n ...(envelope_schema !== undefined ? { envelope_schema } : {}),\n }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['workflowConfigs'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['cronStatus'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeWorkflow() {\n const queryClient = useQueryClient();\n return useMutation<\n { workflowId: string; message: string },\n Error,\n { workflowType: string; data: Record<string, unknown>; metadata?: Record<string, unknown>; execute_as?: string }\n >({\n mutationFn: ({ workflowType, data, metadata, execute_as }) =>\n apiFetch(`/workflows/${workflowType}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, metadata, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['tasks'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['jobs'], refetchType: 'all' });\n },\n });\n}\n"],"names":["useActiveWorkers","useQuery","apiFetch","useDiscoveredWorkflows","useWorkflowConfigs","useCronStatus","useWorkflowExecution","workflowId","useJobs","filters","options","params","useTerminateWorkflow","queryClient","useQueryClient","useMutation","_data","useUpsertWorkflowConfig","workflow_type","body","useDeleteWorkflowConfig","workflowType","useInvokeWorkflow","data","metadata","execute_as"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{u as l,b as a,c as s}from"./vendor-query-B2UbickB.js";import{d as r}from"./index-D-7W2AHB.js";function f(e={}){const o=new URLSearchParams;return e.status&&o.set("status",e.status),e.graph_topic&&o.set("graph_topic",e.graph_topic),e.app_id&&o.set("app_id",e.app_id),e.search&&o.set("search",e.search),e.set_id&&o.set("set_id",e.set_id),e.limit&&o.set("limit",String(e.limit)),e.offset!==void 0&&o.set("offset",String(e.offset)),l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows?${o}`)})}function m(){return l({queryKey:["yamlWorkflowAppIds"],queryFn:()=>r("/yaml-workflows/app-ids")})}function c(e){return l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows/${e}`),enabled:!!e})}function w(){const e=a();return s({mutationFn:o=>r("/yaml-workflows",{method:"POST",body:JSON.stringify(o)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function k(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/deploy`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function p(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/activate`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function d(){const e=a();return s({mutationFn:({id:o,data:t,sync:n,execute_as:u})=>r(`/yaml-workflows/${o}/invoke`,{method:"POST",body:JSON.stringify({data:t,sync:n,...u?{execute_as:u}:{}})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function h(){const e=a();return s({mutationFn:({id:o,task_queue:t,compilation_feedback:n})=>r(`/yaml-workflows/${o}/regenerate`,{method:"POST",body:JSON.stringify({task_queue:t,compilation_feedback:n})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function q(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/archive`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function W(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/restore`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"}),e.invalidateQueries({queryKey:["yamlWorkflow"],refetchType:"all"})}})}function S(){const e=a();return s({mutationFn:({id:o,...t})=>r(`/yaml-workflows/${o}`,{method:"PUT",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function v(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function T(e){return l({queryKey:["yamlWorkflows",e,"versions"],queryFn:()=>r(`/yaml-workflows/${e}/versions`),enabled:!!e})}function F(e,o){return l({queryKey:["yamlWorkflows",e,"versions",o],queryFn:()=>r(`/yaml-workflows/${e}/versions/${o}`),enabled:!!e&&o!==null})}export{m as a,S as b,c,T as d,k as e,p as f,q as g,W as h,v as i,h as j,F as k,d as l,w as m,f as u};
2
- //# sourceMappingURL=yaml-workflows-CA8BrFxc.js.map
1
+ import{u as l,b as a,c as s}from"./vendor-query-B2UbickB.js";import{d as r}from"./index-Dgw1KKpq.js";function f(e={}){const o=new URLSearchParams;return e.status&&o.set("status",e.status),e.graph_topic&&o.set("graph_topic",e.graph_topic),e.app_id&&o.set("app_id",e.app_id),e.search&&o.set("search",e.search),e.set_id&&o.set("set_id",e.set_id),e.limit&&o.set("limit",String(e.limit)),e.offset!==void 0&&o.set("offset",String(e.offset)),l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows?${o}`)})}function m(){return l({queryKey:["yamlWorkflowAppIds"],queryFn:()=>r("/yaml-workflows/app-ids")})}function c(e){return l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows/${e}`),enabled:!!e})}function w(){const e=a();return s({mutationFn:o=>r("/yaml-workflows",{method:"POST",body:JSON.stringify(o)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function k(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/deploy`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function p(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/activate`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function d(){const e=a();return s({mutationFn:({id:o,data:t,sync:n,execute_as:u})=>r(`/yaml-workflows/${o}/invoke`,{method:"POST",body:JSON.stringify({data:t,sync:n,...u?{execute_as:u}:{}})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function h(){const e=a();return s({mutationFn:({id:o,task_queue:t,compilation_feedback:n})=>r(`/yaml-workflows/${o}/regenerate`,{method:"POST",body:JSON.stringify({task_queue:t,compilation_feedback:n})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function q(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/archive`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function W(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/restore`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"}),e.invalidateQueries({queryKey:["yamlWorkflow"],refetchType:"all"})}})}function S(){const e=a();return s({mutationFn:({id:o,...t})=>r(`/yaml-workflows/${o}`,{method:"PUT",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function v(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function T(e){return l({queryKey:["yamlWorkflows",e,"versions"],queryFn:()=>r(`/yaml-workflows/${e}/versions`),enabled:!!e})}function F(e,o){return l({queryKey:["yamlWorkflows",e,"versions",o],queryFn:()=>r(`/yaml-workflows/${e}/versions/${o}`),enabled:!!e&&o!==null})}export{m as a,S as b,c,T as d,k as e,p as f,q as g,W as h,v as i,h as j,F as k,d as l,w as m,f as u};
2
+ //# sourceMappingURL=yaml-workflows-BjrMQLTK.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"yaml-workflows-CA8BrFxc.js","sources":["../../src/api/yaml-workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { LTYamlWorkflowRecord, LTYamlWorkflowStatus, LTYamlWorkflowVersion } from './types';\n\ninterface YamlWorkflowListResponse {\n workflows: LTYamlWorkflowRecord[];\n total: number;\n}\n\ninterface YamlWorkflowFilters {\n status?: LTYamlWorkflowStatus;\n graph_topic?: string;\n app_id?: string;\n search?: string;\n set_id?: string;\n limit?: number;\n offset?: number;\n}\n\nexport function useYamlWorkflows(filters: YamlWorkflowFilters = {}) {\n const params = new URLSearchParams();\n if (filters.status) params.set('status', filters.status);\n if (filters.graph_topic) params.set('graph_topic', filters.graph_topic);\n if (filters.app_id) params.set('app_id', filters.app_id);\n if (filters.search) params.set('search', filters.search);\n if (filters.set_id) params.set('set_id', filters.set_id);\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', filters],\n queryFn: () => apiFetch(`/yaml-workflows?${params}`),\n });\n}\n\nexport function useYamlWorkflowAppIds() {\n return useQuery<{ app_ids: string[] }>({\n queryKey: ['yamlWorkflowAppIds'],\n queryFn: () => apiFetch('/yaml-workflows/app-ids'),\n });\n}\n\nexport function useYamlWorkflowByTopic(graphTopic: string | undefined, appId?: string) {\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', 'byTopic', graphTopic, appId],\n queryFn: () => {\n const params = new URLSearchParams({ graph_topic: graphTopic!, limit: '1' });\n if (appId) params.set('app_id', appId);\n return apiFetch(`/yaml-workflows?${params}`);\n },\n enabled: !!graphTopic,\n });\n}\n\nexport function useYamlWorkflow(id: string) {\n return useQuery<LTYamlWorkflowRecord>({\n queryKey: ['yamlWorkflows', id],\n queryFn: () => apiFetch(`/yaml-workflows/${id}`),\n enabled: !!id,\n });\n}\n\nexport function useCreateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (input: {\n workflow_id: string;\n task_queue: string;\n workflow_name: string;\n name: string;\n description?: string;\n app_id?: string;\n subscribes?: string;\n tags?: string[];\n compilation_feedback?: string;\n }) =>\n apiFetch<LTYamlWorkflowRecord>('/yaml-workflows', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeployYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/deploy`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useActivateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/activate`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, data, sync, execute_as }: { id: string; data: Record<string, unknown>; sync?: boolean; execute_as?: string }) =>\n apiFetch<{ result?: unknown; job_id?: string }>(`/yaml-workflows/${id}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, sync, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRegenerateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, task_queue, compilation_feedback }: { id: string; task_queue?: string; compilation_feedback?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/regenerate`, {\n method: 'POST',\n body: JSON.stringify({ task_queue, compilation_feedback }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useArchiveYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/archive`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRestoreYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/restore`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflow'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpdateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, ...updates }: { id: string; yaml_content?: string; name?: string; description?: string; input_schema?: Record<string, unknown>; output_schema?: Record<string, unknown>; tags?: string[]; app_id?: string; graph_topic?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}`, {\n method: 'PUT',\n body: JSON.stringify(updates),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<{ deleted: boolean }>(`/yaml-workflows/${id}`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Cron scheduling ─────────────────────────────────────────────\n\nexport function useSetYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, cron_schedule, cron_envelope, execute_as }: {\n id: string;\n cron_schedule: string;\n cron_envelope?: Record<string, unknown> | null;\n execute_as?: string | null;\n }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'PUT',\n body: JSON.stringify({ cron_schedule, cron_envelope, execute_as }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useClearYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Version history ─────────────────────────────────────────────\n\nexport function useYamlWorkflowVersions(id: string) {\n return useQuery<{ versions: LTYamlWorkflowVersion[]; total: number }>({\n queryKey: ['yamlWorkflows', id, 'versions'],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions`),\n enabled: !!id,\n });\n}\n\nexport function useYamlWorkflowVersion(id: string, version: number | null) {\n return useQuery<LTYamlWorkflowVersion>({\n queryKey: ['yamlWorkflows', id, 'versions', version],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions/${version}`),\n enabled: !!id && version !== null,\n });\n}\n"],"names":["useYamlWorkflows","filters","params","useQuery","apiFetch","useYamlWorkflowAppIds","useYamlWorkflow","id","useCreateYamlWorkflow","queryClient","useQueryClient","useMutation","input","useDeployYamlWorkflow","useActivateYamlWorkflow","useInvokeYamlWorkflow","data","sync","execute_as","useRegenerateYamlWorkflow","task_queue","compilation_feedback","useArchiveYamlWorkflow","useRestoreYamlWorkflow","useUpdateYamlWorkflow","updates","useDeleteYamlWorkflow","useYamlWorkflowVersions","useYamlWorkflowVersion","version"],"mappings":"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"}
1
+ {"version":3,"file":"yaml-workflows-BjrMQLTK.js","sources":["../../src/api/yaml-workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { LTYamlWorkflowRecord, LTYamlWorkflowStatus, LTYamlWorkflowVersion } from './types';\n\ninterface YamlWorkflowListResponse {\n workflows: LTYamlWorkflowRecord[];\n total: number;\n}\n\ninterface YamlWorkflowFilters {\n status?: LTYamlWorkflowStatus;\n graph_topic?: string;\n app_id?: string;\n search?: string;\n set_id?: string;\n limit?: number;\n offset?: number;\n}\n\nexport function useYamlWorkflows(filters: YamlWorkflowFilters = {}) {\n const params = new URLSearchParams();\n if (filters.status) params.set('status', filters.status);\n if (filters.graph_topic) params.set('graph_topic', filters.graph_topic);\n if (filters.app_id) params.set('app_id', filters.app_id);\n if (filters.search) params.set('search', filters.search);\n if (filters.set_id) params.set('set_id', filters.set_id);\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', filters],\n queryFn: () => apiFetch(`/yaml-workflows?${params}`),\n });\n}\n\nexport function useYamlWorkflowAppIds() {\n return useQuery<{ app_ids: string[] }>({\n queryKey: ['yamlWorkflowAppIds'],\n queryFn: () => apiFetch('/yaml-workflows/app-ids'),\n });\n}\n\nexport function useYamlWorkflowByTopic(graphTopic: string | undefined, appId?: string) {\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', 'byTopic', graphTopic, appId],\n queryFn: () => {\n const params = new URLSearchParams({ graph_topic: graphTopic!, limit: '1' });\n if (appId) params.set('app_id', appId);\n return apiFetch(`/yaml-workflows?${params}`);\n },\n enabled: !!graphTopic,\n });\n}\n\nexport function useYamlWorkflow(id: string) {\n return useQuery<LTYamlWorkflowRecord>({\n queryKey: ['yamlWorkflows', id],\n queryFn: () => apiFetch(`/yaml-workflows/${id}`),\n enabled: !!id,\n });\n}\n\nexport function useCreateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (input: {\n workflow_id: string;\n task_queue: string;\n workflow_name: string;\n name: string;\n description?: string;\n app_id?: string;\n subscribes?: string;\n tags?: string[];\n compilation_feedback?: string;\n }) =>\n apiFetch<LTYamlWorkflowRecord>('/yaml-workflows', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeployYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/deploy`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useActivateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/activate`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, data, sync, execute_as }: { id: string; data: Record<string, unknown>; sync?: boolean; execute_as?: string }) =>\n apiFetch<{ result?: unknown; job_id?: string }>(`/yaml-workflows/${id}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, sync, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRegenerateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, task_queue, compilation_feedback }: { id: string; task_queue?: string; compilation_feedback?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/regenerate`, {\n method: 'POST',\n body: JSON.stringify({ task_queue, compilation_feedback }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useArchiveYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/archive`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRestoreYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/restore`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflow'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpdateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, ...updates }: { id: string; yaml_content?: string; name?: string; description?: string; input_schema?: Record<string, unknown>; output_schema?: Record<string, unknown>; tags?: string[]; app_id?: string; graph_topic?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}`, {\n method: 'PUT',\n body: JSON.stringify(updates),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<{ deleted: boolean }>(`/yaml-workflows/${id}`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Cron scheduling ─────────────────────────────────────────────\n\nexport function useSetYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, cron_schedule, cron_envelope, execute_as }: {\n id: string;\n cron_schedule: string;\n cron_envelope?: Record<string, unknown> | null;\n execute_as?: string | null;\n }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'PUT',\n body: JSON.stringify({ cron_schedule, cron_envelope, execute_as }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useClearYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Version history ─────────────────────────────────────────────\n\nexport function useYamlWorkflowVersions(id: string) {\n return useQuery<{ versions: LTYamlWorkflowVersion[]; total: number }>({\n queryKey: ['yamlWorkflows', id, 'versions'],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions`),\n enabled: !!id,\n });\n}\n\nexport function useYamlWorkflowVersion(id: string, version: number | null) {\n return useQuery<LTYamlWorkflowVersion>({\n queryKey: ['yamlWorkflows', id, 'versions', version],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions/${version}`),\n enabled: !!id && version !== null,\n });\n}\n"],"names":["useYamlWorkflows","filters","params","useQuery","apiFetch","useYamlWorkflowAppIds","useYamlWorkflow","id","useCreateYamlWorkflow","queryClient","useQueryClient","useMutation","input","useDeployYamlWorkflow","useActivateYamlWorkflow","useInvokeYamlWorkflow","data","sync","execute_as","useRegenerateYamlWorkflow","task_queue","compilation_feedback","useArchiveYamlWorkflow","useRestoreYamlWorkflow","useUpdateYamlWorkflow","updates","useDeleteYamlWorkflow","useYamlWorkflowVersions","useYamlWorkflowVersion","version"],"mappings":"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"}
@@ -8,7 +8,7 @@
8
8
  <link rel="preconnect" href="https://fonts.googleapis.com" />
9
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
10
  <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
11
- <script type="module" crossorigin src="./assets/index-D-7W2AHB.js"></script>
11
+ <script type="module" crossorigin src="./assets/index-Dgw1KKpq.js"></script>
12
12
  <link rel="modulepreload" crossorigin href="./assets/vendor-query-B2UbickB.js">
13
13
  <link rel="modulepreload" crossorigin href="./assets/vendor-react-CXumBFUA.js">
14
14
  <link rel="modulepreload" crossorigin href="./assets/vendor-icons-CEWCGPeJ.js">
package/docs/dashboard.md CHANGED
@@ -28,7 +28,7 @@ The sidebar organizes pages into five groups.
28
28
  | Page | Route | Purpose |
29
29
  |------|-------|---------|
30
30
  | **Recent Activity** | `/` | Live event stream and business process overview. |
31
- | **Operations** | `/operations` | COO shop-floor view — pace chart of actual-vs-target flow across all ops-visible roles, station table with live metrics, and the station detail panel. Visible to any user with ops or builder access. |
31
+ | **Pace Board** | `/operations` | COO shop-floor view — pace chart of actual-vs-target flow across every station role, station table with live metrics, and the station detail panel. Visible to any user with ops or builder access. |
32
32
  | **Capabilities** | `/capabilities` | Browse MCP servers grouped by capability category. |
33
33
  | **Agent Automations** | `/agents` | Autonomous event-driven automations. Configure subscriptions, schedules, and knowledge domains. |
34
34
  | **Topics** | `/topics` | Topic catalog — browse all known event topics with descriptions, schemas, and subscriber counts. |
@@ -45,7 +45,7 @@ The sidebar organizes pages into five groups.
45
45
  | Page | Route | Purpose |
46
46
  |------|-------|---------|
47
47
  | **Accounts** | `/admin/users` | User accounts and service accounts (bots). Create, edit, assign roles, manage API keys. |
48
- | **Roles & Permissions** | `/admin/roles` | Define roles and escalation chains. Roles control escalation visibility and invocation access. |
48
+ | **Roles** | `/admin/roles` | Define roles — the queues, forms, and membership that connect workflows to people. Escalation chains, capacity settings, and versioned schemas live here. |
49
49
  | **DB Maintenance** | `/admin/maintenance` | Database housekeeping — vacuum, reindex, table statistics. |
50
50
  | **Task Queues** | `/admin/controlplane` | Active task queues, connected workers, queue depth, and worker health. |
51
51
 
@@ -188,7 +188,7 @@ Lists all durable workflow runs across the system.
188
188
 
189
189
  User Accounts and Service Accounts live on the same page, separated by a tab toggle.
190
190
 
191
- - **User Accounts** — human operators. Create users, assign display names, and grant roles. Roles determine which escalations a user can see and claim, and which workflows they can invoke from the dashboard. A `member` grant carries a work-surface scope (read/write breadth) chosen from the Scope picker; see [Roles](#roles).
191
+ - **User Accounts** — human operators. Create users, assign display names, and grant roles. Roles determine which escalations a user can see and claim, and which workflows they can invoke from the dashboard. A `member` grant carries a work-surface scope (read/write breadth) chosen from the Scope picker; the five named profiles are documented under [Role Detail](#role-detail).
192
192
  - **Service Accounts** — programmatic callers (bots, CI pipelines, external systems). Each service account has an API key for authentication. Assign roles to control access just like human users. Service accounts with the `reviewer` role can claim and resolve escalations programmatically.
193
193
  - **Role assignment** — both account types participate in the same role system. Click any account to edit roles, change display name, or manage credentials.
194
194
 
@@ -196,18 +196,57 @@ User Accounts and Service Accounts live on the same page, separated by a tab tog
196
196
 
197
197
  ### Roles
198
198
 
199
- A role is where a running workflow hands work to a person. Work waits in the role's queue, the role's schema shapes the form the person completes, membership decides who can see and resolve which items, and submitting the form resumes the workflow exactly where it paused. Roles are also where escalation chains are configured the paths work takes between teams when it needs another set of hands.
199
+ Roles are the system's central organizer and gatekeeper: every hand-off between the digital side (running workflows) and the outside world crosses a role. When a workflow needs something only a person or external actor can provide, it raises an escalation into exactly one role's queue and pauses. Membership in the role grants access to that queue and every escalation it contains; each member's scopes determine which specific combinations of activities they may perform via those escalations which items appear, which they can claim, resolve, or forward. Resolving an item resumes the workflow exactly where it paused.
200
200
 
201
- - **Role list** all roles in the system. Each row shows the role key, title, description, user count, chain count, workflow count, and an OPS badge if `ops_visible` is set.
202
- - **Role detail** — click a role to open its detail panel: identity fields (title, description), escalation chains, members, schemas with version history, and the capacity settings (`sla_minutes`, `target_per_hour`, `worker_count`). Edit these inline and save via `PATCH /api/roles/:role`.
203
- - **Members** — who holds the role: admins manage it; members work its queue according to their read/write scope (read = which items appear; write = which they can claim and resolve).
204
- - **Prior Step and Upstream Inputs** — Prior Step (`parent_role`) places the role in one Operations sequence; a role with no prior step starts its own. Upstream Inputs declare the roles it also draws from in other sequences — mixin-like, many allowed — rendered on the Operations chart as a merge glyph on the station rather than a bend in the line.
205
- - **Escalation Schema editor** (`/admin/roles/:role/schema`) — the versioned escalation form has its own page. Enter form fields as JSON Schema in a full-width editor with an optional change summary; every save that changes the schema appends an immutable snapshot and advances the current version. The version rail shows the history — expand any version to view its snapshot or load it into the editor as the base for the next save. Workflows pin a version via `schemaVersion` in the `conditionLT` config so their resolver form keeps that exact shape; escalations without a pin render the latest. The role detail page shows which version is in use and links here.
206
- - **Create Role** — add a new role. Roles referenced in workflow configs are auto-created, but you can also create them here for organizational clarity.
207
- - **Scope picker** — when granting a role at `member` type, a Scope picker offers the five named work-surface profiles: full worker (`all`/`all`, default), see-all-act-own (`all`/`self`), own-items-only (`self`/`self`), read-only auditor (`all`/`none`), and read-only own (`self`/`none`). `admin` and `superadmin` grants show no Scope picker — they always work the whole queue. The picker enforces **write ⊆ read**, so a write breadth wider than the read breadth cannot be selected.
208
- - **Escalation chains** — define source → target role mappings. When a reviewer escalates, the chain determines which roles receive the escalation next. Chains are directional (reviewer → engineer → admin) and support multiple targets per source.
201
+ Because roles carry the queue, the form schema, the membership, and the capacity targets in one place, they are also the unit everything else is built on: [Accounts](#accounts) grant them, escalation views filter by them, and the [Pace Board](#pace-board) renders them as stations.
209
202
 
210
- **API:** `GET /api/roles` lists roles. `POST /api/roles` creates. `PATCH /api/roles/:role` updates metadata and capacity fields. `GET /api/roles/details` returns full `RoleDetail` shapes. `GET /api/roles/:role/schema` fetches the latest or a pinned schema version; `GET /api/roles/:role/schema/versions` lists the history. `GET /api/roles/escalation-chains` lists chains. `POST /api/roles/escalation-chains` adds a chain.
203
+ **Master list** (`/admin/roles`) one row per role:
204
+
205
+ - **Ops dot** — a green dot marks roles that appear as stations on the [Pace Board](#pace-board).
206
+ - **Role / Label / Description** — the role key and its human-facing identity.
207
+ - **Preceded By** — the role's prior step (`parent_role`), linked. Prior steps compose the Pace Board's sequences.
208
+ - **Escalates To** — the chain targets this role can forward work to.
209
+ - **Member Count** — how many accounts hold the role.
210
+ - **Capacity** — SLA (minutes), Target (per hour), and Staff side by side. These drive the Pace Board's computed metrics.
211
+
212
+ Search filters by key, label, or description. **+ Add Role** creates a role here; roles referenced in workflow configs are also auto-created at startup. Click any row to open [Role Detail](#role-detail).
213
+
214
+ **API:** `GET /api/roles` lists roles. `POST /api/roles` creates. `GET /api/roles/details` returns full `RoleDetail` shapes. `GET /api/roles/escalation-chains` lists chains.
215
+
216
+ ### Role Detail
217
+
218
+ Accessible at `/admin/roles/:role`. One page per role — a header plus three columns covering identity, routing and people, and schemas.
219
+
220
+ **Header** — the role key with its prior step, the capacity set, and the **Ops** toggle that shows the role as a station on the [Pace Board](#pace-board). The capacity set holds `sla_minutes`, `target_per_hour`, and `worker_count`; enter any two and the header hints the derived third (`throughput = workers / (sla / 60)`). Save applies header and identity edits via `PATCH /api/roles/:role`.
221
+
222
+ **Identity** — display name and description, shown on role rows and station labels.
223
+
224
+ **Sequence placement** — appears when the Ops toggle is on:
225
+
226
+ - **Prior Step** — places the role in one Pace Board sequence; a role with no prior step starts its own.
227
+ - **Upstream Inputs** — the roles this station also draws from in other sequences. Mixin-like, many allowed, saved live. Rendered on the Pace Board as a merge glyph on the station, never a bend in the line: an upstream is an input, not a descendant.
228
+
229
+ **Escalation Targets** — the chain out of this role, saved live. When a member escalates an item, these targets receive it. Chains are directional and support multiple targets per source.
230
+
231
+ **Members** — who holds the role: admins manage it; members work its queue according to their read/write work-surface scope (read = which items appear; write = which they can claim and resolve). A `member` grant carries a scope chosen from five named profiles: full worker (`all`/`all`, default), see-all-act-own (`all`/`self`), own-items-only (`self`/`self`), read-only auditor (`all`/`none`), and read-only own (`self`/`none`). The picker enforces **write ⊆ read**. `admin` and `superadmin` grants always work the whole queue.
232
+
233
+ **Escalation Schema** — shows the schema version currently in use and links to the [Escalation Schema](#escalation-schema) editor page.
234
+
235
+ **Metadata Schema** — JSON Schema that validates each escalation's `metadata` at creation time. Its keys appear in faceted search autocomplete.
236
+
237
+ **Properties** — a free JSON bag for custom per-role values.
238
+
239
+ **API:** `PATCH /api/roles/:role` updates identity, capacity, placement, and schemas. `POST /api/roles/escalation-chains` adds a chain target; `DELETE /api/roles/escalation-chains` removes one.
240
+
241
+ ### Escalation Schema
242
+
243
+ Accessible at `/admin/roles/:role/schema`. The versioned form behind a role's escalations — the form a person completes to resolve items in the role's queue.
244
+
245
+ - **Editor** — form fields as JSON Schema in a full-width editor, with an optional change summary recorded on the version the save creates. **Save Version** writes only the schema: every save that changes it appends an immutable snapshot and advances the current version.
246
+ - **Version rail** — the full history with the current version marked. Expand any version to view its snapshot or load it into the editor as the base for the next save.
247
+ - **Pinning** — workflows pin a version via `schemaVersion` in the `conditionLT` config, so their resolver form keeps that exact shape for the life of the run. Escalations without a pin render the latest version.
248
+
249
+ **API:** `GET /api/roles/:role/schema` fetches the latest or a pinned version. `GET /api/roles/:role/schema/versions` lists the history. `PATCH /api/roles/:role` with `form_schema` (+ optional `change_summary`) saves a new version.
211
250
 
212
251
  ### DB Maintenance
213
252
 
@@ -265,20 +304,23 @@ Accessible at `/escalations`. A statistics dashboard for escalation health acros
265
304
  - **Summary cards** — open (pending), claimed (in progress), created (new), and resolved counts for the selected window.
266
305
  - **Role breakdown table** — groups escalations by role so you can see which teams have the most pending work. Useful for identifying bottlenecks and rebalancing workload.
267
306
 
268
- ### Operations
307
+ ### Pace Board
308
+
309
+ Accessible at `/operations`. The COO shop-floor view of the roles system: actual-vs-target flow across every station, rendered as a pace chart with a station table and detail panel below.
269
310
 
270
- Accessible at `/operations` (sidebar: Operations; page header: **Pace Board**). The COO shop-floor view shows actual-vs-target flow across ops-visible roles as a pace chart, with a station table and detail panel below.
311
+ The board is [Roles](#roles) end-to-end. Every station is a role with its **Ops** toggle on; sequences are composed from each role's Prior Step (`parent_role`); cross-sequence feeds come from Upstream Inputs; the red target line comes from each role's capacity settings. Configuring the board *is* configuring roles the **Configure** button in the header goes straight there.
271
312
 
272
- Execution is a graph; this page tells its story as **sequences**. Each ops-visible role with no prior step (or whose prior step is outside the ops set) starts a sequence, followed by its `parent_role` descendants in dependency order. The table is always the ground truth of the queues; the SVG is the narrative line drawn through them.
313
+ Execution is a graph; this page tells its story as **sequences**. Each station role with no prior step (or whose prior step is outside the station set) starts a sequence, followed by its `parent_role` descendants in dependency order. The longest sequence leads. The table is always the ground truth of the queues; the SVG is the narrative line drawn through them.
273
314
 
274
- - **Sequence picker** — when more than one sequence exists, tabs appear above the chart, one per sequence, named by its origin role (station count alongside). The active sequence is deep-linked (`?fragment=<origin role>`) and each switch is a browser-history entry, so a shared URL opens the same sequence and back/forward walks between them.
275
- - **Period selector** — `15m`, `1h`, `24h`, `7d`, `30d`. Controls the lookback window for resolved counts, percentile metrics, and the throughput metrics.
276
- - **Pace chart** — connects the active sequence's stations in process dependency order and plots absolute counts for the selected window: a straight red target polyline (`target_per_hour × window hours`) against a smooth actual (resolved) curve with a light area fill. The queue splits into two stacked bands — claimed-and-worked (indigo) and waiting-unclaimed (sky). Station circles are colored by pace ratio (green ≥ 100%, amber ≥ 60%, red below).
277
- - **Merge affordance** — a station that declares upstream inputs (roles feeding it from other sequences) shows a small dashed merge glyph at its floor position. It is deliberately a symbol, never a bend in the line: the upstream is an input, not a descendant. Hover names the feeding roles; click jumps to their sequence.
278
- - **Station table** — one row per station with PENDING, ACTIVE, RESOLVED (column bands in the chart's hues), P99 WAIT, P99 WORK, and a TREND mini-bar. A merge icon next to the role name marks cross-sequence inputs. Stations with in-arrears items show a sub-row with a link to the oldest-first queue view.
279
- - **Station detail panel** — opens on row or circle click. Shows the role's identity, an independent period toggle, and full metric breakdown (wait/work percentiles, SLA target, worker count, links to queue).
315
+ - **Sequence picker** — when more than one sequence exists, tabs appear above the chart, one per sequence, named by its origin role with the station count alongside. The active sequence is deep-linked (`?fragment=<origin role>`) and each switch is a browser-history entry, so a shared URL opens the same sequence and back/forward walks between them.
316
+ - **Period selector** — `15m`, `1h`, `24h`, `7d`, `30d`. Controls the lookback window for resolved counts, percentile metrics, and throughput.
317
+ - **Pace chart** — connects the active sequence's stations in process dependency order and plots absolute counts for the selected window: a straight red target polyline (`target_per_hour × window hours`) against a smooth actual (resolved) curve with a light area fill. The queue splits into two stacked bands — claimed-and-worked (indigo) and waiting-unclaimed (sky). Station circles are colored by pace ratio (green ≥ 100%, amber ≥ 60%, red below); a station with items past SLA carries a dashed red ring.
318
+ - **Merge affordance** — a station that declares upstream inputs shows a small dashed merge glyph at its floor position. It is deliberately a symbol, never a bend in the line: the upstream is an input, not a descendant. Hover names the feeding roles; click jumps to their sequence.
319
+ - **Station table** — one row per station: ROLE (with a merge icon marking cross-sequence inputs), TARGET/H, then PENDING, ACTIVE, RESOLVED in column bands carrying the chart's hues, P99 WAIT, P99 WORK, and a TREND mini-bar. TREND shows the live backlog-to-target ratio while the queue has items; when the queue is idle it shows the period's throughput efficiency, marked with `↩`. Stations with past-SLA items show a sub-row linking to the oldest-first queue view.
320
+ - **Station detail panel** — opens on row or circle click. Shows the role's identity, an independent period toggle, and the full metric breakdown (wait/work percentiles, SLA target, worker count, links to the queue).
321
+ - **Live updates** — escalation events refresh the metrics push-driven and debounced; the header's refresh button forces a reload.
280
322
 
281
- Roles appear on this view when `ops_visible = true` is set. The capacity settings (`sla_minutes`, `target_per_hour`, `worker_count`) drive the computed metrics. Set these via `PATCH /api/roles/:role` or the Roles admin page. See [Operations](operations.md) for the full concept doc.
323
+ A role joins the board via the **Ops** toggle on its [Role Detail](#role-detail) page; the capacity settings (`sla_minutes`, `target_per_hour`, `worker_count`) drive the computed metrics. See [Operations](operations.md) for the full concept doc.
282
324
 
283
325
  **API:** `GET /api/escalations/station-metrics?period=24h`
284
326
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/long-tail",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "description": "Long Tail Workflows — Durable AI workflows with human-in-the-loop escalation. Powered by PostgreSQL.",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -71,7 +71,7 @@
71
71
  "@anthropic-ai/sdk": "^0.92.0",
72
72
  "@aws-sdk/client-s3": "^3.1017.0",
73
73
  "@aws-sdk/s3-request-presigner": "^3.1045.0",
74
- "@hotmeshio/hotmesh": "^0.25.2",
74
+ "@hotmeshio/hotmesh": "^0.25.5",
75
75
  "@modelcontextprotocol/sdk": "^1.27.1",
76
76
  "@opentelemetry/exporter-trace-otlp-proto": "^0.215.0",
77
77
  "@opentelemetry/resources": "^2.5.1",
@@ -1,9 +0,0 @@
1
- import{a as o,j as e}from"./vendor-query-B2UbickB.js";import{b as k,f as w,j as _,c as E}from"./roles-BdtnzLsL.js";import{J as R}from"./index-D-7W2AHB.js";import{g as j,V as C,ag as O}from"./vendor-icons-CEWCGPeJ.js";import{e as V}from"./vendor-react-CXumBFUA.js";const q=`{
2
- "type": "object",
3
- "properties": {
4
- "approved": { "type": "boolean", "title": "Approve?" },
5
- "notes": { "type": "string", "title": "Notes" }
6
- },
7
- "required": ["approved"]
8
- }`;function v(l){const t=l.trim();if(!t)return{ok:!0,value:null};try{const r=JSON.parse(t);return typeof r!="object"||Array.isArray(r)||r===null?{ok:!1}:{ok:!0,value:r}}catch{return{ok:!1}}}function F(){const{role:l}=V(),{data:t,isLoading:r}=k(),n=w(),s=((t==null?void 0:t.roles)??[]).find(a=>a.role===l),[i,c]=o.useState(""),[h,u]=o.useState(""),[N,x]=o.useState(!1),[g,d]=o.useState(!1),[p,m]=o.useState(!1),f=o.useRef(null);o.useEffect(()=>{!s||f.current===s.role||(f.current=s.role,c(s.form_schema?JSON.stringify(s.form_schema,null,2):""),u(""),x(!1),m(!1))},[s]);const y=a=>{c(a),x(!0),d(!1),m(!v(a).ok)},b=()=>{const a=v(i);if(!a.ok||!s){m(!a.ok);return}n.mutate({role:s.role,form_schema:a.value??null,change_summary:h.trim()||void 0},{onSuccess:()=>{x(!1),d(!0),u(""),window.setTimeout(()=>d(!1),2500)}})},S=a=>{c(a?JSON.stringify(a,null,2):""),x(!0),d(!1),m(!1)};return r?e.jsxs("div",{className:"animate-pulse space-y-4",children:[e.jsx("div",{className:"h-8 bg-surface-sunken rounded w-64"}),e.jsx("div",{className:"h-96 bg-surface-sunken rounded"})]}):s?e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-start justify-between mb-10",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-3 mb-1",children:[e.jsx(j,{className:"w-5 h-5 text-cyan-400",strokeWidth:1.5}),e.jsx("h1",{className:"text-lg font-medium text-text-primary",children:"Escalation Schema"}),e.jsx("span",{className:"font-mono text-sm text-text-tertiary",children:s.role}),s.current_schema_version!=null&&e.jsxs("span",{className:"text-[10px] font-mono text-text-quaternary",children:["v",s.current_schema_version," in use"]})]}),e.jsxs("p",{className:"text-xs text-text-tertiary pl-8 max-w-2xl leading-relaxed",children:["Enter form fields as JSON Schema — this is the form a person completes to resolve this role's escalations. Saving a change creates the next version; workflows pin any version with ",e.jsx("code",{className:"font-mono",children:"schemaVersion"}),", and unpinned escalations always use the latest."]})]}),e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[g&&e.jsxs("span",{className:"flex items-center gap-1 text-xs text-status-success animate-page-enter",children:[e.jsx(C,{className:"w-3 h-3"})," Saved"]}),n.error&&e.jsx("span",{className:"text-xs text-status-error max-w-[220px] truncate",children:n.error.message}),e.jsx("button",{onClick:b,disabled:!N||p||n.isPending,className:"px-3 py-1.5 text-xs rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed",children:n.isPending?"Saving…":"Save Version"})]})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-16 items-start",children:[e.jsxs("div",{className:"col-span-2 space-y-6",children:[e.jsx("textarea",{value:i,onChange:a=>y(a.target.value),rows:28,spellCheck:!1,className:"input text-xs font-mono w-full resize-y leading-relaxed",placeholder:q}),p&&e.jsx("p",{className:"text-[10px] text-status-error -mt-4",children:"Invalid JSON"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1.5",children:"Change Summary"}),e.jsx("input",{type:"text",value:h,onChange:a=>u(a.target.value),placeholder:"e.g., Added lotNumber field for shoe orders",className:"input text-sm w-full"}),e.jsx("p",{className:"text-[10px] text-text-quaternary mt-1.5",children:"Recorded on the version this save creates."})]})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3 pb-2 border-b border-surface-border",children:[e.jsx(O,{className:"w-4 h-4 text-text-quaternary",strokeWidth:1.5}),e.jsx("h2",{className:"section-h2",children:"Versions"})]}),e.jsx(J,{role:s.role,onLoad:S})]})]})]}):e.jsxs("div",{className:"flex flex-col items-center justify-center py-20 text-center",children:[e.jsx(j,{className:"w-12 h-12 text-text-quaternary mb-4",strokeWidth:1}),e.jsx("h2",{className:"text-lg font-medium text-text-primary mb-2",children:"Role not found"})]})}function J({role:l,onLoad:t}){const{data:r}=_(l),n=(r==null?void 0:r.versions)??[];return n.length===0?e.jsx("p",{className:"text-[11px] text-text-tertiary leading-relaxed",children:"Versions appear here after the first save. Each schema change adds one; earlier versions stay viewable and loadable as an editing base."}):e.jsx("div",{className:"divide-y divide-surface-border/40",children:n.map(s=>e.jsx(L,{role:l,summary:s,onLoad:t},s.version))})}function L({role:l,summary:t,onLoad:r}){const[n,s]=o.useState(!1),i=E(l,t.version,n);return e.jsxs("div",{className:"py-2",children:[e.jsxs("button",{onClick:()=>s(c=>!c),className:"w-full text-left group",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("span",{className:"text-xs font-mono text-text-secondary",children:["v",t.version]}),t.is_current&&e.jsx("span",{className:"text-[9px] font-bold uppercase tracking-wider text-accent",children:"current"}),e.jsx("span",{className:"flex-1"}),e.jsx("span",{className:"text-[10px] text-text-quaternary shrink-0",children:new Date(t.created_at).toLocaleDateString()})]}),t.change_summary&&e.jsx("p",{className:"mt-0.5 text-[10px] text-text-tertiary truncate",children:t.change_summary})]}),n&&e.jsx("div",{className:"mt-2 space-y-2",children:i.data?e.jsxs(e.Fragment,{children:[i.data.form_schema?e.jsx(R,{data:i.data.form_schema,defaultCollapsed:!0}):e.jsx("p",{className:"text-[10px] text-text-quaternary",children:"This version carries no form schema."}),e.jsx("button",{onClick:()=>r(i.data.form_schema??null),className:"text-[10px] text-accent hover:underline",children:"Load into editor"})]}):e.jsx("p",{className:"text-[10px] text-text-quaternary",children:"Loading…"})})]})}export{F as EscalationSchemaPage};
9
- //# sourceMappingURL=EscalationSchemaPage-Do2iPKUl.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"EscalationSchemaPage-Do2iPKUl.js","sources":["../../src/pages/admin/roles/EscalationSchemaPage.tsx"],"sourcesContent":["import { useState, useEffect, useRef } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { Braces, Check, History } from 'lucide-react';\nimport {\n useRoleDetails,\n useRoleSchema,\n useRoleSchemaVersions,\n useUpdateRole,\n type RoleSchemaVersionSummary,\n} from '../../../api/roles';\nimport { JsonViewer } from '../../../components/common/data/JsonViewer';\n\n/**\n * The escalation form schema, on its own page (/admin/roles/:role/schema).\n * This is the form a person completes to resolve the role's escalations —\n * versioned, pinnable by workflows (conditionLT schemaVersion), and worth a\n * full editing surface. Saving here writes ONLY the schema: one PATCH with\n * form_schema (+ optional change summary); every actual change appends the\n * next immutable version.\n */\n\nconst PLACEHOLDER = `{\n \"type\": \"object\",\n \"properties\": {\n \"approved\": { \"type\": \"boolean\", \"title\": \"Approve?\" },\n \"notes\": { \"type\": \"string\", \"title\": \"Notes\" }\n },\n \"required\": [\"approved\"]\n}`;\n\nfunction safeParseObject(text: string): { ok: boolean; value?: Record<string, unknown> | null } {\n const trimmed = text.trim();\n if (!trimmed) return { ok: true, value: null };\n try {\n const parsed = JSON.parse(trimmed);\n if (typeof parsed !== 'object' || Array.isArray(parsed) || parsed === null) return { ok: false };\n return { ok: true, value: parsed };\n } catch {\n return { ok: false };\n }\n}\n\nexport function EscalationSchemaPage() {\n const { role: roleKey } = useParams<{ role: string }>();\n const { data, isLoading } = useRoleDetails();\n const updateRole = useUpdateRole();\n\n const role = (data?.roles ?? []).find((r) => r.role === roleKey);\n\n const [text, setText] = useState('');\n const [summary, setSummary] = useState('');\n const [dirty, setDirty] = useState(false);\n const [savedOk, setSavedOk] = useState(false);\n const [jsonError, setJsonError] = useState(false);\n\n // Seed the editor from the live schema exactly once per role — refetches\n // (cache invalidations, saves) must not clobber in-progress edits.\n const seededFor = useRef<string | null>(null);\n useEffect(() => {\n if (!role || seededFor.current === role.role) return;\n seededFor.current = role.role;\n setText(role.form_schema ? JSON.stringify(role.form_schema, null, 2) : '');\n setSummary('');\n setDirty(false);\n setJsonError(false);\n }, [role]);\n\n const handleEdit = (value: string) => {\n setText(value);\n setDirty(true);\n setSavedOk(false);\n setJsonError(!safeParseObject(value).ok);\n };\n\n const handleSave = () => {\n const parsed = safeParseObject(text);\n if (!parsed.ok || !role) { setJsonError(!parsed.ok); return; }\n // Saving just the schema — nothing else rides this PATCH.\n updateRole.mutate(\n { role: role.role, form_schema: parsed.value ?? null, change_summary: summary.trim() || undefined },\n {\n onSuccess: () => {\n setDirty(false);\n setSavedOk(true);\n setSummary('');\n window.setTimeout(() => setSavedOk(false), 2500);\n },\n },\n );\n };\n\n const loadIntoEditor = (schema: Record<string, unknown> | null) => {\n setText(schema ? JSON.stringify(schema, null, 2) : '');\n setDirty(true);\n setSavedOk(false);\n setJsonError(false);\n };\n\n if (isLoading) {\n return (\n <div className=\"animate-pulse space-y-4\">\n <div className=\"h-8 bg-surface-sunken rounded w-64\" />\n <div className=\"h-96 bg-surface-sunken rounded\" />\n </div>\n );\n }\n\n if (!role) {\n return (\n <div className=\"flex flex-col items-center justify-center py-20 text-center\">\n <Braces className=\"w-12 h-12 text-text-quaternary mb-4\" strokeWidth={1} />\n <h2 className=\"text-lg font-medium text-text-primary mb-2\">Role not found</h2>\n </div>\n );\n }\n\n return (\n <div>\n {/* ── Header ── */}\n <div className=\"flex items-start justify-between mb-10\">\n <div>\n <div className=\"flex items-center gap-3 mb-1\">\n <Braces className=\"w-5 h-5 text-cyan-400\" strokeWidth={1.5} />\n <h1 className=\"text-lg font-medium text-text-primary\">Escalation Schema</h1>\n <span className=\"font-mono text-sm text-text-tertiary\">{role.role}</span>\n {role.current_schema_version != null && (\n <span className=\"text-[10px] font-mono text-text-quaternary\">\n v{role.current_schema_version} in use\n </span>\n )}\n </div>\n <p className=\"text-xs text-text-tertiary pl-8 max-w-2xl leading-relaxed\">\n Enter form fields as JSON Schema — this is the form a person completes to\n resolve this role's escalations. Saving a change creates the next version;\n workflows pin any version with <code className=\"font-mono\">schemaVersion</code>,\n and unpinned escalations always use the latest.\n </p>\n </div>\n\n <div className=\"flex items-center gap-2 shrink-0\">\n {savedOk && (\n <span className=\"flex items-center gap-1 text-xs text-status-success animate-page-enter\">\n <Check className=\"w-3 h-3\" /> Saved\n </span>\n )}\n {updateRole.error && (\n <span className=\"text-xs text-status-error max-w-[220px] truncate\">\n {(updateRole.error as Error).message}\n </span>\n )}\n <button\n onClick={handleSave}\n disabled={!dirty || jsonError || updateRole.isPending}\n className=\"px-3 py-1.5 text-xs rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {updateRole.isPending ? 'Saving…' : 'Save Version'}\n </button>\n </div>\n </div>\n\n {/* ── Editor + version rail ── */}\n <div className=\"grid grid-cols-3 gap-16 items-start\">\n <div className=\"col-span-2 space-y-6\">\n <textarea\n value={text}\n onChange={(e) => handleEdit(e.target.value)}\n rows={28}\n spellCheck={false}\n className=\"input text-xs font-mono w-full resize-y leading-relaxed\"\n placeholder={PLACEHOLDER}\n />\n {jsonError && <p className=\"text-[10px] text-status-error -mt-4\">Invalid JSON</p>}\n\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1.5\">\n Change Summary\n </label>\n <input\n type=\"text\"\n value={summary}\n onChange={(e) => setSummary(e.target.value)}\n placeholder=\"e.g., Added lotNumber field for shoe orders\"\n className=\"input text-sm w-full\"\n />\n <p className=\"text-[10px] text-text-quaternary mt-1.5\">\n Recorded on the version this save creates.\n </p>\n </div>\n </div>\n\n {/* Version history — view any snapshot, load one as the editing base */}\n <div>\n <div className=\"flex items-center gap-2 mb-3 pb-2 border-b border-surface-border\">\n <History className=\"w-4 h-4 text-text-quaternary\" strokeWidth={1.5} />\n <h2 className=\"section-h2\">Versions</h2>\n </div>\n <VersionRail role={role.role} onLoad={loadIntoEditor} />\n </div>\n </div>\n </div>\n );\n}\n\nfunction VersionRail({\n role,\n onLoad,\n}: {\n role: string;\n onLoad: (schema: Record<string, unknown> | null) => void;\n}) {\n const { data } = useRoleSchemaVersions(role);\n const versions = data?.versions ?? [];\n\n if (versions.length === 0) {\n return (\n <p className=\"text-[11px] text-text-tertiary leading-relaxed\">\n Versions appear here after the first save. Each schema change adds one;\n earlier versions stay viewable and loadable as an editing base.\n </p>\n );\n }\n\n return (\n <div className=\"divide-y divide-surface-border/40\">\n {versions.map((v) => (\n <VersionEntry key={v.version} role={role} summary={v} onLoad={onLoad} />\n ))}\n </div>\n );\n}\n\nfunction VersionEntry({\n role,\n summary,\n onLoad,\n}: {\n role: string;\n summary: RoleSchemaVersionSummary;\n onLoad: (schema: Record<string, unknown> | null) => void;\n}) {\n const [open, setOpen] = useState(false);\n // Snapshot fetch is lazy — only when the entry is expanded.\n const snapshot = useRoleSchema(role, summary.version, open);\n\n return (\n <div className=\"py-2\">\n <button onClick={() => setOpen((o) => !o)} className=\"w-full text-left group\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs font-mono text-text-secondary\">v{summary.version}</span>\n {summary.is_current && (\n <span className=\"text-[9px] font-bold uppercase tracking-wider text-accent\">current</span>\n )}\n <span className=\"flex-1\" />\n <span className=\"text-[10px] text-text-quaternary shrink-0\">\n {new Date(summary.created_at).toLocaleDateString()}\n </span>\n </div>\n {summary.change_summary && (\n <p className=\"mt-0.5 text-[10px] text-text-tertiary truncate\">{summary.change_summary}</p>\n )}\n </button>\n {open && (\n <div className=\"mt-2 space-y-2\">\n {snapshot.data ? (\n <>\n {snapshot.data.form_schema\n ? <JsonViewer data={snapshot.data.form_schema} defaultCollapsed />\n : <p className=\"text-[10px] text-text-quaternary\">This version carries no form schema.</p>}\n <button\n onClick={() => onLoad((snapshot.data!.form_schema ?? null) as Record<string, unknown> | null)}\n className=\"text-[10px] text-accent hover:underline\"\n >\n Load into editor\n </button>\n </>\n ) : (\n <p className=\"text-[10px] text-text-quaternary\">Loading…</p>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"names":["PLACEHOLDER","safeParseObject","text","trimmed","parsed","EscalationSchemaPage","roleKey","useParams","data","isLoading","useRoleDetails","updateRole","useUpdateRole","role","r","setText","useState","summary","setSummary","dirty","setDirty","savedOk","setSavedOk","jsonError","setJsonError","seededFor","useRef","useEffect","handleEdit","value","handleSave","loadIntoEditor","schema","jsxs","jsx","Braces","Check","e","History","VersionRail","onLoad","useRoleSchemaVersions","versions","v","VersionEntry","open","setOpen","snapshot","useRoleSchema","o","Fragment","JsonViewer"],"mappings":"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"}
@@ -1,11 +0,0 @@
1
- import{j as e,a as m}from"./vendor-query-B2UbickB.js";import{b as X,f as B,g as Y,e as Z,h as ee,i as te}from"./roles-BdtnzLsL.js";import{J as U}from"./index-D-7W2AHB.js";import{C as se}from"./ConfirmDeleteModal-D9_1b4MW.js";import{u as ae}from"./users-BxKf5dAX.js";import{T as $,v as I,V as re,p as ne,as as oe,N as le,f as ie,g as J}from"./vendor-icons-CEWCGPeJ.js";import{e as ce,c as de,L as xe}from"./vendor-react-CXumBFUA.js";import"./Modal-CSrxpXeM.js";function pe({role:a}){const{data:d}=ae({role:a,limit:100}),n=(d==null?void 0:d.users)??[];return n.length===0?e.jsx("p",{className:"text-[11px] text-text-tertiary",children:"Assign users to this role to staff its queue. Members see and resolve escalations here according to their read/write scope; admins manage the role itself."}):e.jsx("div",{className:"divide-y divide-surface-border/40",children:n.map(i=>{const p=i.roles.find(c=>c.role===a);return p?e.jsxs("div",{className:"flex items-center justify-between py-1.5 gap-2",children:[e.jsx("span",{className:"text-xs text-text-secondary truncate",children:i.display_name||i.external_id}),e.jsx("span",{className:"text-[10px] text-text-quaternary font-mono shrink-0",children:me(p)})]},i.id):null})})}function me(a){return a.type==="superadmin"||a.type==="admin"?a.type:`member · read ${a.read_scope} · write ${a.write_scope}`}function L(a){return a==null?"":JSON.stringify(a,null,2)}function C(a){const d=a.trim();if(!d)return{ok:!0,value:void 0};try{const n=JSON.parse(d);return typeof n!="object"||Array.isArray(n)||n===null?{ok:!1}:{ok:!0,value:n}}catch{return{ok:!1}}}function h({icon:a,color:d,label:n,aside:i}){return e.jsxs("div",{className:"flex items-center justify-between mb-3 pb-2 border-b border-surface-border",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(a,{className:`w-4 h-4 ${d}`,strokeWidth:1.5}),e.jsx("h2",{className:"section-h2",children:n})]}),i]})}function ue({role:a,allRoles:d}){const{data:n}=Z(),i=ee(),p=te(),[c,u]=m.useState(""),t=(n==null?void 0:n.chains)??[],s=m.useMemo(()=>t.filter(l=>l.source_role===a.role).map(l=>l.target_role),[t,a.role]),f=m.useMemo(()=>d.map(l=>l.role).filter(l=>l!==a.role&&l!=="superadmin"&&!s.includes(l)),[d,a.role,s]);return a.role==="superadmin"?e.jsx("p",{className:"text-[11px] text-text-tertiary",children:"Superadmins can escalate to any role implicitly."}):e.jsxs("div",{className:"space-y-3",children:[s.length===0?e.jsx("p",{className:"text-[11px] text-text-tertiary",children:"Add a target role to route hand-offs."}):e.jsx("div",{className:"flex flex-wrap gap-1.5",children:s.map(l=>e.jsxs("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 text-[10px] bg-surface-sunken rounded font-mono text-text-secondary",children:[l,e.jsx("button",{onClick:()=>p.mutate({source_role:a.role,target_role:l}),className:"text-text-quaternary hover:text-red-400 transition-colors leading-none ml-0.5",children:"×"})]},l))}),f.length>0&&e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("select",{value:c,onChange:l=>u(l.target.value),className:"select text-xs font-mono flex-1",children:[e.jsx("option",{value:"",children:"Add target…"}),f.map(l=>e.jsx("option",{value:l,children:l},l))]}),e.jsx("button",{onClick:()=>{c&&i.mutate({source_role:a.role,target_role:c},{onSuccess:()=>u("")})},disabled:!c||i.isPending,className:"px-2.5 py-1 text-xs rounded bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed shrink-0",children:i.isPending?"…":"Add"})]})]})}function he({role:a,allRoles:d}){const n=B(),[i,p]=m.useState(""),c=a.upstream_roles??[],u=m.useMemo(()=>d.map(s=>s.role).filter(s=>s!==a.role&&s!=="superadmin"&&!c.includes(s)),[d,a.role,c]),t=s=>n.mutate({role:a.role,upstream_roles:s},{onSuccess:()=>p("")});return e.jsxs("div",{className:"space-y-3",children:[c.length===0?e.jsx("p",{className:"text-[11px] text-text-tertiary",children:"Add a role from another sequence that this station draws input from. Prior Step sets where this role sits in its own sequence; upstream inputs mark the side-quests that land here."}):e.jsx("div",{className:"flex flex-wrap gap-1.5",children:c.map(s=>e.jsxs("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 text-[10px] bg-surface-sunken rounded font-mono text-text-secondary",children:[s,e.jsx("button",{onClick:()=>t(c.filter(f=>f!==s)),className:"text-text-quaternary hover:text-red-400 transition-colors leading-none ml-0.5",children:"×"})]},s))}),u.length>0&&e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("select",{value:i,onChange:s=>p(s.target.value),className:"select text-xs font-mono flex-1",children:[e.jsx("option",{value:"",children:"Add upstream input…"}),u.map(s=>e.jsx("option",{value:s,children:s},s))]}),e.jsx("button",{onClick:()=>{i&&t([...c,i])},disabled:!i||n.isPending,className:"px-2.5 py-1 text-xs rounded bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed shrink-0",children:n.isPending?"…":"Add"})]}),n.error&&e.jsx("p",{className:"text-[10px] text-status-error",children:n.error.message})]})}function fe(a){return{title:a.title??"",description:a.description??"",ops_visible:a.ops_visible,parent_role:a.parent_role??"",metadata_schema:L(a.metadata_schema),properties:L(a.properties)||"{}",sla_minutes:a.sla_minutes!=null?String(a.sla_minutes):"",target_per_hour:a.target_per_hour!=null?String(a.target_per_hour):"",worker_count:a.worker_count!=null?String(a.worker_count):""}}function ke(){const{role:a}=ce(),d=de(),{data:n,isLoading:i}=X(),p=B(),c=Y(),u=(n==null?void 0:n.roles)??[],t=u.find(r=>r.role===a),[s,f]=m.useState({title:"",description:"",ops_visible:!1,parent_role:"",metadata_schema:"",properties:"{}",sla_minutes:"",target_per_hour:"",worker_count:""}),[l,P]=m.useState(!1),[V,b]=m.useState(!1),[g,_]=m.useState({}),[W,M]=m.useState(!1),[y,q]=m.useState(new Set),F=r=>q(o=>new Set([...o,r]));m.useEffect(()=>{t&&(f(fe(t)),P(!1),b(!1),_({}),q(new Set))},[a,t==null?void 0:t.role]);const v=r=>{f(o=>({...o,...r})),P(!0),b(!1)},z=m.useMemo(()=>u.filter(r=>{if(!t||r.role===t.role)return!1;let o=r;const x=new Set;for(;o!=null&&o.parent_role;){if(o.parent_role===t.role)return!1;if(x.has(o.parent_role))break;x.add(o.parent_role),o=u.find(j=>j.role===o.parent_role)}return!0}),[u,t]),G=()=>{const r=C(s.metadata_schema),o=C(s.properties),x={};if(r.ok||(x.metadata_schema="Invalid JSON"),o.ok||(x.properties="Invalid JSON"),_(x),Object.keys(x).length||!t)return;const j=D=>{const N=parseFloat(D);return isNaN(N)?null:N},E=D=>{const N=j(D);return N==null?null:Math.round(N)};p.mutate({role:t.role,title:s.title.trim()||null,description:s.description.trim()||null,ops_visible:s.ops_visible,parent_role:s.parent_role||null,metadata_schema:r.value??null,properties:o.value??{},sla_minutes:j(s.sla_minutes),target_per_hour:j(s.target_per_hour),worker_count:E(s.worker_count)},{onSuccess:()=>{P(!1),b(!0),q(new Set),window.setTimeout(()=>b(!1),2500)}})},H=()=>{t&&c.mutate(t.role,{onSuccess:()=>d("/admin/roles")})};if(i)return e.jsxs("div",{className:"animate-pulse space-y-4",children:[e.jsx("div",{className:"h-8 bg-surface-sunken rounded w-48"}),e.jsx("div",{className:"h-4 bg-surface-sunken rounded w-64"}),e.jsx("div",{className:"h-64 bg-surface-sunken rounded"})]});if(!t)return e.jsxs("div",{className:"flex flex-col items-center justify-center py-20 text-center",children:[e.jsx($,{className:"w-12 h-12 text-text-quaternary mb-4",strokeWidth:1}),e.jsx("h2",{className:"text-lg font-medium text-text-primary mb-2",children:"Role not found"})]});const K=t.user_count>0||t.chain_count>0||t.workflow_count>0,Q=l&&!Object.values(g).some(Boolean),w=parseFloat(s.sla_minutes),k=parseFloat(s.target_per_hour),S=parseFloat(s.worker_count),O=!isNaN(w)&&w>0,R=!isNaN(k)&&k>0,A=!isNaN(S)&&S>0,T=O&&A&&!R?`→ target ≈ ${(S/(w/60)).toFixed(1)}/h`:O&&R&&!A?`→ workers ≈ ${(k*(w/60)).toFixed(1)}`:R&&A&&!O?`→ SLA ≈ ${(S/k*60).toFixed(0)}m`:null;return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-start justify-between gap-8 mb-12",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-1",children:[e.jsx($,{className:"w-5 h-5 text-accent",strokeWidth:1.5}),e.jsx("h1",{className:"text-lg font-mono font-medium text-text-primary",children:t.role}),t.parent_role&&e.jsxs("span",{className:"flex items-center gap-1 text-[10px] text-text-quaternary font-mono",children:[e.jsx(I,{className:"w-3 h-3"})," ",t.parent_role]})]}),t.title&&e.jsx("p",{className:"text-sm text-text-secondary pl-8",children:t.title})]}),e.jsxs("div",{className:"flex items-end gap-4 bg-surface-sunken rounded-lg px-4 py-2.5 shrink-0 mx-auto",title:"throughput = workers / (sla / 60)",children:[[{key:"sla_minutes",label:"SLA",unit:"min",placeholder:"30"},{key:"target_per_hour",label:"Target",unit:"/h",placeholder:"20"},{key:"worker_count",label:"Workers",unit:"",placeholder:"4"}].map(({key:r,label:o,unit:x,placeholder:j})=>e.jsxs("div",{children:[e.jsxs("label",{className:"block text-[9px] font-semibold uppercase tracking-widest text-text-quaternary mb-1",children:[o,x&&e.jsx("span",{className:"normal-case font-normal ml-1",children:x})]}),e.jsx("input",{type:"number",min:"0",step:"any",value:s[r],onChange:E=>v({[r]:E.target.value}),placeholder:j,className:"input text-xs w-16 font-mono"})]},r)),T&&e.jsx("span",{className:"text-[10px] text-accent font-mono whitespace-nowrap pb-2",children:T})]}),e.jsxs("div",{className:"flex items-center gap-3 shrink-0",children:[e.jsxs("div",{className:"flex items-center gap-2",title:"Show as a station on the Pace Board",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary",children:"Ops"}),e.jsx("button",{onClick:()=>v({ops_visible:!s.ops_visible}),className:`w-9 h-5 rounded-full transition-colors relative shrink-0 ${s.ops_visible?"bg-accent":"bg-surface-border"}`,children:e.jsx("span",{className:`absolute top-[3px] left-0 w-3.5 h-3.5 rounded-full bg-white transition-transform shadow ${s.ops_visible?"translate-x-[18px]":"translate-x-[3px]"}`})})]}),V&&e.jsxs("span",{className:"flex items-center gap-1 text-xs text-status-success animate-page-enter",children:[e.jsx(re,{className:"w-3 h-3"})," Saved"]}),p.error&&e.jsx("span",{className:"text-xs text-status-error max-w-[180px] truncate",children:p.error.message}),e.jsx("button",{onClick:G,disabled:!Q||p.isPending,className:"px-3 py-1.5 text-xs rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed",children:p.isPending?"Saving…":"Save Role"}),!K&&e.jsxs("button",{onClick:()=>M(!0),className:"px-3 py-1.5 text-xs rounded-md text-red-400/60 hover:text-red-400 hover:bg-red-600/10 transition-colors flex items-center gap-1",children:[e.jsx(ne,{className:"w-3 h-3"})," Delete"]})]})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-16 items-start",children:[e.jsxs("div",{className:"space-y-14",children:[e.jsxs("div",{className:"space-y-8",children:[e.jsx(h,{icon:$,color:"text-accent",label:"Identity"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1.5",children:"Display Name"}),e.jsx("input",{type:"text",value:s.title,onChange:r=>v({title:r.target.value}),placeholder:`e.g., ${t.role.charAt(0).toUpperCase()+t.role.slice(1)}`,className:"input text-sm w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1.5",children:"Description"}),e.jsx("textarea",{value:s.description,onChange:r=>v({description:r.target.value}),placeholder:"A short description shown on role cards and in the operations view.",rows:4,className:"input text-sm w-full resize-none"})]})]}),e.jsxs("div",{className:`space-y-14 overflow-hidden transition-all duration-300 ease-out ${s.ops_visible?"opacity-100 max-h-[900px]":"opacity-0 max-h-0 pointer-events-none"}`,"aria-hidden":!s.ops_visible,children:[e.jsxs("div",{className:"space-y-5",children:[e.jsx(h,{icon:I,color:"text-text-tertiary",label:"Prior Step"}),e.jsxs("select",{value:s.parent_role,onChange:r=>v({parent_role:r.target.value}),className:"select text-sm w-full font-mono",children:[e.jsx("option",{value:"",children:"None — root process"}),z.map(r=>e.jsx("option",{value:r.role,children:r.title?`${r.role} — ${r.title}`:r.role},r.role))]}),e.jsx("p",{className:"text-[10px] text-text-tertiary leading-relaxed",children:"Places this role in one Pace Board sequence. A role with no prior step starts its own sequence."})]}),e.jsxs("div",{className:"space-y-5",children:[e.jsx(h,{icon:oe,color:"text-text-tertiary",label:"Upstream Inputs",aside:e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{className:"w-1.5 h-1.5 rounded-full bg-emerald-500"}),e.jsx("span",{className:"text-[9px] font-semibold uppercase tracking-widest text-emerald-600",children:"Live"})]})}),e.jsx(he,{role:t,allRoles:u})]})]})]}),e.jsxs("div",{className:"space-y-14",children:[e.jsxs("div",{children:[e.jsx(h,{icon:le,color:"text-text-quaternary",label:"Escalation Targets",aside:e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{className:"w-1.5 h-1.5 rounded-full bg-emerald-500"}),e.jsx("span",{className:"text-[9px] font-semibold uppercase tracking-widest text-emerald-600",children:"Live"})]})}),e.jsx(ue,{role:t,allRoles:u})]}),e.jsxs("div",{className:"pt-3 pb-4 border-t border-surface-border/40",children:[e.jsx(h,{icon:ie,color:"text-text-quaternary",label:"Members",aside:e.jsx("span",{className:"text-[9px] font-normal normal-case text-text-quaternary",children:"read = what appears · write = what they can act on"})}),e.jsx(pe,{role:t.role})]})]}),e.jsxs("div",{className:"space-y-14",children:[e.jsxs("div",{children:[e.jsx(h,{icon:J,color:"text-cyan-400",label:"Escalation Schema",aside:t.current_schema_version!=null?e.jsxs("span",{className:"text-[9px] font-mono text-text-quaternary",children:["v",t.current_schema_version," in use"]}):void 0}),e.jsxs("p",{className:"text-[10px] text-text-tertiary mb-3 leading-relaxed",children:["The form a person completes to resolve this role's escalations. Versioned — each save adds one; workflows pin any version via"," ",e.jsx("code",{className:"font-mono",children:"schemaVersion"}),"."]}),e.jsx(xe,{to:`/admin/roles/${encodeURIComponent(t.role)}/schema`,className:"text-xs text-accent hover:underline",children:t.form_schema?`Open schema editor — v${t.current_schema_version??1} in use →`:"Define the escalation form →"})]}),e.jsxs("div",{children:[e.jsx(h,{icon:J,color:"text-violet-400",label:"Metadata Schema",aside:!y.has("metadata_schema")&&t.metadata_schema?e.jsx("button",{onClick:()=>F("metadata_schema"),className:"text-[9px] text-accent hover:underline",children:"Edit"}):void 0}),e.jsxs("p",{className:"text-[10px] text-text-tertiary mb-3 leading-relaxed",children:["Validates ",e.jsx("code",{className:"font-mono",children:"metadata"})," at creation time. Keys appear in faceted search autocomplete."]}),!y.has("metadata_schema")&&t.metadata_schema?e.jsx(U,{data:t.metadata_schema}):e.jsxs(e.Fragment,{children:[e.jsx("textarea",{value:s.metadata_schema,onChange:r=>{const o=r.target.value;v({metadata_schema:o}),_(x=>({...x,metadata_schema:C(o).ok?void 0:"Invalid JSON"}))},rows:10,spellCheck:!1,className:"input text-xs font-mono w-full resize-y",placeholder:`{
2
- "type": "object",
3
- "properties": {
4
- "order_id": { "type": "string" }
5
- },
6
- "required": ["order_id"]
7
- }`}),g.metadata_schema&&e.jsx("p",{className:"text-[10px] text-status-error mt-1",children:g.metadata_schema})]})]}),e.jsxs("div",{children:[e.jsx(h,{icon:J,color:"text-text-quaternary",label:"Properties",aside:!y.has("properties")&&t.properties&&Object.keys(t.properties).length>0?e.jsx("button",{onClick:()=>F("properties"),className:"text-[9px] text-accent hover:underline",children:"Edit"}):e.jsx("span",{className:"text-[9px] font-normal normal-case text-text-quaternary",children:"custom JSON"})}),!y.has("properties")&&t.properties&&Object.keys(t.properties).length>0?e.jsx(U,{data:t.properties,defaultCollapsed:!0}):e.jsxs(e.Fragment,{children:[e.jsx("textarea",{value:s.properties,onChange:r=>{const o=r.target.value;v({properties:o}),_(x=>({...x,properties:C(o).ok?void 0:"Invalid JSON"}))},rows:5,spellCheck:!1,className:"input text-xs font-mono w-full resize-none",placeholder:`{
8
- "icon": "wrench",
9
- "color": "#6366f1"
10
- }`}),g.properties&&e.jsx("p",{className:"text-[10px] text-status-error mt-1",children:g.properties})]})]})]})]}),e.jsx(se,{open:W,onClose:()=>M(!1),onConfirm:H,title:"Delete Role",description:e.jsxs(e.Fragment,{children:["Delete role ",e.jsx("span",{className:"font-medium font-mono text-text-primary",children:t.role}),"? This cannot be undone."]}),isPending:c.isPending,error:c.error})]})}export{ke as RoleDetailPage};
11
- //# sourceMappingURL=RoleDetailPage-7j6Mk780.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RoleDetailPage-7j6Mk780.js","sources":["../../src/pages/admin/roles/RoleMembersSection.tsx","../../src/pages/admin/roles/RoleDetailPage.tsx"],"sourcesContent":["import { useUsers } from '../../../api/users';\nimport type { LTUserRole } from '../../../api/types/users';\n\n/**\n * Who can see through this role's window, and how far. Membership is admin or\n * member; a member's reach over the queue is two axes — read (which\n * escalations appear: their own, or the whole queue) and write (which they can\n * claim and resolve: none, their own, or the whole queue).\n */\nexport function RoleMembersSection({ role }: { role: string }) {\n const { data } = useUsers({ role, limit: 100 });\n const users = data?.users ?? [];\n\n if (users.length === 0) {\n return (\n <p className=\"text-[11px] text-text-tertiary\">\n Assign users to this role to staff its queue. Members see and resolve\n escalations here according to their read/write scope; admins manage the\n role itself.\n </p>\n );\n }\n\n return (\n <div className=\"divide-y divide-surface-border/40\">\n {users.map((u) => {\n const membership = u.roles.find((r) => r.role === role);\n if (!membership) return null;\n return (\n <div key={u.id} className=\"flex items-center justify-between py-1.5 gap-2\">\n <span className=\"text-xs text-text-secondary truncate\">\n {u.display_name || u.external_id}\n </span>\n <span className=\"text-[10px] text-text-quaternary font-mono shrink-0\">\n {describeMembership(membership)}\n </span>\n </div>\n );\n })}\n </div>\n );\n}\n\nfunction describeMembership(m: LTUserRole): string {\n if (m.type === 'superadmin' || m.type === 'admin') return m.type;\n return `member · read ${m.read_scope} · write ${m.write_scope}`;\n}\n","import { useState, useEffect, useMemo } from 'react';\nimport { useParams, useNavigate, Link } from 'react-router-dom';\nimport {\n Tag, GitBranch, GitMerge, Network, Trash2, Check, Braces, Users,\n} from 'lucide-react';\nimport {\n useRoleDetails,\n useUpdateRole,\n useDeleteRole,\n useEscalationChains,\n useAddEscalationChain,\n useRemoveEscalationChain,\n type RoleDetail,\n} from '../../../api/roles';\nimport { JsonViewer } from '../../../components/common/data/JsonViewer';\nimport { ConfirmDeleteModal } from '../../../components/common/modal/ConfirmDeleteModal';\nimport { RoleMembersSection } from './RoleMembersSection';\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction safePrettyPrint(value: unknown): string {\n if (value == null) return '';\n return JSON.stringify(value, null, 2);\n}\n\nfunction safeParseJson(text: string): { ok: boolean; value?: Record<string, unknown> } {\n const trimmed = text.trim();\n if (!trimmed) return { ok: true, value: undefined };\n try {\n const parsed = JSON.parse(trimmed);\n if (typeof parsed !== 'object' || Array.isArray(parsed) || parsed === null) return { ok: false };\n return { ok: true, value: parsed };\n } catch {\n return { ok: false };\n }\n}\n\n// ── Section header ────────────────────────────────────────────────────────────\n\nfunction SectionHead({\n icon: Icon,\n color,\n label,\n aside,\n}: {\n icon: React.ElementType;\n color: string;\n label: string;\n aside?: React.ReactNode;\n}) {\n return (\n <div className=\"flex items-center justify-between mb-3 pb-2 border-b border-surface-border\">\n <div className=\"flex items-center gap-2\">\n <Icon className={`w-4 h-4 ${color}`} strokeWidth={1.5} />\n <h2 className=\"section-h2\">{label}</h2>\n </div>\n {aside}\n </div>\n );\n}\n\n// ── Escalation section (live-save) ────────────────────────────────────────────\n\nfunction EscalationSection({ role, allRoles }: { role: RoleDetail; allRoles: RoleDetail[] }) {\n const { data: chainsData } = useEscalationChains();\n const addChain = useAddEscalationChain();\n const removeChain = useRemoveEscalationChain();\n const [newTarget, setNewTarget] = useState('');\n\n const chains = chainsData?.chains ?? [];\n const targets = useMemo(\n () => chains.filter((c) => c.source_role === role.role).map((c) => c.target_role),\n [chains, role.role],\n );\n const available = useMemo(\n () => allRoles\n .map((r) => r.role)\n .filter((r) => r !== role.role && r !== 'superadmin' && !targets.includes(r)),\n [allRoles, role.role, targets],\n );\n\n if (role.role === 'superadmin') {\n return <p className=\"text-[11px] text-text-tertiary\">Superadmins can escalate to any role implicitly.</p>;\n }\n\n return (\n <div className=\"space-y-3\">\n {targets.length === 0 ? (\n <p className=\"text-[11px] text-text-tertiary\">Add a target role to route hand-offs.</p>\n ) : (\n <div className=\"flex flex-wrap gap-1.5\">\n {targets.map((t) => (\n <span\n key={t}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 text-[10px] bg-surface-sunken rounded font-mono text-text-secondary\"\n >\n {t}\n <button\n onClick={() => removeChain.mutate({ source_role: role.role, target_role: t })}\n className=\"text-text-quaternary hover:text-red-400 transition-colors leading-none ml-0.5\"\n >\n ×\n </button>\n </span>\n ))}\n </div>\n )}\n {available.length > 0 && (\n <div className=\"flex items-center gap-2\">\n <select\n value={newTarget}\n onChange={(e) => setNewTarget(e.target.value)}\n className=\"select text-xs font-mono flex-1\"\n >\n <option value=\"\">Add target…</option>\n {available.map((r) => <option key={r} value={r}>{r}</option>)}\n </select>\n <button\n onClick={() => {\n if (!newTarget) return;\n addChain.mutate({ source_role: role.role, target_role: newTarget }, { onSuccess: () => setNewTarget('') });\n }}\n disabled={!newTarget || addChain.isPending}\n className=\"px-2.5 py-1 text-xs rounded bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed shrink-0\"\n >\n {addChain.isPending ? '…' : 'Add'}\n </button>\n </div>\n )}\n </div>\n );\n}\n\n// ── Upstream inputs section (live-save) ───────────────────────────────────────\n\n/**\n * The graph edges that don't fit the line. Prior Step (parent_role) places\n * this role in ONE sequence on the Operations page; upstream inputs declare\n * the roles it also draws from in OTHER sequences — mixin-like, many allowed.\n * The chart shows them as a merge glyph on the station, never as a bend in\n * the sequence.\n */\nfunction UpstreamSection({ role, allRoles }: { role: RoleDetail; allRoles: RoleDetail[] }) {\n const updateRole = useUpdateRole();\n const [newUpstream, setNewUpstream] = useState('');\n\n const upstreams = role.upstream_roles ?? [];\n const available = useMemo(\n () => allRoles\n .map((r) => r.role)\n .filter((r) => r !== role.role && r !== 'superadmin' && !upstreams.includes(r)),\n [allRoles, role.role, upstreams],\n );\n\n const save = (next: string[]) =>\n updateRole.mutate({ role: role.role, upstream_roles: next }, { onSuccess: () => setNewUpstream('') });\n\n return (\n <div className=\"space-y-3\">\n {upstreams.length === 0 ? (\n <p className=\"text-[11px] text-text-tertiary\">\n Add a role from another sequence that this station draws input from.\n Prior Step sets where this role sits in its own sequence; upstream\n inputs mark the side-quests that land here.\n </p>\n ) : (\n <div className=\"flex flex-wrap gap-1.5\">\n {upstreams.map((u) => (\n <span\n key={u}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 text-[10px] bg-surface-sunken rounded font-mono text-text-secondary\"\n >\n {u}\n <button\n onClick={() => save(upstreams.filter((x) => x !== u))}\n className=\"text-text-quaternary hover:text-red-400 transition-colors leading-none ml-0.5\"\n >\n ×\n </button>\n </span>\n ))}\n </div>\n )}\n {available.length > 0 && (\n <div className=\"flex items-center gap-2\">\n <select\n value={newUpstream}\n onChange={(e) => setNewUpstream(e.target.value)}\n className=\"select text-xs font-mono flex-1\"\n >\n <option value=\"\">Add upstream input…</option>\n {available.map((r) => <option key={r} value={r}>{r}</option>)}\n </select>\n <button\n onClick={() => { if (newUpstream) save([...upstreams, newUpstream]); }}\n disabled={!newUpstream || updateRole.isPending}\n className=\"px-2.5 py-1 text-xs rounded bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed shrink-0\"\n >\n {updateRole.isPending ? '…' : 'Add'}\n </button>\n </div>\n )}\n {updateRole.error && (\n <p className=\"text-[10px] text-status-error\">{(updateRole.error as Error).message}</p>\n )}\n </div>\n );\n}\n\n// ── Draft state ───────────────────────────────────────────────────────────────\n\ninterface Draft {\n title: string;\n description: string;\n ops_visible: boolean;\n parent_role: string;\n metadata_schema: string;\n properties: string;\n sla_minutes: string;\n target_per_hour: string;\n worker_count: string;\n}\n\nfunction draftFrom(role: RoleDetail): Draft {\n return {\n title: role.title ?? '',\n description: role.description ?? '',\n ops_visible: role.ops_visible,\n parent_role: role.parent_role ?? '',\n metadata_schema: safePrettyPrint(role.metadata_schema),\n properties: safePrettyPrint(role.properties) || '{}',\n sla_minutes: role.sla_minutes != null ? String(role.sla_minutes) : '',\n target_per_hour: role.target_per_hour != null ? String(role.target_per_hour) : '',\n worker_count: role.worker_count != null ? String(role.worker_count) : '',\n };\n}\n\n// ── Page ──────────────────────────────────────────────────────────────────────\n\nexport function RoleDetailPage() {\n const { role: roleKey } = useParams<{ role: string }>();\n const navigate = useNavigate();\n const { data, isLoading } = useRoleDetails();\n const updateRole = useUpdateRole();\n const deleteRole = useDeleteRole();\n\n const roles = data?.roles ?? [];\n const role = roles.find((r) => r.role === roleKey);\n\n const [draft, setDraft] = useState<Draft>({\n title: '', description: '', ops_visible: false, parent_role: '',\n metadata_schema: '', properties: '{}',\n sla_minutes: '', target_per_hour: '', worker_count: '',\n });\n const [dirty, setDirty] = useState(false);\n const [savedOk, setSavedOk] = useState(false);\n const [errors, setErrors] = useState<{ metadata_schema?: string; properties?: string }>({});\n const [confirmDelete, setConfirmDelete] = useState(false);\n const [editingJson, setEditingJson] = useState(new Set<string>());\n\n const startEditingJson = (field: string) => setEditingJson((prev) => new Set([...prev, field]));\n\n useEffect(() => {\n if (!role) return;\n setDraft(draftFrom(role));\n setDirty(false);\n setSavedOk(false);\n setErrors({});\n setEditingJson(new Set());\n }, [roleKey, role?.role]);\n\n const update = (changes: Partial<Draft>) => {\n setDraft((d) => ({ ...d, ...changes }));\n setDirty(true);\n setSavedOk(false);\n };\n\n const availableParents = useMemo(\n () => roles.filter((r) => {\n if (!role || r.role === role.role) return false;\n let cur: RoleDetail | undefined = r;\n const seen = new Set<string>();\n while (cur?.parent_role) {\n if (cur.parent_role === role.role) return false;\n if (seen.has(cur.parent_role)) break;\n seen.add(cur.parent_role);\n cur = roles.find((x) => x.role === cur!.parent_role);\n }\n return true;\n }),\n [roles, role],\n );\n\n const handleSave = () => {\n const metaResult = safeParseJson(draft.metadata_schema);\n const propsResult = safeParseJson(draft.properties);\n const newErrors: typeof errors = {};\n if (!metaResult.ok) newErrors.metadata_schema = 'Invalid JSON';\n if (!propsResult.ok) newErrors.properties = 'Invalid JSON';\n setErrors(newErrors);\n if (Object.keys(newErrors).length || !role) return;\n\n const parseNum = (s: string) => { const v = parseFloat(s); return isNaN(v) ? null : v; };\n // Staff counts are whole people/machines — round rather than persist 2.5 workers.\n const parseCount = (s: string) => { const v = parseNum(s); return v == null ? null : Math.round(v); };\n\n updateRole.mutate(\n {\n role: role.role,\n title: draft.title.trim() || null,\n description: draft.description.trim() || null,\n ops_visible: draft.ops_visible,\n parent_role: draft.parent_role || null,\n metadata_schema: metaResult.value ?? null,\n properties: propsResult.value ?? {},\n sla_minutes: parseNum(draft.sla_minutes),\n target_per_hour: parseNum(draft.target_per_hour),\n worker_count: parseCount(draft.worker_count),\n },\n {\n onSuccess: () => {\n setDirty(false);\n setSavedOk(true);\n setEditingJson(new Set());\n window.setTimeout(() => setSavedOk(false), 2500);\n },\n },\n );\n };\n\n const handleDelete = () => {\n if (!role) return;\n deleteRole.mutate(role.role, { onSuccess: () => navigate('/admin/roles') });\n };\n\n // ── Loading / not found ───────────────────────────────────────────────────\n\n if (isLoading) {\n return (\n <div className=\"animate-pulse space-y-4\">\n <div className=\"h-8 bg-surface-sunken rounded w-48\" />\n <div className=\"h-4 bg-surface-sunken rounded w-64\" />\n <div className=\"h-64 bg-surface-sunken rounded\" />\n </div>\n );\n }\n\n if (!role) {\n return (\n <div className=\"flex flex-col items-center justify-center py-20 text-center\">\n <Tag className=\"w-12 h-12 text-text-quaternary mb-4\" strokeWidth={1} />\n <h2 className=\"text-lg font-medium text-text-primary mb-2\">Role not found</h2>\n </div>\n );\n }\n\n const inUse = role.user_count > 0 || role.chain_count > 0 || role.workflow_count > 0;\n const canSave = dirty && !Object.values(errors).some(Boolean);\n\n // Any two capacity settings derive the third — hint the missing one.\n const sla = parseFloat(draft.sla_minutes);\n const tph = parseFloat(draft.target_per_hour);\n const wc = parseFloat(draft.worker_count);\n const slaOk = !isNaN(sla) && sla > 0;\n const tphOk = !isNaN(tph) && tph > 0;\n const wcOk = !isNaN(wc) && wc > 0;\n const derivedCapacityHint =\n slaOk && wcOk && !tphOk ? `→ target ≈ ${(wc / (sla / 60)).toFixed(1)}/h` :\n slaOk && tphOk && !wcOk ? `→ workers ≈ ${(tph * (sla / 60)).toFixed(1)}` :\n tphOk && wcOk && !slaOk ? `→ SLA ≈ ${(wc / tph * 60).toFixed(0)}m` : null;\n\n return (\n <div>\n {/* ── Header: identity · capacity set · ops toggle + actions ── */}\n <div className=\"flex items-start justify-between gap-8 mb-12\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-3 mb-1\">\n <Tag className=\"w-5 h-5 text-accent\" strokeWidth={1.5} />\n <h1 className=\"text-lg font-mono font-medium text-text-primary\">{role.role}</h1>\n {role.parent_role && (\n <span className=\"flex items-center gap-1 text-[10px] text-text-quaternary font-mono\">\n <GitBranch className=\"w-3 h-3\" /> {role.parent_role}\n </span>\n )}\n </div>\n {role.title && <p className=\"text-sm text-text-secondary pl-8\">{role.title}</p>}\n </div>\n\n {/* Capacity — one grouped set, centered. Any two settings derive the third. */}\n <div\n className=\"flex items-end gap-4 bg-surface-sunken rounded-lg px-4 py-2.5 shrink-0 mx-auto\"\n title=\"throughput = workers / (sla / 60)\"\n >\n {[\n { key: 'sla_minutes' as const, label: 'SLA', unit: 'min', placeholder: '30' },\n { key: 'target_per_hour' as const, label: 'Target', unit: '/h', placeholder: '20' },\n { key: 'worker_count' as const, label: 'Workers', unit: '', placeholder: '4' },\n ].map(({ key, label, unit, placeholder }) => (\n <div key={key}>\n <label className=\"block text-[9px] font-semibold uppercase tracking-widest text-text-quaternary mb-1\">\n {label}\n {unit && <span className=\"normal-case font-normal ml-1\">{unit}</span>}\n </label>\n <input\n type=\"number\"\n min=\"0\"\n step=\"any\"\n value={draft[key]}\n onChange={(e) => update({ [key]: e.target.value })}\n placeholder={placeholder}\n className=\"input text-xs w-16 font-mono\"\n />\n </div>\n ))}\n {derivedCapacityHint && (\n <span className=\"text-[10px] text-accent font-mono whitespace-nowrap pb-2\">\n {derivedCapacityHint}\n </span>\n )}\n </div>\n\n <div className=\"flex items-center gap-3 shrink-0\">\n {/* Ops — on the same line as Save: this role is (or isn't) a station */}\n <div className=\"flex items-center gap-2\" title=\"Show as a station on the Pace Board\">\n <span className=\"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary\">Ops</span>\n <button\n onClick={() => update({ ops_visible: !draft.ops_visible })}\n className={`w-9 h-5 rounded-full transition-colors relative shrink-0 ${\n draft.ops_visible ? 'bg-accent' : 'bg-surface-border'\n }`}\n >\n <span\n className={`absolute top-[3px] left-0 w-3.5 h-3.5 rounded-full bg-white transition-transform shadow ${\n draft.ops_visible ? 'translate-x-[18px]' : 'translate-x-[3px]'\n }`}\n />\n </button>\n </div>\n {savedOk && (\n <span className=\"flex items-center gap-1 text-xs text-status-success animate-page-enter\">\n <Check className=\"w-3 h-3\" /> Saved\n </span>\n )}\n {updateRole.error && (\n <span className=\"text-xs text-status-error max-w-[180px] truncate\">\n {(updateRole.error as Error).message}\n </span>\n )}\n <button\n onClick={handleSave}\n disabled={!canSave || updateRole.isPending}\n className=\"px-3 py-1.5 text-xs rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {updateRole.isPending ? 'Saving…' : 'Save Role'}\n </button>\n {!inUse && (\n <button\n onClick={() => setConfirmDelete(true)}\n className=\"px-3 py-1.5 text-xs rounded-md text-red-400/60 hover:text-red-400 hover:bg-red-600/10 transition-colors flex items-center gap-1\"\n >\n <Trash2 className=\"w-3 h-3\" /> Delete\n </button>\n )}\n </div>\n </div>\n\n {/* ── Three-column body ── */}\n <div className=\"grid grid-cols-3 gap-16 items-start\">\n\n {/* ── Col 1: Identity ── */}\n <div className=\"space-y-14\">\n\n {/* Identity */}\n <div className=\"space-y-8\">\n <SectionHead icon={Tag} color=\"text-accent\" label=\"Identity\" />\n\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1.5\">\n Display Name\n </label>\n <input\n type=\"text\"\n value={draft.title}\n onChange={(e) => update({ title: e.target.value })}\n placeholder={`e.g., ${role.role.charAt(0).toUpperCase() + role.role.slice(1)}`}\n className=\"input text-sm w-full\"\n />\n </div>\n\n <div>\n <label className=\"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1.5\">\n Description\n </label>\n <textarea\n value={draft.description}\n onChange={(e) => update({ description: e.target.value })}\n placeholder=\"A short description shown on role cards and in the operations view.\"\n rows={4}\n className=\"input text-sm w-full resize-none\"\n />\n </div>\n </div>\n\n {/* Sequence placement — only meaningful for stations, so these two\n sections follow the Ops toggle, easing in and out with it. */}\n <div\n className={`space-y-14 overflow-hidden transition-all duration-300 ease-out ${\n draft.ops_visible ? 'opacity-100 max-h-[900px]' : 'opacity-0 max-h-0 pointer-events-none'\n }`}\n aria-hidden={!draft.ops_visible}\n >\n {/* Prior Step */}\n <div className=\"space-y-5\">\n <SectionHead icon={GitBranch} color=\"text-text-tertiary\" label=\"Prior Step\" />\n <select\n value={draft.parent_role}\n onChange={(e) => update({ parent_role: e.target.value })}\n className=\"select text-sm w-full font-mono\"\n >\n <option value=\"\">None — root process</option>\n {availableParents.map((r) => (\n <option key={r.role} value={r.role}>\n {r.title ? `${r.role} — ${r.title}` : r.role}\n </option>\n ))}\n </select>\n <p className=\"text-[10px] text-text-tertiary leading-relaxed\">\n Places this role in one Pace Board sequence. A role with no prior\n step starts its own sequence.\n </p>\n </div>\n\n {/* Upstream inputs — cross-sequence graph edges, live-save */}\n <div className=\"space-y-5\">\n <SectionHead\n icon={GitMerge}\n color=\"text-text-tertiary\"\n label=\"Upstream Inputs\"\n aside={\n <div className=\"flex items-center gap-1\">\n <span className=\"w-1.5 h-1.5 rounded-full bg-emerald-500\" />\n <span className=\"text-[9px] font-semibold uppercase tracking-widest text-emerald-600\">Live</span>\n </div>\n }\n />\n <UpstreamSection role={role} allRoles={roles} />\n </div>\n </div>\n\n </div>\n\n {/* ── Col 2: Routing & People ── */}\n <div className=\"space-y-14\">\n\n {/* Escalation targets — live */}\n <div>\n <SectionHead\n icon={Network}\n color=\"text-text-quaternary\"\n label=\"Escalation Targets\"\n aside={\n <div className=\"flex items-center gap-1\">\n <span className=\"w-1.5 h-1.5 rounded-full bg-emerald-500\" />\n <span className=\"text-[9px] font-semibold uppercase tracking-widest text-emerald-600\">Live</span>\n </div>\n }\n />\n <EscalationSection role={role} allRoles={roles} />\n </div>\n\n {/* Members — who can see through this window, and how far */}\n <div className=\"pt-3 pb-4 border-t border-surface-border/40\">\n <SectionHead\n icon={Users}\n color=\"text-text-quaternary\"\n label=\"Members\"\n aside={\n <span className=\"text-[9px] font-normal normal-case text-text-quaternary\">\n read = what appears · write = what they can act on\n </span>\n }\n />\n <RoleMembersSection role={role.role} />\n </div>\n </div>\n\n {/* ── Col 3: Schemas & Properties ── */}\n <div className=\"space-y-14\">\n {/* Escalation Schema — versioned, edited on its own page */}\n <div>\n <SectionHead\n icon={Braces}\n color=\"text-cyan-400\"\n label=\"Escalation Schema\"\n aside={\n role.current_schema_version != null ? (\n <span className=\"text-[9px] font-mono text-text-quaternary\">v{role.current_schema_version} in use</span>\n ) : undefined\n }\n />\n <p className=\"text-[10px] text-text-tertiary mb-3 leading-relaxed\">\n The form a person completes to resolve this role's escalations.\n Versioned — each save adds one; workflows pin any version via{' '}\n <code className=\"font-mono\">schemaVersion</code>.\n </p>\n <Link\n to={`/admin/roles/${encodeURIComponent(role.role)}/schema`}\n className=\"text-xs text-accent hover:underline\"\n >\n {role.form_schema\n ? `Open schema editor — v${role.current_schema_version ?? 1} in use →`\n : 'Define the escalation form →'}\n </Link>\n </div>\n\n {/* Metadata Schema */}\n <div>\n <SectionHead\n icon={Braces}\n color=\"text-violet-400\"\n label=\"Metadata Schema\"\n aside={\n !editingJson.has('metadata_schema') && role.metadata_schema ? (\n <button onClick={() => startEditingJson('metadata_schema')} className=\"text-[9px] text-accent hover:underline\">Edit</button>\n ) : undefined\n }\n />\n <p className=\"text-[10px] text-text-tertiary mb-3 leading-relaxed\">\n Validates <code className=\"font-mono\">metadata</code> at creation time. Keys appear in faceted search autocomplete.\n </p>\n {!editingJson.has('metadata_schema') && role.metadata_schema ? (\n <JsonViewer data={role.metadata_schema} />\n ) : (\n <>\n <textarea\n value={draft.metadata_schema}\n onChange={(e) => {\n const val = e.target.value;\n update({ metadata_schema: val });\n setErrors((prev) => ({ ...prev, metadata_schema: safeParseJson(val).ok ? undefined : 'Invalid JSON' }));\n }}\n rows={10}\n spellCheck={false}\n className=\"input text-xs font-mono w-full resize-y\"\n placeholder={'{\\n \"type\": \"object\",\\n \"properties\": {\\n \"order_id\": { \"type\": \"string\" }\\n },\\n \"required\": [\"order_id\"]\\n}'}\n />\n {errors.metadata_schema && <p className=\"text-[10px] text-status-error mt-1\">{errors.metadata_schema}</p>}\n </>\n )}\n </div>\n\n {/* Properties (free bag) */}\n <div>\n <SectionHead\n icon={Braces}\n color=\"text-text-quaternary\"\n label=\"Properties\"\n aside={\n !editingJson.has('properties') && role.properties && Object.keys(role.properties).length > 0 ? (\n <button onClick={() => startEditingJson('properties')} className=\"text-[9px] text-accent hover:underline\">Edit</button>\n ) : (\n <span className=\"text-[9px] font-normal normal-case text-text-quaternary\">custom JSON</span>\n )\n }\n />\n {!editingJson.has('properties') && role.properties && Object.keys(role.properties).length > 0 ? (\n <JsonViewer data={role.properties} defaultCollapsed />\n ) : (\n <>\n <textarea\n value={draft.properties}\n onChange={(e) => {\n const val = e.target.value;\n update({ properties: val });\n setErrors((prev) => ({ ...prev, properties: safeParseJson(val).ok ? undefined : 'Invalid JSON' }));\n }}\n rows={5}\n spellCheck={false}\n className=\"input text-xs font-mono w-full resize-none\"\n placeholder={'{\\n \"icon\": \"wrench\",\\n \"color\": \"#6366f1\"\\n}'}\n />\n {errors.properties && <p className=\"text-[10px] text-status-error mt-1\">{errors.properties}</p>}\n </>\n )}\n </div>\n </div>\n </div>\n\n {/* ── Delete confirmation ── */}\n <ConfirmDeleteModal\n open={confirmDelete}\n onClose={() => setConfirmDelete(false)}\n onConfirm={handleDelete}\n title=\"Delete Role\"\n description={\n <>\n Delete role <span className=\"font-medium font-mono text-text-primary\">{role.role}</span>? This cannot be undone.\n </>\n }\n isPending={deleteRole.isPending}\n error={deleteRole.error as Error | null}\n />\n </div>\n );\n}\n"],"names":["RoleMembersSection","role","data","useUsers","users","jsx","u","membership","r","jsxs","describeMembership","m","safePrettyPrint","value","safeParseJson","text","trimmed","parsed","SectionHead","Icon","color","label","aside","EscalationSection","allRoles","chainsData","useEscalationChains","addChain","useAddEscalationChain","removeChain","useRemoveEscalationChain","newTarget","setNewTarget","useState","chains","targets","useMemo","c","available","t","e","UpstreamSection","updateRole","useUpdateRole","newUpstream","setNewUpstream","upstreams","save","next","x","draftFrom","RoleDetailPage","roleKey","useParams","navigate","useNavigate","isLoading","useRoleDetails","deleteRole","useDeleteRole","roles","draft","setDraft","dirty","setDirty","savedOk","setSavedOk","errors","setErrors","confirmDelete","setConfirmDelete","editingJson","setEditingJson","startEditingJson","field","prev","useEffect","update","changes","d","availableParents","cur","seen","handleSave","metaResult","propsResult","newErrors","parseNum","s","v","parseCount","handleDelete","Tag","inUse","canSave","sla","tph","wc","slaOk","tphOk","wcOk","derivedCapacityHint","GitBranch","key","unit","placeholder","Check","Trash2","GitMerge","Network","Users","Braces","Link","JsonViewer","Fragment","val","ConfirmDeleteModal"],"mappings":"4cASO,SAASA,GAAmB,CAAE,KAAAC,GAA0B,CAC7D,KAAM,CAAE,KAAAC,GAASC,GAAS,CAAE,KAAAF,EAAM,MAAO,IAAK,EACxCG,GAAQF,GAAA,YAAAA,EAAM,QAAS,CAAA,EAE7B,OAAIE,EAAM,SAAW,EAEjBC,EAAAA,IAAC,IAAA,CAAE,UAAU,iCAAiC,SAAA,6JAI9C,QAKD,MAAA,CAAI,UAAU,oCACZ,SAAAD,EAAM,IAAKE,GAAM,CAChB,MAAMC,EAAaD,EAAE,MAAM,KAAME,GAAMA,EAAE,OAASP,CAAI,EACtD,OAAKM,EAEHE,EAAAA,KAAC,MAAA,CAAe,UAAU,iDACxB,SAAA,CAAAJ,MAAC,QAAK,UAAU,uCACb,SAAAC,EAAE,cAAgBA,EAAE,YACvB,QACC,OAAA,CAAK,UAAU,sDACb,SAAAI,GAAmBH,CAAU,CAAA,CAChC,CAAA,CAAA,EANQD,EAAE,EAOZ,EATsB,IAW1B,CAAC,CAAA,CACH,CAEJ,CAEA,SAASI,GAAmBC,EAAuB,CACjD,OAAIA,EAAE,OAAS,cAAgBA,EAAE,OAAS,QAAgBA,EAAE,KACrD,iBAAiBA,EAAE,UAAU,YAAYA,EAAE,WAAW,EAC/D,CC1BA,SAASC,EAAgBC,EAAwB,CAC/C,OAAIA,GAAS,KAAa,GACnB,KAAK,UAAUA,EAAO,KAAM,CAAC,CACtC,CAEA,SAASC,EAAcC,EAAgE,CACrF,MAAMC,EAAUD,EAAK,KAAA,EACrB,GAAI,CAACC,EAAS,MAAO,CAAE,GAAI,GAAM,MAAO,MAAA,EACxC,GAAI,CACF,MAAMC,EAAS,KAAK,MAAMD,CAAO,EACjC,OAAI,OAAOC,GAAW,UAAY,MAAM,QAAQA,CAAM,GAAKA,IAAW,KAAa,CAAE,GAAI,EAAA,EAClF,CAAE,GAAI,GAAM,MAAOA,CAAA,CAC5B,MAAQ,CACN,MAAO,CAAE,GAAI,EAAA,CACf,CACF,CAIA,SAASC,EAAY,CACnB,KAAMC,EACN,MAAAC,EACA,MAAAC,EACA,MAAAC,CACF,EAKG,CACD,OACEb,EAAAA,KAAC,MAAA,CAAI,UAAU,6EACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAJ,MAACc,GAAK,UAAW,WAAWC,CAAK,GAAI,YAAa,IAAK,EACvDf,EAAAA,IAAC,KAAA,CAAG,UAAU,aAAc,SAAAgB,CAAA,CAAM,CAAA,EACpC,EACCC,CAAA,EACH,CAEJ,CAIA,SAASC,GAAkB,CAAE,KAAAtB,EAAM,SAAAuB,GAA0D,CAC3F,KAAM,CAAE,KAAMC,CAAA,EAAeC,EAAA,EACvBC,EAAWC,GAAA,EACXC,EAAcC,GAAA,EACd,CAACC,EAAWC,CAAY,EAAIC,EAAAA,SAAS,EAAE,EAEvCC,GAAST,GAAA,YAAAA,EAAY,SAAU,CAAA,EAC/BU,EAAUC,EAAAA,QACd,IAAMF,EAAO,OAAQG,GAAMA,EAAE,cAAgBpC,EAAK,IAAI,EAAE,IAAKoC,GAAMA,EAAE,WAAW,EAChF,CAACH,EAAQjC,EAAK,IAAI,CAAA,EAEdqC,EAAYF,EAAAA,QAChB,IAAMZ,EACH,IAAKhB,GAAMA,EAAE,IAAI,EACjB,OAAQA,GAAMA,IAAMP,EAAK,MAAQO,IAAM,cAAgB,CAAC2B,EAAQ,SAAS3B,CAAC,CAAC,EAC9E,CAACgB,EAAUvB,EAAK,KAAMkC,CAAO,CAAA,EAG/B,OAAIlC,EAAK,OAAS,aACTI,EAAAA,IAAC,IAAA,CAAE,UAAU,iCAAiC,SAAA,mDAAgD,EAIrGI,EAAAA,KAAC,MAAA,CAAI,UAAU,YACZ,SAAA,CAAA0B,EAAQ,SAAW,EAClB9B,EAAAA,IAAC,IAAA,CAAE,UAAU,iCAAiC,SAAA,uCAAA,CAAqC,EAEnFA,MAAC,OAAI,UAAU,yBACZ,SAAA8B,EAAQ,IAAKI,GACZ9B,EAAAA,KAAC,OAAA,CAEC,UAAU,iHAET,SAAA,CAAA8B,EACDlC,EAAAA,IAAC,SAAA,CACC,QAAS,IAAMwB,EAAY,OAAO,CAAE,YAAa5B,EAAK,KAAM,YAAasC,EAAG,EAC5E,UAAU,gFACX,SAAA,GAAA,CAAA,CAED,CAAA,EATKA,CAAA,CAWR,EACH,EAEDD,EAAU,OAAS,GAClB7B,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAA,EAAAA,KAAC,SAAA,CACC,MAAOsB,EACP,SAAWS,GAAMR,EAAaQ,EAAE,OAAO,KAAK,EAC5C,UAAU,kCAEV,SAAA,CAAAnC,EAAAA,IAAC,SAAA,CAAO,MAAM,GAAG,SAAA,cAAW,EAC3BiC,EAAU,IAAK9B,GAAMH,EAAAA,IAAC,UAAe,MAAOG,EAAI,SAAAA,CAAA,EAAdA,CAAgB,CAAS,CAAA,CAAA,CAAA,EAE9DH,EAAAA,IAAC,SAAA,CACC,QAAS,IAAM,CACR0B,GACLJ,EAAS,OAAO,CAAE,YAAa1B,EAAK,KAAM,YAAa8B,CAAA,EAAa,CAAE,UAAW,IAAMC,EAAa,EAAE,EAAG,CAC3G,EACA,SAAU,CAACD,GAAaJ,EAAS,UACjC,UAAU,2JAET,SAAAA,EAAS,UAAY,IAAM,KAAA,CAAA,CAC9B,CAAA,CACF,CAAA,EAEJ,CAEJ,CAWA,SAASc,GAAgB,CAAE,KAAAxC,EAAM,SAAAuB,GAA0D,CACzF,MAAMkB,EAAaC,EAAA,EACb,CAACC,EAAaC,CAAc,EAAIZ,EAAAA,SAAS,EAAE,EAE3Ca,EAAY7C,EAAK,gBAAkB,CAAA,EACnCqC,EAAYF,EAAAA,QAChB,IAAMZ,EACH,IAAKhB,GAAMA,EAAE,IAAI,EACjB,OAAQA,GAAMA,IAAMP,EAAK,MAAQO,IAAM,cAAgB,CAACsC,EAAU,SAAStC,CAAC,CAAC,EAChF,CAACgB,EAAUvB,EAAK,KAAM6C,CAAS,CAAA,EAG3BC,EAAQC,GACZN,EAAW,OAAO,CAAE,KAAMzC,EAAK,KAAM,eAAgB+C,CAAA,EAAQ,CAAE,UAAW,IAAMH,EAAe,EAAE,EAAG,EAEtG,OACEpC,EAAAA,KAAC,MAAA,CAAI,UAAU,YACZ,SAAA,CAAAqC,EAAU,SAAW,EACpBzC,EAAAA,IAAC,IAAA,CAAE,UAAU,iCAAiC,SAAA,qLAAA,CAI9C,EAEAA,MAAC,OAAI,UAAU,yBACZ,SAAAyC,EAAU,IAAKxC,GACdG,EAAAA,KAAC,OAAA,CAEC,UAAU,iHAET,SAAA,CAAAH,EACDD,EAAAA,IAAC,SAAA,CACC,QAAS,IAAM0C,EAAKD,EAAU,OAAQG,GAAMA,IAAM3C,CAAC,CAAC,EACpD,UAAU,gFACX,SAAA,GAAA,CAAA,CAED,CAAA,EATKA,CAAA,CAWR,EACH,EAEDgC,EAAU,OAAS,GAClB7B,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAA,EAAAA,KAAC,SAAA,CACC,MAAOmC,EACP,SAAWJ,GAAMK,EAAeL,EAAE,OAAO,KAAK,EAC9C,UAAU,kCAEV,SAAA,CAAAnC,EAAAA,IAAC,SAAA,CAAO,MAAM,GAAG,SAAA,sBAAmB,EACnCiC,EAAU,IAAK9B,GAAMH,EAAAA,IAAC,UAAe,MAAOG,EAAI,SAAAA,CAAA,EAAdA,CAAgB,CAAS,CAAA,CAAA,CAAA,EAE9DH,EAAAA,IAAC,SAAA,CACC,QAAS,IAAM,CAAMuC,GAAaG,EAAK,CAAC,GAAGD,EAAWF,CAAW,CAAC,CAAG,EACrE,SAAU,CAACA,GAAeF,EAAW,UACrC,UAAU,2JAET,SAAAA,EAAW,UAAY,IAAM,KAAA,CAAA,CAChC,EACF,EAEDA,EAAW,OACVrC,MAAC,IAAA,CAAE,UAAU,gCAAkC,SAAAqC,EAAW,MAAgB,OAAA,CAAQ,CAAA,EAEtF,CAEJ,CAgBA,SAASQ,GAAUjD,EAAyB,CAC1C,MAAO,CACL,MAAOA,EAAK,OAAS,GACrB,YAAaA,EAAK,aAAe,GACjC,YAAaA,EAAK,YAClB,YAAaA,EAAK,aAAe,GACjC,gBAAiBW,EAAgBX,EAAK,eAAe,EACrD,WAAYW,EAAgBX,EAAK,UAAU,GAAK,KAChD,YAAaA,EAAK,aAAe,KAAO,OAAOA,EAAK,WAAW,EAAI,GACnE,gBAAiBA,EAAK,iBAAmB,KAAO,OAAOA,EAAK,eAAe,EAAI,GAC/E,aAAcA,EAAK,cAAgB,KAAO,OAAOA,EAAK,YAAY,EAAI,EAAA,CAE1E,CAIO,SAASkD,IAAiB,CAC/B,KAAM,CAAE,KAAMC,CAAA,EAAYC,GAAA,EACpBC,EAAWC,GAAA,EACX,CAAE,KAAArD,EAAM,UAAAsD,CAAA,EAAcC,EAAA,EACtBf,EAAaC,EAAA,EACbe,EAAaC,EAAA,EAEbC,GAAQ1D,GAAA,YAAAA,EAAM,QAAS,CAAA,EACvBD,EAAO2D,EAAM,KAAM,GAAM,EAAE,OAASR,CAAO,EAE3C,CAACS,EAAOC,CAAQ,EAAI7B,WAAgB,CACxC,MAAO,GAAI,YAAa,GAAI,YAAa,GAAO,YAAa,GAC7D,gBAAiB,GAAI,WAAY,KACjC,YAAa,GAAI,gBAAiB,GAAI,aAAc,EAAA,CACrD,EACK,CAAC8B,EAAOC,CAAQ,EAAI/B,EAAAA,SAAS,EAAK,EAClC,CAACgC,EAASC,CAAU,EAAIjC,EAAAA,SAAS,EAAK,EACtC,CAACkC,EAAQC,CAAS,EAAInC,EAAAA,SAA4D,CAAA,CAAE,EACpF,CAACoC,EAAeC,CAAgB,EAAIrC,EAAAA,SAAS,EAAK,EAClD,CAACsC,EAAaC,CAAc,EAAIvC,EAAAA,SAAS,IAAI,GAAa,EAE1DwC,EAAoBC,GAAkBF,EAAgBG,GAAS,IAAI,IAAI,CAAC,GAAGA,EAAMD,CAAK,CAAC,CAAC,EAE9FE,EAAAA,UAAU,IAAM,CACT3E,IACL6D,EAASZ,GAAUjD,CAAI,CAAC,EACxB+D,EAAS,EAAK,EACdE,EAAW,EAAK,EAChBE,EAAU,CAAA,CAAE,EACZI,EAAe,IAAI,GAAK,EAC1B,EAAG,CAACpB,EAASnD,GAAA,YAAAA,EAAM,IAAI,CAAC,EAExB,MAAM4E,EAAUC,GAA4B,CAC1ChB,EAAUiB,IAAO,CAAE,GAAGA,EAAG,GAAGD,GAAU,EACtCd,EAAS,EAAI,EACbE,EAAW,EAAK,CAClB,EAEMc,EAAmB5C,EAAAA,QACvB,IAAMwB,EAAM,OAAQ,GAAM,CACxB,GAAI,CAAC3D,GAAQ,EAAE,OAASA,EAAK,KAAM,MAAO,GAC1C,IAAIgF,EAA8B,EAClC,MAAMC,MAAW,IACjB,KAAOD,GAAA,MAAAA,EAAK,aAAa,CACvB,GAAIA,EAAI,cAAgBhF,EAAK,KAAM,MAAO,GAC1C,GAAIiF,EAAK,IAAID,EAAI,WAAW,EAAG,MAC/BC,EAAK,IAAID,EAAI,WAAW,EACxBA,EAAMrB,EAAM,KAAMX,GAAMA,EAAE,OAASgC,EAAK,WAAW,CACrD,CACA,MAAO,EACT,CAAC,EACD,CAACrB,EAAO3D,CAAI,CAAA,EAGRkF,EAAa,IAAM,CACvB,MAAMC,EAAatE,EAAc+C,EAAM,eAAe,EAChDwB,EAAcvE,EAAc+C,EAAM,UAAU,EAC5CyB,EAA2B,CAAA,EAIjC,GAHKF,EAAW,KAAIE,EAAU,gBAAkB,gBAC3CD,EAAY,KAAIC,EAAU,WAAa,gBAC5ClB,EAAUkB,CAAS,EACf,OAAO,KAAKA,CAAS,EAAE,QAAU,CAACrF,EAAM,OAE5C,MAAMsF,EAAYC,GAAc,CAAE,MAAMC,EAAI,WAAWD,CAAC,EAAG,OAAO,MAAMC,CAAC,EAAI,KAAOA,CAAG,EAEjFC,EAAcF,GAAc,CAAE,MAAMC,EAAIF,EAASC,CAAC,EAAG,OAAOC,GAAK,KAAO,KAAO,KAAK,MAAMA,CAAC,CAAG,EAEpG/C,EAAW,OACT,CACE,KAAMzC,EAAK,KACX,MAAO4D,EAAM,MAAM,KAAA,GAAU,KAC7B,YAAaA,EAAM,YAAY,KAAA,GAAU,KACzC,YAAaA,EAAM,YACnB,YAAaA,EAAM,aAAe,KAClC,gBAAiBuB,EAAW,OAAS,KACrC,WAAYC,EAAY,OAAS,CAAA,EACjC,YAAaE,EAAS1B,EAAM,WAAW,EACvC,gBAAiB0B,EAAS1B,EAAM,eAAe,EAC/C,aAAc6B,EAAW7B,EAAM,YAAY,CAAA,EAE7C,CACE,UAAW,IAAM,CACfG,EAAS,EAAK,EACdE,EAAW,EAAI,EACfM,EAAe,IAAI,GAAK,EACxB,OAAO,WAAW,IAAMN,EAAW,EAAK,EAAG,IAAI,CACjD,CAAA,CACF,CAEJ,EAEMyB,EAAe,IAAM,CACpB1F,GACLyD,EAAW,OAAOzD,EAAK,KAAM,CAAE,UAAW,IAAMqD,EAAS,cAAc,EAAG,CAC5E,EAIA,GAAIE,EACF,OACE/C,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAJ,EAAAA,IAAC,MAAA,CAAI,UAAU,oCAAA,CAAqC,EACpDA,EAAAA,IAAC,MAAA,CAAI,UAAU,oCAAA,CAAqC,EACpDA,EAAAA,IAAC,MAAA,CAAI,UAAU,gCAAA,CAAiC,CAAA,EAClD,EAIJ,GAAI,CAACJ,EACH,OACEQ,EAAAA,KAAC,MAAA,CAAI,UAAU,8DACb,SAAA,CAAAJ,EAAAA,IAACuF,EAAA,CAAI,UAAU,sCAAsC,YAAa,EAAG,EACrEvF,EAAAA,IAAC,KAAA,CAAG,UAAU,6CAA6C,SAAA,gBAAA,CAAc,CAAA,EAC3E,EAIJ,MAAMwF,EAAQ5F,EAAK,WAAa,GAAKA,EAAK,YAAc,GAAKA,EAAK,eAAiB,EAC7E6F,EAAU/B,GAAS,CAAC,OAAO,OAAOI,CAAM,EAAE,KAAK,OAAO,EAGtD4B,EAAM,WAAWlC,EAAM,WAAW,EAClCmC,EAAM,WAAWnC,EAAM,eAAe,EACtCoC,EAAK,WAAWpC,EAAM,YAAY,EAClCqC,EAAQ,CAAC,MAAMH,CAAG,GAAKA,EAAM,EAC7BI,EAAQ,CAAC,MAAMH,CAAG,GAAKA,EAAM,EAC7BI,EAAO,CAAC,MAAMH,CAAE,GAAKA,EAAK,EAC1BI,EACJH,GAASE,GAAQ,CAACD,EAAQ,eAAeF,GAAMF,EAAM,KAAK,QAAQ,CAAC,CAAC,KACpEG,GAASC,GAAS,CAACC,EAAO,gBAAgBJ,GAAOD,EAAM,KAAK,QAAQ,CAAC,CAAC,GACtEI,GAASC,GAAQ,CAACF,EAAQ,YAAYD,EAAKD,EAAM,IAAI,QAAQ,CAAC,CAAC,IAAM,KAEvE,cACG,MAAA,CAEC,SAAA,CAAAvF,EAAAA,KAAC,MAAA,CAAI,UAAU,+CACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,UACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,+BACb,SAAA,CAAAJ,EAAAA,IAACuF,EAAA,CAAI,UAAU,sBAAsB,YAAa,IAAK,EACvDvF,EAAAA,IAAC,KAAA,CAAG,UAAU,kDAAmD,WAAK,KAAK,EAC1EJ,EAAK,aACJQ,OAAC,OAAA,CAAK,UAAU,qEACd,SAAA,CAAAJ,EAAAA,IAACiG,EAAA,CAAU,UAAU,SAAA,CAAU,EAAE,IAAErG,EAAK,WAAA,CAAA,CAC1C,CAAA,EAEJ,EACCA,EAAK,OAASI,EAAAA,IAAC,KAAE,UAAU,mCAAoC,WAAK,KAAA,CAAM,CAAA,EAC7E,EAGAI,EAAAA,KAAC,MAAA,CACC,UAAU,iFACV,MAAM,oCAEL,SAAA,CAAA,CACC,CAAE,IAAK,cAA6B,MAAO,MAAW,KAAM,MAAO,YAAa,IAAA,EAChF,CAAE,IAAK,kBAA6B,MAAO,SAAW,KAAM,KAAO,YAAa,IAAA,EAChF,CAAE,IAAK,eAA6B,MAAO,UAAW,KAAM,GAAO,YAAa,GAAA,CAAI,EACpF,IAAI,CAAC,CAAE,IAAA8F,EAAK,MAAAlF,EAAO,KAAAmF,EAAM,YAAAC,CAAA,IACzBhG,EAAAA,KAAC,MAAA,CACC,SAAA,CAAAA,EAAAA,KAAC,QAAA,CAAM,UAAU,qFACd,SAAA,CAAAY,EACAmF,GAAQnG,EAAAA,IAAC,OAAA,CAAK,UAAU,+BAAgC,SAAAmG,CAAA,CAAK,CAAA,EAChE,EACAnG,EAAAA,IAAC,QAAA,CACC,KAAK,SACL,IAAI,IACJ,KAAK,MACL,MAAOwD,EAAM0C,CAAG,EAChB,SAAW/D,GAAMqC,EAAO,CAAE,CAAC0B,CAAG,EAAG/D,EAAE,OAAO,MAAO,EACjD,YAAAiE,EACA,UAAU,8BAAA,CAAA,CACZ,CAAA,EAbQF,CAcV,CACD,EACAF,GACChG,EAAAA,IAAC,OAAA,CAAK,UAAU,2DACb,SAAAgG,CAAA,CACH,CAAA,CAAA,CAAA,EAIJ5F,EAAAA,KAAC,MAAA,CAAI,UAAU,mCAEb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,0BAA0B,MAAM,sCAC7C,SAAA,CAAAJ,EAAAA,IAAC,OAAA,CAAK,UAAU,yEAAyE,SAAA,MAAG,EAC5FA,EAAAA,IAAC,SAAA,CACC,QAAS,IAAMwE,EAAO,CAAE,YAAa,CAAChB,EAAM,YAAa,EACzD,UAAW,4DACTA,EAAM,YAAc,YAAc,mBACpC,GAEA,SAAAxD,EAAAA,IAAC,OAAA,CACC,UAAW,2FACTwD,EAAM,YAAc,qBAAuB,mBAC7C,EAAA,CAAA,CACF,CAAA,CACF,EACF,EACCI,GACCxD,EAAAA,KAAC,OAAA,CAAK,UAAU,yEACd,SAAA,CAAAJ,EAAAA,IAACqG,GAAA,CAAM,UAAU,SAAA,CAAU,EAAE,QAAA,EAC/B,EAEDhE,EAAW,OACVrC,MAAC,OAAA,CAAK,UAAU,mDACZ,SAAAqC,EAAW,MAAgB,OAAA,CAC/B,EAEFrC,EAAAA,IAAC,SAAA,CACC,QAAS8E,EACT,SAAU,CAACW,GAAWpD,EAAW,UACjC,UAAU,qJAET,SAAAA,EAAW,UAAY,UAAY,WAAA,CAAA,EAErC,CAACmD,GACApF,EAAAA,KAAC,SAAA,CACC,QAAS,IAAM6D,EAAiB,EAAI,EACpC,UAAU,kIAEV,SAAA,CAAAjE,EAAAA,IAACsG,GAAA,CAAO,UAAU,SAAA,CAAU,EAAE,SAAA,CAAA,CAAA,CAChC,CAAA,CAEJ,CAAA,EACF,EAGAlG,EAAAA,KAAC,MAAA,CAAI,UAAU,sCAGb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,aAGb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,YACb,SAAA,CAAAJ,MAACa,GAAY,KAAM0E,EAAK,MAAM,cAAc,MAAM,WAAW,SAE5D,MAAA,CACC,SAAA,CAAAvF,EAAAA,IAAC,QAAA,CAAM,UAAU,sFAAsF,SAAA,eAEvG,EACAA,EAAAA,IAAC,QAAA,CACC,KAAK,OACL,MAAOwD,EAAM,MACb,SAAWrB,GAAMqC,EAAO,CAAE,MAAOrC,EAAE,OAAO,MAAO,EACjD,YAAa,SAASvC,EAAK,KAAK,OAAO,CAAC,EAAE,YAAA,EAAgBA,EAAK,KAAK,MAAM,CAAC,CAAC,GAC5E,UAAU,sBAAA,CAAA,CACZ,EACF,SAEC,MAAA,CACC,SAAA,CAAAI,EAAAA,IAAC,QAAA,CAAM,UAAU,sFAAsF,SAAA,cAEvG,EACAA,EAAAA,IAAC,WAAA,CACC,MAAOwD,EAAM,YACb,SAAWrB,GAAMqC,EAAO,CAAE,YAAarC,EAAE,OAAO,MAAO,EACvD,YAAY,sEACZ,KAAM,EACN,UAAU,kCAAA,CAAA,CACZ,CAAA,CACF,CAAA,EACF,EAIA/B,EAAAA,KAAC,MAAA,CACC,UAAW,mEACToD,EAAM,YAAc,4BAA8B,uCACpD,GACA,cAAa,CAACA,EAAM,YAGpB,SAAA,CAAApD,EAAAA,KAAC,MAAA,CAAI,UAAU,YACb,SAAA,CAAAJ,MAACa,GAAY,KAAMoF,EAAW,MAAM,qBAAqB,MAAM,aAAa,EAC5E7F,EAAAA,KAAC,SAAA,CACC,MAAOoD,EAAM,YACb,SAAWrB,GAAMqC,EAAO,CAAE,YAAarC,EAAE,OAAO,MAAO,EACvD,UAAU,kCAEV,SAAA,CAAAnC,EAAAA,IAAC,SAAA,CAAO,MAAM,GAAG,SAAA,sBAAmB,EACnC2E,EAAiB,IAAK,SACpB,SAAA,CAAoB,MAAO,EAAE,KAC3B,SAAA,EAAE,MAAQ,GAAG,EAAE,IAAI,MAAM,EAAE,KAAK,GAAK,EAAE,MAD7B,EAAE,IAEf,CACD,CAAA,CAAA,CAAA,EAEH3E,EAAAA,IAAC,IAAA,CAAE,UAAU,iDAAiD,SAAA,iGAAA,CAG9D,CAAA,EACF,EAGAI,EAAAA,KAAC,MAAA,CAAI,UAAU,YACb,SAAA,CAAAJ,EAAAA,IAACa,EAAA,CACC,KAAM0F,GACN,MAAM,qBACN,MAAM,kBACN,MACEnG,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAJ,EAAAA,IAAC,OAAA,CAAK,UAAU,yCAAA,CAA0C,EAC1DA,EAAAA,IAAC,OAAA,CAAK,UAAU,sEAAsE,SAAA,MAAA,CAAI,CAAA,CAAA,CAC5F,CAAA,CAAA,EAGJA,EAAAA,IAACoC,GAAA,CAAgB,KAAAxC,EAAY,SAAU2D,CAAA,CAAO,CAAA,CAAA,CAChD,CAAA,CAAA,CAAA,CACF,EAEF,EAGAnD,EAAAA,KAAC,MAAA,CAAI,UAAU,aAGb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAJ,EAAAA,IAACa,EAAA,CACC,KAAM2F,GACN,MAAM,uBACN,MAAM,qBACN,MACEpG,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAJ,EAAAA,IAAC,OAAA,CAAK,UAAU,yCAAA,CAA0C,EAC1DA,EAAAA,IAAC,OAAA,CAAK,UAAU,sEAAsE,SAAA,MAAA,CAAI,CAAA,CAAA,CAC5F,CAAA,CAAA,EAGJA,EAAAA,IAACkB,GAAA,CAAkB,KAAAtB,EAAY,SAAU2D,CAAA,CAAO,CAAA,EAClD,EAGAnD,EAAAA,KAAC,MAAA,CAAI,UAAU,8CACb,SAAA,CAAAJ,EAAAA,IAACa,EAAA,CACC,KAAM4F,GACN,MAAM,uBACN,MAAM,UACN,MACEzG,EAAAA,IAAC,OAAA,CAAK,UAAU,0DAA0D,SAAA,oDAAA,CAE1E,CAAA,CAAA,EAGJA,EAAAA,IAACL,GAAA,CAAmB,KAAMC,EAAK,IAAA,CAAM,CAAA,CAAA,CACvC,CAAA,EACF,EAGAQ,EAAAA,KAAC,MAAA,CAAI,UAAU,aAEb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAJ,EAAAA,IAACa,EAAA,CACC,KAAM6F,EACN,MAAM,gBACN,MAAM,oBACN,MACE9G,EAAK,wBAA0B,KAC7BQ,EAAAA,KAAC,OAAA,CAAK,UAAU,4CAA4C,SAAA,CAAA,IAAER,EAAK,uBAAuB,SAAA,CAAA,CAAO,EAC/F,MAAA,CAAA,EAGRQ,EAAAA,KAAC,IAAA,CAAE,UAAU,sDAAsD,SAAA,CAAA,gIAEH,IAC9DJ,EAAAA,IAAC,OAAA,CAAK,UAAU,YAAY,SAAA,gBAAa,EAAO,GAAA,EAClD,EACAA,EAAAA,IAAC2G,GAAA,CACC,GAAI,gBAAgB,mBAAmB/G,EAAK,IAAI,CAAC,UACjD,UAAU,sCAET,WAAK,YACF,yBAAyBA,EAAK,wBAA0B,CAAC,YACzD,8BAAA,CAAA,CACN,EACF,SAGC,MAAA,CACC,SAAA,CAAAI,EAAAA,IAACa,EAAA,CACC,KAAM6F,EACN,MAAM,kBACN,MAAM,kBACN,MACE,CAACxC,EAAY,IAAI,iBAAiB,GAAKtE,EAAK,gBAC1CI,EAAAA,IAAC,SAAA,CAAO,QAAS,IAAMoE,EAAiB,iBAAiB,EAAG,UAAU,yCAAyC,gBAAI,EACjH,MAAA,CAAA,EAGRhE,EAAAA,KAAC,IAAA,CAAE,UAAU,sDAAsD,SAAA,CAAA,aACvDJ,EAAAA,IAAC,OAAA,CAAK,UAAU,YAAY,SAAA,WAAQ,EAAO,gEAAA,EACvD,EACC,CAACkE,EAAY,IAAI,iBAAiB,GAAKtE,EAAK,gBAC3CI,MAAC4G,EAAA,CAAW,KAAMhH,EAAK,eAAA,CAAiB,EAExCQ,EAAAA,KAAAyG,EAAAA,SAAA,CACE,SAAA,CAAA7G,EAAAA,IAAC,WAAA,CACC,MAAOwD,EAAM,gBACb,SAAWrB,GAAM,CACf,MAAM2E,EAAM3E,EAAE,OAAO,MACrBqC,EAAO,CAAE,gBAAiBsC,EAAK,EAC/B/C,EAAWO,IAAU,CAAE,GAAGA,EAAM,gBAAiB7D,EAAcqG,CAAG,EAAE,GAAK,OAAY,cAAA,EAAiB,CACxG,EACA,KAAM,GACN,WAAY,GACZ,UAAU,0CACV,YAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA,EAEdhD,EAAO,iBAAmB9D,EAAAA,IAAC,KAAE,UAAU,qCAAsC,WAAO,eAAA,CAAgB,CAAA,CAAA,CACvG,CAAA,EAEJ,SAGC,MAAA,CACC,SAAA,CAAAA,EAAAA,IAACa,EAAA,CACC,KAAM6F,EACN,MAAM,uBACN,MAAM,aACN,MACE,CAACxC,EAAY,IAAI,YAAY,GAAKtE,EAAK,YAAc,OAAO,KAAKA,EAAK,UAAU,EAAE,OAAS,EACzFI,EAAAA,IAAC,SAAA,CAAO,QAAS,IAAMoE,EAAiB,YAAY,EAAG,UAAU,yCAAyC,SAAA,MAAA,CAAI,EAE9GpE,EAAAA,IAAC,OAAA,CAAK,UAAU,0DAA0D,SAAA,aAAA,CAAW,CAAA,CAAA,EAI1F,CAACkE,EAAY,IAAI,YAAY,GAAKtE,EAAK,YAAc,OAAO,KAAKA,EAAK,UAAU,EAAE,OAAS,QACzFgH,EAAA,CAAW,KAAMhH,EAAK,WAAY,iBAAgB,EAAA,CAAC,EAEpDQ,EAAAA,KAAAyG,EAAAA,SAAA,CACE,SAAA,CAAA7G,EAAAA,IAAC,WAAA,CACC,MAAOwD,EAAM,WACb,SAAWrB,GAAM,CACf,MAAM2E,EAAM3E,EAAE,OAAO,MACrBqC,EAAO,CAAE,WAAYsC,EAAK,EAC1B/C,EAAWO,IAAU,CAAE,GAAGA,EAAM,WAAY7D,EAAcqG,CAAG,EAAE,GAAK,OAAY,cAAA,EAAiB,CACnG,EACA,KAAM,EACN,WAAY,GACZ,UAAU,6CACV,YAAa;AAAA;AAAA;AAAA,EAAA,CAAA,EAEdhD,EAAO,YAAc9D,EAAAA,IAAC,KAAE,UAAU,qCAAsC,WAAO,UAAA,CAAW,CAAA,CAAA,CAC7F,CAAA,CAAA,CAEJ,CAAA,CAAA,CACF,CAAA,EACF,EAGAA,EAAAA,IAAC+G,GAAA,CACC,KAAM/C,EACN,QAAS,IAAMC,EAAiB,EAAK,EACrC,UAAWqB,EACX,MAAM,cACN,YACElF,EAAAA,KAAAyG,WAAA,CAAE,SAAA,CAAA,eACY7G,EAAAA,IAAC,OAAA,CAAK,UAAU,0CAA2C,WAAK,KAAK,EAAO,0BAAA,EAC1F,EAEF,UAAWqD,EAAW,UACtB,MAAOA,EAAW,KAAA,CAAA,CACpB,EACF,CAEJ"}