@hotmeshio/long-tail 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/api/escalations/create.js +45 -0
- package/build/api/escalations/index.d.ts +1 -1
- package/build/api/escalations/index.js +2 -1
- package/build/api/escalations/list.d.ts +3 -0
- package/build/api/escalations/list.js +14 -0
- package/build/api/roles.d.ts +17 -0
- package/build/api/roles.js +46 -0
- package/build/bin/ltc.js +1 -0
- package/build/lib/cli/commands/escalations.d.ts +1 -0
- package/build/lib/cli/commands/escalations.js +2 -0
- package/build/lib/db/migrate.js +22 -2
- package/build/lib/db/schemas/014_roles_v2.sql +19 -0
- package/build/lib/db/schemas/015_role_ops.sql +50 -0
- package/build/lib/db/schemas/016_station_metrics_indexes.sql +13 -0
- package/build/lib/events/system-events.js +3 -0
- package/build/modules/auth.d.ts +9 -0
- package/build/modules/auth.js +38 -1
- package/build/routes/escalations/list.js +10 -0
- package/build/routes/roles.js +16 -5
- package/build/scripts/ortho-populate.d.ts +37 -0
- package/build/scripts/ortho-populate.js +228 -0
- package/build/sdk/index.d.ts +4 -0
- package/build/sdk/index.js +2 -0
- package/build/services/escalation/client.js +93 -2
- package/build/services/escalation/crud.js +18 -9
- package/build/services/escalation/metrics-cache.d.ts +14 -0
- package/build/services/escalation/metrics-cache.js +53 -0
- package/build/services/escalation/queries.d.ts +14 -2
- package/build/services/escalation/queries.js +121 -11
- package/build/services/escalation/sql.d.ts +29 -2
- package/build/services/escalation/sql.js +156 -27
- package/build/services/escalation/types.d.ts +17 -0
- package/build/services/escalation/types.js +1 -0
- package/build/services/mcp/external-server.js +5 -1
- package/build/services/orchestrator/condition.d.ts +20 -0
- package/build/services/orchestrator/condition.js +20 -0
- package/build/services/role/index.d.ts +22 -3
- package/build/services/role/index.js +50 -2
- package/build/services/role/sql.d.ts +11 -1
- package/build/services/role/sql.js +38 -1
- package/build/services/role/types.d.ts +32 -0
- package/build/system/mcp-servers/admin/escalations.js +8 -7
- package/build/system/mcp-servers/admin/index.js +5 -3
- package/build/system/mcp-servers/admin/ortho.d.ts +10 -0
- package/build/system/mcp-servers/admin/ortho.js +242 -0
- package/build/system/mcp-servers/admin/schemas.d.ts +40 -3
- package/build/system/mcp-servers/admin/schemas.js +17 -4
- package/build/system/mcp-servers/admin/users.js +31 -0
- package/build/system/seed/tool-manifests-admin.d.ts +4016 -712
- package/build/system/seed/tool-manifests-admin.js +14 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/escalation.d.ts +3 -1
- package/dashboard/dist/assets/{AdminDashboard-C5gfVEeL.js → AdminDashboard-Bg1HgukI.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-C5gfVEeL.js.map → AdminDashboard-Bg1HgukI.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-CWEnuiGN.js → AgentConfigPage-HBe_YDU_.js} +6 -6
- package/dashboard/dist/assets/{AgentConfigPage-CWEnuiGN.js.map → AgentConfigPage-HBe_YDU_.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-B6IE27iK.js → AgentDetailPage-BsaiYbwL.js} +4 -4
- package/dashboard/dist/assets/{AgentDetailPage-B6IE27iK.js.map → AgentDetailPage-BsaiYbwL.js.map} +1 -1
- package/dashboard/dist/assets/AgentsPage-DhN2lIBh.js +2 -0
- package/dashboard/dist/assets/{AgentsPage-Blhh2RsK.js.map → AgentsPage-DhN2lIBh.js.map} +1 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-_xcWvlIz.js +2 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-_xcWvlIz.js.map +1 -0
- package/dashboard/dist/assets/{BotPicker-DSozotGk.js → BotPicker-DY6iUVC9.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-DSozotGk.js.map → BotPicker-DY6iUVC9.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-CrS_DTA1.js → CapabilitiesPage-w1owqsmN.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-CrS_DTA1.js.map → CapabilitiesPage-w1owqsmN.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-1i6bOQ1L.js → CollapsibleSection-DIMGjlJ-.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-1i6bOQ1L.js.map → CollapsibleSection-DIMGjlJ-.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-BxJio06E.js → CredentialsPage-D1OmMHux.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-BxJio06E.js.map → CredentialsPage-D1OmMHux.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-BAfIHHz4.js → CronLabel-CQy3DrUQ.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-BAfIHHz4.js.map → CronLabel-CQy3DrUQ.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-BLF0NFJK.js → CustomDurationPicker-BoBkl9tw.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-BLF0NFJK.js.map → CustomDurationPicker-BoBkl9tw.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-CEx_wk-g.js → DropZone-QXbiuU0b.js} +2 -2
- package/dashboard/dist/assets/{DropZone-CEx_wk-g.js.map → DropZone-QXbiuU0b.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-nKGJvznH.js → ElapsedCell-Donjm9gT.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-nKGJvznH.js.map → ElapsedCell-Donjm9gT.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-bNNVA6R2.js → EscalationsOverview-CvHIJ_GG.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-bNNVA6R2.js.map → EscalationsOverview-CvHIJ_GG.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-BCuDdqlU.js → EventTable-DpAXMmT3.js} +2 -2
- package/dashboard/dist/assets/{EventTable-BCuDdqlU.js.map → EventTable-DpAXMmT3.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-BPAvqHls.js → GraphInvokePage-De1XVx5d.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-BPAvqHls.js.map → GraphInvokePage-De1XVx5d.js.map} +1 -1
- package/dashboard/dist/assets/HomePage-BYR5VXXw.js +2 -0
- package/dashboard/dist/assets/HomePage-BYR5VXXw.js.map +1 -0
- package/dashboard/dist/assets/{ListToolbar-DIJZfEgu.js → ListToolbar-Bx7jGzPA.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-DIJZfEgu.js.map → ListToolbar-Bx7jGzPA.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-DCfSCfPg.js → McpOverview-DXRKcJN0.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-DCfSCfPg.js.map → McpOverview-DXRKcJN0.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-mb7rmtNe.js → McpQueryDetailPage-CmW15w5e.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-mb7rmtNe.js.map → McpQueryDetailPage-CmW15w5e.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-D9b1T0I3.js → McpQueryPage-BE6I011z.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-D9b1T0I3.js.map → McpQueryPage-BE6I011z.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-Bz2UyuNm.js → McpRunDetailPage-Dsa3G3XQ.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-Bz2UyuNm.js.map → McpRunDetailPage-Dsa3G3XQ.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-Dw7w_ZO-.js → McpRunsPage-uTbym66Y.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-Dw7w_ZO-.js.map → McpRunsPage-uTbym66Y.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-D27vqDXy.js → NamespacePill-BGf0jHwE.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-D27vqDXy.js.map → NamespacePill-BGf0jHwE.js.map} +1 -1
- package/dashboard/dist/assets/OperationsPage-CAmiFHI6.js +2 -0
- package/dashboard/dist/assets/OperationsPage-CAmiFHI6.js.map +1 -0
- package/dashboard/dist/assets/{OperatorDashboard-CTzSDW3N.js → OperatorDashboard-i8cxaDlk.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-CTzSDW3N.js.map → OperatorDashboard-i8cxaDlk.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-B_1zTx2q.js → PageHeader-BZJsEVOC.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-B_1zTx2q.js.map → PageHeader-BZJsEVOC.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-D-cPg7UD.js → PageHeaderWithStats-BWuD7s9c.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-D-cPg7UD.js.map → PageHeaderWithStats-BWuD7s9c.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-olG2CS-h.js → ProcessDetailPage-CP7GZhgs.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-olG2CS-h.js.map → ProcessDetailPage-CP7GZhgs.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-CUZSL06Y.js → ProcessesListPage-btsU6hBR.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-CUZSL06Y.js.map → ProcessesListPage-btsU6hBR.js.map} +1 -1
- package/dashboard/dist/assets/RoleDetailPage-BB_e330f.js +16 -0
- package/dashboard/dist/assets/RoleDetailPage-BB_e330f.js.map +1 -0
- package/dashboard/dist/assets/{RolePill-B-V-31lC.js → RolePill-Pb9TKSQN.js} +2 -2
- package/dashboard/dist/assets/{RolePill-B-V-31lC.js.map → RolePill-Pb9TKSQN.js.map} +1 -1
- package/dashboard/dist/assets/RolesPage-1DBoEMsb.js +2 -0
- package/dashboard/dist/assets/RolesPage-1DBoEMsb.js.map +1 -0
- package/dashboard/dist/assets/{RunAsSelector-BoLHF4fy.js → RunAsSelector-Cp6j3FEY.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-BoLHF4fy.js.map → RunAsSelector-Cp6j3FEY.js.map} +1 -1
- package/dashboard/dist/assets/StatusBadge-D9MeQHrh.js +2 -0
- package/dashboard/dist/assets/StatusBadge-D9MeQHrh.js.map +1 -0
- package/dashboard/dist/assets/{StickyPagination-BEMY1L-H.js → StickyPagination-Pr8kawv8.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-BEMY1L-H.js.map → StickyPagination-Pr8kawv8.js.map} +1 -1
- package/dashboard/dist/assets/StreamMessageDetail-BqmQ-N3y.js +2 -0
- package/dashboard/dist/assets/{StreamMessageDetail-CVRVWXcU.js.map → StreamMessageDetail-BqmQ-N3y.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-DDpU0-Jn.js → SwimlaneTimeline-y1YmXrsj.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-DDpU0-Jn.js.map → SwimlaneTimeline-y1YmXrsj.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-BHVfG307.js → TagInput-Df4myuYF.js} +2 -2
- package/dashboard/dist/assets/{TagInput-BHVfG307.js.map → TagInput-Df4myuYF.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-B_xQtJMg.js → TaskDetailPage-CT5rXHK5.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-B_xQtJMg.js.map → TaskDetailPage-CT5rXHK5.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-CGlxXqWt.js → TaskQueuePill-YalYdCNo.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-CGlxXqWt.js.map → TaskQueuePill-YalYdCNo.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-CsrdIOKk.js → TasksListPage-DOy6JlKS.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-CsrdIOKk.js.map → TasksListPage-DOy6JlKS.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-DmicaxjT.js → TimeAgo-BAQwZSpq.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-DmicaxjT.js.map → TimeAgo-BAQwZSpq.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-DeK89eRV.js → TimestampCell-BK_jufns.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-DeK89eRV.js.map → TimestampCell-BK_jufns.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-NV7PxSpA.js → ToolPill-VGpT6Quy.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-NV7PxSpA.js.map → ToolPill-VGpT6Quy.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-D3s2n9-9.js → ToolTestPanel-5PMQyUCe.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-D3s2n9-9.js.map → ToolTestPanel-5PMQyUCe.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-qyv7UWT_.js → TopicDetailPage-Cn1ShfR8.js} +3 -3
- package/dashboard/dist/assets/{TopicDetailPage-qyv7UWT_.js.map → TopicDetailPage-Cn1ShfR8.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-CEUfMoed.js → TopicsPage-D67tjS8L.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-CEUfMoed.js.map → TopicsPage-D67tjS8L.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-Bn_BxI8K.js → UserName-Dsu1Jk4N.js} +2 -2
- package/dashboard/dist/assets/{UserName-Bn_BxI8K.js.map → UserName-Dsu1Jk4N.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-DAk2RqpB.js → WorkflowExecutionPage-BwQoOmUE.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-DAk2RqpB.js.map → WorkflowExecutionPage-BwQoOmUE.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-DDR0B6DN.js → WorkflowPill-pPUqmx6Q.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-DDR0B6DN.js.map → WorkflowPill-pPUqmx6Q.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-DfBgM80t.js → WorkflowsDashboard-D3z7COgH.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-DfBgM80t.js.map → WorkflowsDashboard-D3z7COgH.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview--Dkoo9Jq.js → WorkflowsOverview-C15JcxyY.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview--Dkoo9Jq.js.map → WorkflowsOverview-C15JcxyY.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-B6HYbfFj.js → YamlWorkflowDetailPage-BYq3t7E-.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-B6HYbfFj.js.map → YamlWorkflowDetailPage-BYq3t7E-.js.map} +1 -1
- package/dashboard/dist/assets/YamlWorkflowsPage-B44WgwE_.js +2 -0
- package/dashboard/dist/assets/{YamlWorkflowsPage-CJE-PxC0.js.map → YamlWorkflowsPage-B44WgwE_.js.map} +1 -1
- package/dashboard/dist/assets/{agents-DUciUZpt.js → agents-BRmmK6Y9.js} +2 -2
- package/dashboard/dist/assets/{agents-DUciUZpt.js.map → agents-BRmmK6Y9.js.map} +1 -1
- package/dashboard/dist/assets/{bots-BnyqCfuC.js → bots-BD75mzGG.js} +2 -2
- package/dashboard/dist/assets/{bots-BnyqCfuC.js.map → bots-BD75mzGG.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-CkTWWT0q.js → capabilities-DDgC_Kds.js} +2 -2
- package/dashboard/dist/assets/{capabilities-CkTWWT0q.js.map → capabilities-DDgC_Kds.js.map} +1 -1
- package/dashboard/dist/assets/controlplane-BJh12lMv.js +2 -0
- package/dashboard/dist/assets/controlplane-BJh12lMv.js.map +1 -0
- package/dashboard/dist/assets/{escalation-De9JnTKI.js → escalation-DIJt2sgn.js} +2 -2
- package/dashboard/dist/assets/{escalation-De9JnTKI.js.map → escalation-DIJt2sgn.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-Df7Pluzg.js → escalation-columns-zl6E94Up.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-Df7Pluzg.js.map → escalation-columns-zl6E94Up.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cqjf-yVP.js → index-B0kmiSmt.js} +2 -2
- package/dashboard/dist/assets/{index-Cqjf-yVP.js.map → index-B0kmiSmt.js.map} +1 -1
- package/dashboard/dist/assets/index-BRtKQtQZ.css +1 -0
- package/dashboard/dist/assets/{index-BxdiKgnH.js → index-BUbzfEA9.js} +2 -2
- package/dashboard/dist/assets/{index-BxdiKgnH.js.map → index-BUbzfEA9.js.map} +1 -1
- package/dashboard/dist/assets/{index-DpAS4-DA.js → index-BhznDv-4.js} +2 -2
- package/dashboard/dist/assets/{index-DpAS4-DA.js.map → index-BhznDv-4.js.map} +1 -1
- package/dashboard/dist/assets/{index-BAhkWcOq.js → index-CDPBXB4e.js} +4 -4
- package/dashboard/dist/assets/{index-BAhkWcOq.js.map → index-CDPBXB4e.js.map} +1 -1
- package/dashboard/dist/assets/{index-CgD9fA9P.js → index-CV4lEd4I.js} +2 -2
- package/dashboard/dist/assets/{index-CgD9fA9P.js.map → index-CV4lEd4I.js.map} +1 -1
- package/dashboard/dist/assets/{index-DjxTV3cn.js → index-CknKy4RA.js} +2 -2
- package/dashboard/dist/assets/{index-DjxTV3cn.js.map → index-CknKy4RA.js.map} +1 -1
- package/dashboard/dist/assets/{index-DNugmBs7.js → index-CpgV4Kkp.js} +2 -2
- package/dashboard/dist/assets/{index-DNugmBs7.js.map → index-CpgV4Kkp.js.map} +1 -1
- package/dashboard/dist/assets/{index-B1kc6itM.js → index-CtDf8vvQ.js} +24 -24
- package/dashboard/dist/assets/index-CtDf8vvQ.js.map +1 -0
- package/dashboard/dist/assets/{index-BzMsh6Ui.js → index-DU7YumVJ.js} +2 -2
- package/dashboard/dist/assets/{index-BzMsh6Ui.js.map → index-DU7YumVJ.js.map} +1 -1
- package/dashboard/dist/assets/{index-BsIaUbKD.js → index-DVVIeBBk.js} +2 -2
- package/dashboard/dist/assets/{index-BsIaUbKD.js.map → index-DVVIeBBk.js.map} +1 -1
- package/dashboard/dist/assets/index-DccCwyZl.js +6 -0
- package/dashboard/dist/assets/{index-CN0efCE9.js.map → index-DccCwyZl.js.map} +1 -1
- package/dashboard/dist/assets/{index-7hqtQI43.js → index-DrUkTcn-.js} +2 -2
- package/dashboard/dist/assets/{index-7hqtQI43.js.map → index-DrUkTcn-.js.map} +1 -1
- package/dashboard/dist/assets/{index-B07xLlyz.js → index-j-C7g_Ej.js} +2 -2
- package/dashboard/dist/assets/{index-B07xLlyz.js.map → index-j-C7g_Ej.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-D4SvdNv5.js → knowledge-pNDWACXB.js} +2 -2
- package/dashboard/dist/assets/{knowledge-D4SvdNv5.js.map → knowledge-pNDWACXB.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-CLP9EnnU.js → mcp-query-CmNjvxTG.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-CLP9EnnU.js.map → mcp-query-CmNjvxTG.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-DVxt4T9J.js → mcp-xddLBwUW.js} +2 -2
- package/dashboard/dist/assets/{mcp-DVxt4T9J.js.map → mcp-xddLBwUW.js.map} +1 -1
- package/dashboard/dist/assets/pipelines-B05sd2nB.js +2 -0
- package/dashboard/dist/assets/pipelines-B05sd2nB.js.map +1 -0
- package/dashboard/dist/assets/roles-bRgaMcdy.js +2 -0
- package/dashboard/dist/assets/roles-bRgaMcdy.js.map +1 -0
- package/dashboard/dist/assets/tasks-Bm1OKrJA.js +2 -0
- package/dashboard/dist/assets/{tasks-1eTuP02d.js.map → tasks-Bm1OKrJA.js.map} +1 -1
- package/dashboard/dist/assets/{topics-B3p8K0PW.js → topics-BVIqtmd4.js} +2 -2
- package/dashboard/dist/assets/{topics-B3p8K0PW.js.map → topics-BVIqtmd4.js.map} +1 -1
- package/dashboard/dist/assets/useEventHooks-_qCzU74s.js +2 -0
- package/dashboard/dist/assets/useEventHooks-_qCzU74s.js.map +1 -0
- package/dashboard/dist/assets/{useNamespace-Dx81_JM0.js → useNamespace-CDnCSFpG.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-Dx81_JM0.js.map → useNamespace-CDnCSFpG.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-D5T3TbE7.js → useYamlActivityEvents-zrHMhaFM.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-D5T3TbE7.js.map → useYamlActivityEvents-zrHMhaFM.js.map} +1 -1
- package/dashboard/dist/assets/{users-BEMysNdR.js → users-BPBMZg27.js} +2 -2
- package/dashboard/dist/assets/{users-BEMysNdR.js.map → users-BPBMZg27.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons--Ivmp-RX.js → vendor-icons-C1zVP_dv.js} +125 -115
- package/dashboard/dist/assets/vendor-icons-C1zVP_dv.js.map +1 -0
- package/dashboard/dist/assets/workflows-CT6nTL1I.js +2 -0
- package/dashboard/dist/assets/workflows-CT6nTL1I.js.map +1 -0
- package/dashboard/dist/assets/{yaml-workflows-4rJ5v5rJ.js → yaml-workflows-CdfjkOKU.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-4rJ5v5rJ.js.map → yaml-workflows-CdfjkOKU.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/api/http/escalations.md +82 -6
- package/docs/api/http/roles.md +82 -3
- package/docs/api/mcp/admin.md +127 -1
- package/docs/api/sdk/escalations.md +65 -4
- package/docs/api/sdk/roles.md +81 -0
- package/docs/cli.md +2 -0
- package/docs/dashboard.md +17 -2
- package/docs/hitl-guide.md +12 -3
- package/docs/operations.md +113 -0
- package/package.json +3 -2
- package/dashboard/dist/assets/AgentsPage-Blhh2RsK.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-ClwAle76.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-ClwAle76.js.map +0 -1
- package/dashboard/dist/assets/HomePage-BZ1YTrjR.js +0 -2
- package/dashboard/dist/assets/HomePage-BZ1YTrjR.js.map +0 -1
- package/dashboard/dist/assets/RolesPage-DLnaW6iD.js +0 -2
- package/dashboard/dist/assets/RolesPage-DLnaW6iD.js.map +0 -1
- package/dashboard/dist/assets/StatusBadge-Bl3FXVmF.js +0 -2
- package/dashboard/dist/assets/StatusBadge-Bl3FXVmF.js.map +0 -1
- package/dashboard/dist/assets/StreamMessageDetail-CVRVWXcU.js +0 -2
- package/dashboard/dist/assets/YamlWorkflowsPage-CJE-PxC0.js +0 -2
- package/dashboard/dist/assets/controlplane-D9HaFZsC.js +0 -2
- package/dashboard/dist/assets/controlplane-D9HaFZsC.js.map +0 -1
- package/dashboard/dist/assets/index-B1kc6itM.js.map +0 -1
- package/dashboard/dist/assets/index-CN0efCE9.js +0 -6
- package/dashboard/dist/assets/index-nO0cim3_.css +0 -1
- package/dashboard/dist/assets/pipelines-C_x0LTBN.js +0 -2
- package/dashboard/dist/assets/pipelines-C_x0LTBN.js.map +0 -1
- package/dashboard/dist/assets/roles-QaGFZQ58.js +0 -2
- package/dashboard/dist/assets/roles-QaGFZQ58.js.map +0 -1
- package/dashboard/dist/assets/tasks-1eTuP02d.js +0 -2
- package/dashboard/dist/assets/useEventHooks-BNZky4xM.js +0 -2
- package/dashboard/dist/assets/useEventHooks-BNZky4xM.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons--Ivmp-RX.js.map +0 -1
- package/dashboard/dist/assets/workflows-C4rjvQbI.js +0 -2
- package/dashboard/dist/assets/workflows-C4rjvQbI.js.map +0 -1
package/docs/hitl-guide.md
CHANGED
|
@@ -62,11 +62,16 @@ export async function approvalWorkflow(envelope: LTEnvelope) {
|
|
|
62
62
|
},
|
|
63
63
|
},
|
|
64
64
|
envelope: { data: envelope.data },
|
|
65
|
+
timeout: '72h', // SLA: resume with false + expire the row if unresolved
|
|
65
66
|
});
|
|
66
67
|
|
|
67
|
-
if (
|
|
68
|
-
//
|
|
69
|
-
//
|
|
68
|
+
if (decision === false) {
|
|
69
|
+
// SLA timer fired first — the row is already status='expired' (engine-side,
|
|
70
|
+
// atomic) and a late resolve returns already-expired. Branch to fallback.
|
|
71
|
+
return { type: 'return' as const, data: { autoRejected: 'sla' } };
|
|
72
|
+
}
|
|
73
|
+
if (decision === null) {
|
|
74
|
+
// escalation was cancelled (workflow terminated or explicit cancel)
|
|
70
75
|
return { type: 'return' as const, data: { cancelled: true } };
|
|
71
76
|
}
|
|
72
77
|
|
|
@@ -78,6 +83,10 @@ export async function approvalWorkflow(envelope: LTEnvelope) {
|
|
|
78
83
|
}
|
|
79
84
|
```
|
|
80
85
|
|
|
86
|
+
The `timeout` field (hotmesh 0.25.1+) makes the wait SLA-gated in the same
|
|
87
|
+
single Leg1 write: one `conditionLT` call yields the worklist row AND the
|
|
88
|
+
resume timer. Omit it for an open-ended wait.
|
|
89
|
+
|
|
81
90
|
#### Two-step form
|
|
82
91
|
|
|
83
92
|
When you need to create the escalation separately — for example to enrich routing metadata before pausing — create it first, then wait:
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Operations
|
|
2
|
+
|
|
3
|
+
The Operations view gives anyone managing a process pipeline a live picture of how work is flowing across every station. It answers the question the COO actually asks: *are we keeping up, and where are things backing up?*
|
|
4
|
+
|
|
5
|
+
## What "operations" means
|
|
6
|
+
|
|
7
|
+
A process is a directed sequence of **stations** — each station is a role where work lands, is claimed, and gets resolved before moving downstream. The ortho manufacturing pipeline is one example: `design → review → print → grind → glue → finish → qa → ship`. Any set of roles with `parent_role` set forms a process graph.
|
|
8
|
+
|
|
9
|
+
Stations opt in to the Operations view by setting `ops_visible = true` on the role. Roles without that flag appear in the Roles admin page but not on `/operations`.
|
|
10
|
+
|
|
11
|
+
## Capacity settings
|
|
12
|
+
|
|
13
|
+
Each station has three settings that define what "healthy" looks like — knowing any two derives the third (`target_per_hour = worker_count / (sla_minutes / 60)`):
|
|
14
|
+
|
|
15
|
+
| Field | Description |
|
|
16
|
+
|-------|-------------|
|
|
17
|
+
| `sla_minutes` | Target resolution time in minutes. Items older than this are counted as `in_arrears`. |
|
|
18
|
+
| `target_per_hour` | Intended throughput — how many items should resolve per hour. Used to compute `throughput_pct` and the station's expected count on the pace chart. |
|
|
19
|
+
| `worker_count` | Capacity at this station — number of staff or machines expected to be active. |
|
|
20
|
+
|
|
21
|
+
These are set via `PATCH /api/roles/:role` or the Roles admin page.
|
|
22
|
+
|
|
23
|
+
## Pace chart
|
|
24
|
+
|
|
25
|
+
The chart is the centrepiece. It plots **absolute counts for the selected window** across the pipeline — every station in dependency order (parent before children, breadth-first) on the X axis.
|
|
26
|
+
|
|
27
|
+
Two lines cross the stations:
|
|
28
|
+
|
|
29
|
+
- **Target** — a straight red polyline at each station's expected count for the window (`target_per_hour × window hours`; e.g. 22/h over 15m ≈ 5).
|
|
30
|
+
- **Actual** — a smooth curve through each station's resolved count for the window, with a light area fill beneath it. Reading actual against target shows at a glance which stations are keeping pace.
|
|
31
|
+
|
|
32
|
+
Each station appears as a circle on the actual curve, colored by its pace ratio (`actual / target`):
|
|
33
|
+
|
|
34
|
+
- **Green** — met or beat the target (ratio ≥ 1.0).
|
|
35
|
+
- **Amber** — behind (ratio ≥ 0.6).
|
|
36
|
+
- **Red** — well behind (ratio < 0.6).
|
|
37
|
+
- **Grey** — target unset for this station.
|
|
38
|
+
|
|
39
|
+
Circle radius grows modestly with resolved volume. Hovering a circle shows a tooltip with the actual count, target, queue depth, and active claims. A separate indigo dot marks each station's **active** (claimed) count.
|
|
40
|
+
|
|
41
|
+
Below each circle, a three-number strip shows the live state:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
5↑ · 2● · 12✓
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- `↑` pending (amber when > 0)
|
|
48
|
+
- `●` active / claimed (indigo when > 0)
|
|
49
|
+
- `✓` resolved in period (green, bold — the "did we hit target" signal)
|
|
50
|
+
|
|
51
|
+
Stations without a `target_per_hour` still appear on the X axis — the lines have a gap there, and the tooltip prompts you to set a target rate to plot pace.
|
|
52
|
+
|
|
53
|
+
## Station table
|
|
54
|
+
|
|
55
|
+
Below the chart, a flat table lists every station with its live numbers:
|
|
56
|
+
|
|
57
|
+
| Column | Description |
|
|
58
|
+
|--------|-------------|
|
|
59
|
+
| PENDING | Items queued right now |
|
|
60
|
+
| ACTIVE | Items currently claimed |
|
|
61
|
+
| RESOLVED | Items resolved in the selected period |
|
|
62
|
+
| P99 WAIT | 99th-percentile queue time (created → claimed) in minutes |
|
|
63
|
+
| P99 WORK | 99th-percentile processing time (claimed → resolved) in minutes |
|
|
64
|
+
| TREND | Mini fill bar + percentage — live backlog ratio while items queue, period throughput efficiency when idle |
|
|
65
|
+
|
|
66
|
+
If a station has `in_arrears > 0`, a sub-row appears: `⚠ N items past SLA — view oldest first →`. The link opens the escalation queue sorted by `created_at` ascending, filtered to that role.
|
|
67
|
+
|
|
68
|
+
Clicking any row opens the station detail panel.
|
|
69
|
+
|
|
70
|
+
## Station detail panel
|
|
71
|
+
|
|
72
|
+
A 340 px right rail that slides open when a row or chart circle is clicked. Three sections:
|
|
73
|
+
|
|
74
|
+
1. **Identity** — role key, title, description, link to edit in Roles.
|
|
75
|
+
2. **Period selector** — `15m | 1h | 24h | 7d | 30d` toggle for this station only. It opens on the chart's selected window, then adjusts independently.
|
|
76
|
+
3. **Metrics** — pending / resolved / active counts; wait and work percentiles (P99, P50, avg); SLA target; worker count; links to the queue.
|
|
77
|
+
|
|
78
|
+
Close the panel with × or by clicking another row.
|
|
79
|
+
|
|
80
|
+
## Data source
|
|
81
|
+
|
|
82
|
+
All station metrics come from `GET /api/escalations/station-metrics?period=<period>`. The endpoint runs two queries against `public.hmsh_escalations` joined to `lt_roles` (for `sla_minutes` and `target_per_hour`): a live-counts pass over the pending backlog, and a window-bounded percentile pass over resolved rows (`PERCENTILE_CONT` in Postgres, served by the `idx_hmsh_esc_resolved_cover` index). Updates reach the page as push events — every escalation write invalidates the metrics through the Socket.IO event system.
|
|
83
|
+
|
|
84
|
+
`pending` is always the live count regardless of period. `resolved`, percentiles, and `throughput_pct` are scoped to the lookback window. See [`lt.escalations.getStationMetrics`](api/sdk/escalations.md#getstationmetrics) for the full response shape.
|
|
85
|
+
|
|
86
|
+
## Period selector
|
|
87
|
+
|
|
88
|
+
The global period toggle in the page header controls the chart and table simultaneously. The station detail panel has its own independent period toggle so you can zoom into a single station without losing the overview.
|
|
89
|
+
|
|
90
|
+
Period options: `15m`, `1h`, `24h`, `7d`, `30d`.
|
|
91
|
+
|
|
92
|
+
## Configuring a station
|
|
93
|
+
|
|
94
|
+
1. Go to `/admin/roles` and click the role.
|
|
95
|
+
2. Set `ops_visible = true`, `sla_minutes`, `target_per_hour`, and `worker_count`.
|
|
96
|
+
3. Set `parent_role` to the upstream role this station receives work from. Leave blank for root stations.
|
|
97
|
+
4. The role appears on `/operations` on the next refresh — settings take effect live.
|
|
98
|
+
|
|
99
|
+
## The ortho pipeline
|
|
100
|
+
|
|
101
|
+
The built-in ortho manufacturing demo registers 8 roles in sequence:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
design → review → print → grind → glue → finish → qa → ship
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Each stage uses `condition()` — a HotMesh atomic Leg1 write that creates an escalation and suspends the workflow in a single Postgres transaction. When an operator (or Claude agent via the `ortho_complete_stage` MCP tool) resolves the escalation, the resolve itself signals the workflow: it resumes in place and the next stage's escalation appears.
|
|
108
|
+
|
|
109
|
+
See [MCP Admin Tools — Ortho Pipeline](api/mcp/admin.md#ortho-pipeline) for the agent loop.
|
|
110
|
+
|
|
111
|
+
## Navigation
|
|
112
|
+
|
|
113
|
+
The Operations entry lives in the choreography sidebar (the left rail visible on `/operations` and `/escalations`), separate from the Admin sidebar. The `/operations` route admits admin-type users, superadmins, and engineers — the same audience the sidebar shows the entry to.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hotmeshio/long-tail",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
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",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"token": "ts-node scripts/token.ts",
|
|
44
44
|
"process": "tsx scripts/process.ts",
|
|
45
45
|
"demo": "bash scripts/demo.sh",
|
|
46
|
+
"ortho:populate": "ts-node scripts/ortho-populate.ts",
|
|
46
47
|
"dashboard:install": "cd dashboard && npm install",
|
|
47
48
|
"dashboard:dev": "cd dashboard && npm run dev",
|
|
48
49
|
"dashboard:build": "cd dashboard && npm run build",
|
|
@@ -70,7 +71,7 @@
|
|
|
70
71
|
"@anthropic-ai/sdk": "^0.92.0",
|
|
71
72
|
"@aws-sdk/client-s3": "^3.1017.0",
|
|
72
73
|
"@aws-sdk/s3-request-presigner": "^3.1045.0",
|
|
73
|
-
"@hotmeshio/hotmesh": "^0.
|
|
74
|
+
"@hotmeshio/hotmesh": "^0.25.1",
|
|
74
75
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
75
76
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.215.0",
|
|
76
77
|
"@opentelemetry/resources": "^2.5.1",
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{j as e}from"./vendor-query-B2UbickB.js";import{u as h}from"./agents-DUciUZpt.js";import{u as f,b}from"./index-B1kc6itM.js";import{i as j}from"./useEventHooks-BNZky4xM.js";import{u as v}from"./useFilterParams-x-Dg0Vgz.js";import{b as N}from"./api-path-u2Jf9QXS.js";import{D as y}from"./DataTable-ZWgVQg7F.js";import{S as P}from"./StickyPagination-BEMY1L-H.js";import{F as S,b as k}from"./FilterBar-BQ2JGg8U.js";import{P as w}from"./PageHeader-B_1zTx2q.js";import{L as _}from"./ListToolbar-DIJZfEgu.js";import{k as A}from"./vendor-icons--Ivmp-RX.js";import{c as z}from"./vendor-react-CXumBFUA.js";import"./EmptyState-BcsfPq9T.js";const C=[{value:"active",label:"Active"},{value:"inactive",label:"Inactive"},{value:"paused",label:"Paused"},{value:"error",label:"Error"}],F=[{key:"name",label:"Agent",render:t=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:`w-1.5 h-1.5 rounded-full shrink-0 ${t.status==="active"?"bg-emerald-400":t.status==="paused"?"bg-amber-400":t.status==="error"?"bg-red-400":"bg-zinc-500"}`}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("span",{className:"text-xs font-medium text-text-primary block",children:t.id}),t.description&&e.jsx("p",{className:"text-[10px] text-text-tertiary truncate",children:t.description})]})]})},{key:"knowledge_domain",label:"Knowledge",render:t=>t.knowledge_domain?e.jsx("span",{className:"text-[10px] font-mono text-text-secondary whitespace-nowrap",children:t.knowledge_domain}):e.jsx("span",{className:"text-text-quaternary",children:"—"}),className:"w-28"},{key:"schedules",label:"Schedules",render:t=>{var o,r;const s=(o=t.behaviors)==null?void 0:o.schedules,a=s!=null&&s.length?s.map(l=>l.cron):(r=t.behaviors)!=null&&r.cron?[t.behaviors.cron]:[];return a.length?e.jsxs("span",{className:"text-[10px] font-mono text-text-secondary whitespace-nowrap",children:[a[0],a.length>1?` +${a.length-1}`:""]}):e.jsx("span",{className:"text-text-quaternary",children:"—"})},className:"w-28"},{key:"subscriptions",label:"Subscriptions",render:t=>{var r;const s=t.subscription_count??0,a=t.sub_topics??[];if(!s)return e.jsx("span",{className:"text-text-quaternary",children:"—"});const o=((r=a[0])==null?void 0:r.replace(/^lt\.events\./,""))??"";return e.jsxs("span",{className:"text-[10px] font-mono text-text-secondary whitespace-nowrap",children:[o,s>1?` +${s-1}`:""]})},className:"w-36"},{key:"last_run_at",label:"Last Run",render:t=>t.last_run_at?e.jsx("span",{className:"whitespace-nowrap",children:e.jsx(b,{date:t.last_run_at})}):e.jsx("span",{className:"text-text-quaternary",children:"—"}),className:"w-32"}];function V(){var p;const t=z(),{data:s}=f(),a=!!((p=s==null?void 0:s.ai)!=null&&p.enabled),o=a?"Agent":"Automation",r=a?"Agents":"Automations";j();const{filters:l,setFilter:u,pagination:n}=v({filters:{status:""}}),{data:i,isLoading:d,refetch:x,isFetching:g}=h({status:l.status||void 0,limit:n.pageSize,offset:n.offset}),m=(i==null?void 0:i.total)??0;return e.jsxs("div",{children:[e.jsx(w,{title:r,docsHash:"#docs:agents.md",actions:e.jsxs("button",{onClick:()=>t("/agents/new"),className:"flex items-center gap-2 px-4 py-2 text-sm rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors",children:[e.jsx(A,{className:"w-4 h-4"})," Create ",o]})}),e.jsx(S,{actions:e.jsx(_,{onRefresh:()=>x(),isFetching:g,apiPath:N("/agents",{limit:n.pageSize,offset:n.offset,status:l.status||void 0})}),children:e.jsx(k,{label:"Status",value:l.status,onChange:c=>u("status",c),options:C})}),e.jsx(y,{columns:F,data:(i==null?void 0:i.agents)??[],keyFn:c=>c.id,onRowClick:c=>t(`/agents/${c.id}`),isLoading:d,emptyMessage:`No ${r.toLowerCase()} found`}),e.jsx(P,{page:n.page,totalPages:n.totalPages(m),onPageChange:n.setPage,total:m,pageSize:n.pageSize,onPageSizeChange:n.setPageSize})]})}export{V as AgentsPage};
|
|
2
|
-
//# sourceMappingURL=AgentsPage-Blhh2RsK.js.map
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{j as e,a as p}from"./vendor-query-B2UbickB.js";import{c as Le,f as $e,a as De}from"./vendor-react-CXumBFUA.js";import{u as Ue,j as He,k as Je,g as qe,l as Ge,m as Qe,n as Ve,o as Ye,p as Ke,q as Xe,r as We,s as Ze,t as et,v as tt}from"./index-B1kc6itM.js";import{f as st}from"./useEventHooks-BNZky4xM.js";import{u as te,C as fe,a as at}from"./CustomDurationPicker-BLF0NFJK.js";import{u as nt}from"./roles-QaGFZQ58.js";import{u as lt}from"./useFilterParams-x-Dg0Vgz.js";import{u as pe}from"./useDebouncedValue-BA5S7V54.js";import{b as it}from"./api-path-u2Jf9QXS.js";import{D as rt}from"./DataTable-ZWgVQg7F.js";import{S as ot}from"./StickyPagination-BEMY1L-H.js";import{P as ct}from"./PageHeader-B_1zTx2q.js";import{P as dt}from"./constants-BHkpVaqx.js";import{M as se}from"./Modal-CSrxpXeM.js";import{u as ut}from"./users-BEMysNdR.js";import{E as xt,a as mt}from"./escalation-columns-Df7Pluzg.js";import{R as ht,a as gt}from"./RowActions-BA9L9djf.js";import{L as ft}from"./ListToolbar-DIJZfEgu.js";import{a3 as pt,S as bt,X as yt}from"./vendor-icons--Ivmp-RX.js";import"./EmptyState-BcsfPq9T.js";import"./FilterBar-BQ2JGg8U.js";import"./PriorityBadge-B4ykBH7f.js";import"./RolePill-B-V-31lC.js";import"./WorkflowPill-DDR0B6DN.js";import"./escalation-De9JnTKI.js";const T=t=>{if(t)try{return JSON.parse(t)}catch{return}},A=t=>t==null||Array.isArray(t)&&t.length===0||typeof t=="object"&&!Array.isArray(t)&&Object.keys(t).length===0;function vt(t){const s={},o=T(t.get("facets"));A(o)||(s.facets=o);const c=T(t.get("block"));A(c)||(s.block=c);const x=T(t.get("range"));A(x)||(s.range=x);const f=T(t.get("exists"));A(f)||(s.exists=f);const h=T(t.get("roles"));A(h)||(s.roles=h);const l=T(t.get("orderBy"));return A(l)||(s.orderBy=l),t.get("available")!=null&&(s.available=t.get("available")==="true"),s}function jt(t,s){const o=(c,x)=>A(x)?t.delete(c):t.set(c,JSON.stringify(x));o("facets",s.facets),o("block",s.block),o("range",s.range),o("exists",s.exists),o("roles",s.roles),o("orderBy",s.orderBy),s.available==null?t.delete("available"):t.set("available",String(s.available))}function Ct(t){var s,o,c,x;return Object.keys(t.facets??{}).length+(((s=t.block)==null?void 0:s.length)??0)+(((o=t.range)==null?void 0:o.length)??0)+(((c=t.exists)==null?void 0:c.length)??0)+(((x=t.orderBy)==null?void 0:x.length)??0)+(t.available!=null?1:0)}const kt=["<","<=",">",">=","="],Nt=["priority","created_at","updated_at","status","role"],P="h-7 rounded border border-surface-border bg-surface px-2 text-xs text-text-primary focus:border-accent focus:outline-none",H="text-text-tertiary hover:text-text-primary transition-colors";function ge(t){return t==="true"?!0:t==="false"?!1:t.trim()!==""&&!Number.isNaN(Number(t))?Number(t):t}const St=t=>Object.entries(t??{}).map(([s,o])=>({key:s,value:String(o)})),Pt=t=>(t??[]).map(s=>{const[o,c]=Object.entries(s)[0]??["",""];return{key:o,value:String(c)}});function M({title:t,hint:s,children:o}){return e.jsxs("div",{className:"border-t border-surface-border/50 py-3 first:border-t-0 first:pt-1",children:[e.jsxs("div",{className:"mb-1.5 flex items-baseline justify-between",children:[e.jsx("span",{className:"text-[11px] font-medium uppercase tracking-wide text-text-tertiary",children:t}),s&&e.jsx("span",{className:"text-[10px] font-mono text-text-tertiary/70",children:s})]}),o]})}function J({value:t,onChange:s,placeholder:o}){return e.jsx("input",{list:"lt-facet-keys",className:`${P} w-40`,placeholder:o,value:t,onChange:c=>s(c.target.value)})}function wt({value:t,onChange:s,facetKeys:o=[],search:c="",onSearchChange:x}){const f=St(t.facets),h=Pt(t.block),l=t.range??[],u=t.exists??[],b=t.orderBy??[],v=a=>{const i={};for(const n of a)n.key&&(i[n.key]=ge(n.value));s({...t,facets:Object.keys(i).length?i:void 0})},N=a=>{const i=a.filter(n=>n.key).map(n=>({[n.key]:ge(n.value)}));s({...t,block:i.length?i:void 0})},k=a=>s({...t,range:a.length?a:void 0}),S=a=>s({...t,exists:a.length?a:void 0}),C=a=>s({...t,orderBy:a.length?a:void 0});return e.jsxs("div",{className:"text-xs",children:[e.jsx("datalist",{id:"lt-facet-keys",children:o.map(a=>e.jsx("option",{value:a},a))}),e.jsxs("datalist",{id:"lt-sort-fields",children:[Nt.map(a=>e.jsx("option",{value:a},a)),o.map(a=>e.jsx("option",{value:`metadata.${a}`},a))]}),x&&e.jsx(M,{title:"Text contains",hint:"id · text · metadata",children:e.jsx("input",{className:`${P} w-full`,placeholder:"ID, workflow, origin, any text…",value:c,onChange:a=>x(a.target.value)})}),e.jsx(M,{title:"Has facet",hint:"metadata @>",children:[...f,{key:"",value:""}].map((a,i)=>e.jsxs("div",{className:"mb-1 flex items-center gap-1",children:[e.jsx(J,{value:a.key,placeholder:"key",onChange:n=>{const r=[...f];r[i]={...a,key:n},v(r)}}),e.jsx("span",{className:"text-text-tertiary",children:"="}),e.jsx("input",{className:`${P} w-40`,placeholder:"value",value:a.value,onChange:n=>{const r=[...f];r[i]={...a,value:n.target.value},v(r)}}),i<f.length&&e.jsx("button",{className:H,onClick:()=>v(f.filter((n,r)=>r!==i)),children:"×"})]},i))}),e.jsx(M,{title:"Range",hint:"numeric",children:[...l,{facet:"",op:"<=",value:0}].map((a,i)=>e.jsxs("div",{className:"mb-1 flex items-center gap-1",children:[e.jsx(J,{value:a.facet,placeholder:"numeric facet",onChange:n=>{const r=[...l];r[i]={...a,facet:n},k(r.filter(y=>y.facet))}}),e.jsx("select",{className:P,value:a.op,onChange:n=>{const r=[...l];r[i]={...a,op:n.target.value},k(r.filter(y=>y.facet))},children:kt.map(n=>e.jsx("option",{value:n,children:n},n))}),e.jsx("input",{type:"number",className:`${P} w-24`,value:a.value,onChange:n=>{const r=[...l];r[i]={...a,value:Number(n.target.value)},k(r.filter(y=>y.facet))}}),i<l.length&&e.jsx("button",{className:H,onClick:()=>k(l.filter((n,r)=>r!==i)),children:"×"})]},i))}),e.jsx(M,{title:"Has key",hint:"metadata ? key",children:e.jsxs("div",{className:"flex flex-wrap items-center gap-1",children:[u.map(a=>e.jsxs("span",{className:"flex items-center gap-1 rounded bg-accent/15 px-1.5 py-0.5 text-accent",children:[a,e.jsx("button",{className:"text-accent/70 hover:text-accent",onClick:()=>S(u.filter(i=>i!==a)),children:"×"})]},a)),e.jsx(J,{value:"",placeholder:"+ key",onChange:a=>{a&&!u.includes(a)&&S([...u,a])}})]})}),e.jsx(M,{title:"Exclude",hint:"NOT @>",children:[...h,{key:"",value:""}].map((a,i)=>e.jsxs("div",{className:"mb-1 flex items-center gap-1",children:[e.jsx(J,{value:a.key,placeholder:"key",onChange:n=>{const r=[...h];r[i]={...a,key:n},N(r)}}),e.jsx("span",{className:"text-text-tertiary",children:"="}),e.jsx("input",{className:`${P} w-40`,placeholder:"value",value:a.value,onChange:n=>{const r=[...h];r[i]={...a,value:n.target.value},N(r)}}),i<h.length&&e.jsx("button",{className:H,onClick:()=>N(h.filter((n,r)=>r!==i)),children:"×"})]},i))}),e.jsx(M,{title:"Sort by",children:[...b,{field:"",direction:"asc"}].map((a,i)=>e.jsxs("div",{className:"mb-1 flex items-center gap-1",children:[e.jsx("input",{list:"lt-sort-fields",className:`${P} w-44`,placeholder:"column or metadata.key",value:a.field,onChange:n=>{const r=[...b];r[i]={...a,field:n.target.value},C(r.filter(y=>y.field))}}),e.jsxs("select",{className:P,value:a.direction??"asc",onChange:n=>{const r=[...b];r[i]={...a,direction:n.target.value},C(r.filter(y=>y.field))},children:[e.jsx("option",{value:"asc",children:"asc"}),e.jsx("option",{value:"desc",children:"desc"})]}),e.jsxs("label",{className:"flex items-center gap-1 text-text-tertiary",children:[e.jsx("input",{type:"checkbox",checked:!!a.numeric,onChange:n=>{const r=[...b];r[i]={...a,numeric:n.target.checked},C(r.filter(y=>y.field))}}),"num"]}),i<b.length&&e.jsx("button",{className:H,onClick:()=>C(b.filter((n,r)=>r!==i)),children:"×"})]},i))})]})}const At=t=>t.isPriorityPending||t.isClaimPending||t.isAssignPending||t.isEscalatePending||t.isTriagePending||t.isCancelPending,ee="inline-flex items-center h-7 px-2.5 text-[11px] font-medium text-text-secondary bg-surface border border-surface-border rounded-[4px] hover:border-accent/50 hover:text-text-primary transition-colors disabled:opacity-50 disabled:hover:border-surface-border",Z=`${ee} appearance-none cursor-pointer`,Bt="inline-flex items-center h-7 px-2.5 text-[11px] font-medium text-status-error bg-surface border border-status-error/30 rounded-[4px] hover:border-status-error hover:bg-status-error/5 transition-colors disabled:opacity-50";function Et(t){var h;const s=At(t),o=te(),{data:c}=Ue(),x=((h=c==null?void 0:c.ai)==null?void 0:h.enabled)===!0,f=t.selectedCount>0;return e.jsx("div",{className:`grid transition-all duration-200 ease-in-out ${f?"grid-rows-[1fr] opacity-100":"grid-rows-[0fr] opacity-0 pointer-events-none"}`,children:e.jsx("div",{className:"overflow-hidden",children:e.jsxs("div",{className:"flex flex-wrap items-center gap-2 py-2.5 pl-3 pr-2 mt-4 mb-3 bg-surface-sunken/60 border-l-2 border-l-accent",children:[e.jsxs("span",{className:"text-[11px] font-semibold uppercase tracking-wider text-accent tabular-nums",children:[t.selectedCount," selected"]}),e.jsx("div",{className:"mx-1 h-4 w-px bg-surface-border"}),e.jsxs("select",{onChange:l=>{l.target.value&&(t.onSetPriority(parseInt(l.target.value)),l.target.value="")},disabled:s,className:Z,defaultValue:"",children:[e.jsx("option",{value:"",disabled:!0,children:"Priority…"}),dt.map(l=>e.jsx("option",{value:l.value,children:l.label},l.value))]}),e.jsxs("select",{onChange:l=>{l.target.value&&(t.onClaim(parseInt(l.target.value)),l.target.value="")},disabled:s,className:Z,defaultValue:"",children:[e.jsx("option",{value:"",disabled:!0,children:"Claim for…"}),o.map(l=>e.jsx("option",{value:l.value,children:l.label},l.value))]}),e.jsx("button",{onClick:t.onAssign,disabled:s,className:ee,children:t.isAssignPending?"Assigning…":"Assign to…"}),t.availableRoles.length>0&&e.jsxs("select",{onChange:l=>{l.target.value&&(t.onEscalate(l.target.value),l.target.value="")},disabled:s,className:Z,defaultValue:"",children:[e.jsx("option",{value:"",disabled:!0,children:"Escalate to…"}),t.availableRoles.map(l=>e.jsx("option",{value:l,children:l},l))]}),x&&e.jsx("button",{onClick:t.onTriage,disabled:s,className:ee,children:t.isTriagePending?"Triaging…":"Triage"}),e.jsx("button",{onClick:t.onCancel,disabled:s,className:Bt,children:t.isCancelPending?"Cancelling…":"Cancel"}),e.jsx("div",{className:"flex-1"}),s&&e.jsx("span",{className:"text-[11px] text-text-tertiary animate-pulse",children:"Processing…"}),e.jsx("button",{onClick:t.onClearSelection,className:"px-1 text-[11px] font-medium text-text-tertiary hover:text-text-primary transition-colors",children:"Clear"})]})})})}function Ot({open:t,onClose:s,selectedCount:o,selectedRoles:c,onSubmit:x,isPending:f}){const{isSuperAdmin:h}=He(),l=te(),[u,b]=p.useState("user"),[v,N]=p.useState(null),[k,S]=p.useState(""),[C,a]=p.useState("30"),[i,n]=p.useState(0),r=p.useCallback(m=>n(m),[]),y=!h&&c.length===1?c[0]:void 0,L=pe(k,250),{data:g,isLoading:_}=ut({role:y,status:"active",search:L.trim()||void 0,limit:200}),B=(g==null?void 0:g.users)??[],E=()=>{b("user"),N(null),S(""),a("30"),n(0),s()},q=m=>{N(m),b("duration")},z=()=>{b("user")},G=()=>{if(!v)return;const m=C==="custom"?i:parseInt(C);!m||m<=0||x(v.id,m)};return e.jsx(se,{open:t,onClose:E,title:"Assign Escalations",children:e.jsxs("div",{className:"space-y-4",children:[u==="user"&&e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"text-sm text-text-secondary",children:["Select a user to assign"," ",e.jsx("span",{className:"font-medium text-text-primary",children:o})," ","escalation(s) to:"]}),e.jsx("input",{type:"text",value:k,onChange:m=>S(m.target.value),placeholder:"Search by name or email...",className:"input text-xs w-full",autoFocus:!0}),e.jsxs("div",{className:"max-h-60 overflow-y-auto border border-surface-border rounded-lg divide-y divide-surface-border",children:[_&&e.jsx("p",{className:"text-xs text-text-tertiary p-3",children:"Loading users..."}),!_&&B.length===0&&e.jsx("p",{className:"text-xs text-text-tertiary p-3",children:"No users found"}),B.map(m=>e.jsxs("button",{onClick:()=>q(m),className:"w-full text-left px-3 py-2 hover:bg-surface-hover transition-colors",children:[e.jsx("p",{className:"text-xs font-medium text-text-primary",children:m.display_name||m.external_id}),m.email&&e.jsx("p",{className:"text-[10px] text-text-tertiary",children:m.email})]},m.id))]}),e.jsx("div",{className:"flex justify-end pt-2",children:e.jsx("button",{onClick:E,className:"btn-secondary text-xs",children:"Cancel"})})]}),u==="duration"&&v&&e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"text-sm text-text-secondary",children:["Assign to"," ",e.jsx("span",{className:"font-medium text-text-primary",children:v.display_name||v.external_id})," ","for:"]}),e.jsxs("select",{value:C,onChange:m=>{a(m.target.value),n(0)},className:"select w-full text-sm",children:[l.map(m=>e.jsx("option",{value:m.value,children:m.label},m.value)),e.jsx("option",{value:"custom",children:"Other..."})]}),C==="custom"&&e.jsx(fe,{onChange:r,autoFocus:!0}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:z,className:"btn-secondary text-xs",children:"Back"}),e.jsx("button",{onClick:G,disabled:f,className:"btn-primary text-xs",children:f?"Assigning...":"Assign"})]})]})]})})}function Ft({open:t,onClose:s,selectedCount:o,onSubmit:c,isPending:x}){const[f,h]=p.useState(""),l=()=>{c(f||void 0)};return e.jsx(se,{open:t,onClose:s,title:"Submit for AI Triage",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("p",{className:"text-sm text-text-secondary",children:["Submit ",e.jsx("span",{className:"font-medium text-text-primary",children:o})," escalation(s) for AI triage? The triage orchestrator will take over resolution."]}),e.jsxs("div",{children:[e.jsxs("label",{className:"text-xs font-medium text-text-secondary block mb-1",children:["Triage hint ",e.jsx("span",{className:"text-text-tertiary",children:"(optional)"})]}),e.jsx("input",{type:"text",value:f,onChange:u=>h(u.target.value),placeholder:"e.g., image_orientation",className:"input text-xs font-mono w-full"}),e.jsx("p",{className:"text-[10px] text-text-tertiary mt-1",children:"Guides the triage workflow on what remediation to apply"})]}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:s,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:l,disabled:x,className:"btn-primary text-xs",children:x?"Submitting...":"Submit for Triage"})]})]})})}function R(t,s,o){return c=>{t.mutate(c,{onSuccess:()=>{s(),o==null||o()}})}}function Tt(t){const s=()=>[...t.selectedIds];return{handleSetPriority:u=>{R(t.setPriority,t.clearSelection)({ids:s(),priority:u})},handleBulkClaim:u=>{R(t.bulkClaim,t.clearSelection)({ids:s(),durationMinutes:u})},handleBulkEscalate:u=>{R(t.bulkEscalate,t.clearSelection)({ids:s(),targetRole:u})},handleBulkTriage:u=>{R(t.bulkTriage,t.clearSelection,t.closeTriageModal)({ids:s(),hint:u})},handleBulkAssign:(u,b)=>{R(t.bulkAssign,t.clearSelection,t.closeAssignModal)({ids:s(),targetUserId:u,durationMinutes:b})},handleBulkCancel:()=>{R(t.bulkCancel,t.clearSelection,t.closeCancelModal)({ids:s()})}}}function Mt({claimTarget:t,onClose:s,claimDuration:o,onDurationChange:c,claimDurations:x,onCustomClaimChange:f,onClaim:h,isPending:l}){return e.jsx(se,{open:!!t,onClose:s,title:"Claim Escalation",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("p",{className:"text-sm text-text-secondary",children:["Claim ",e.jsx("span",{className:"font-medium text-text-primary",children:t==null?void 0:t.type})," for:"]}),e.jsxs("select",{value:o,onChange:u=>{c(u.target.value)},className:"select w-full text-sm",children:[x.map(u=>e.jsx("option",{value:u.value,children:u.label},u.value)),e.jsx("option",{value:"custom",children:"Other..."})]}),o==="custom"&&e.jsx(fe,{onChange:f,autoFocus:!0}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:s,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:h,className:"btn-primary text-xs",disabled:l,children:l?"Claiming...":"Claim"})]})]})})}function is(){var de,ue,xe,me,he;st();const t=Le(),{filters:s,setFilter:o,pagination:c,sort:x,setSort:f}=lt({filters:{role:"",type:"",priority:"",status:"available",search:""}}),h=pe(s.search,300),l=te(),[u,b]=p.useState(null),[v,N]=p.useState("30"),[k,S]=p.useState(0),C=p.useCallback(d=>S(d),[]),[a,i]=p.useState(new Set),[n,r]=p.useState(!1),[y,L]=$e(),g=p.useMemo(()=>vt(y),[y]),_=p.useCallback(d=>{L(j=>{const W=new URLSearchParams(j);return jt(W,d),W.delete("page"),W},{replace:!0})},[L]),{data:B}=Je(n),E=Ct(g)+(s.search?1:0),[q,z]=p.useState(!1),[G,m]=p.useState(!1),[be,Q]=p.useState(!1),ae=qe(),ne=Ge(),le=Qe(),V=Ve(),ie=Ye(),Y=Ke(),$=Xe(),{data:O}=nt(),{data:K}=We();p.useEffect(()=>{i(new Set)},[s.role,s.type,s.priority,s.status,h,c.page,c.pageSize]);const D=s.status||"",I=D==="available",X=D==="claimed",re=X?"pending":D==="resolved"?"resolved":D==="cancelled"?"cancelled":void 0,oe={role:s.role||void 0,type:s.type||void 0,priority:s.priority?parseInt(s.priority):void 0,limit:c.pageSize,offset:c.offset,sort_by:x.sort_by||"created_at",order:x.order||"desc",search:h||void 0,...g},ye=Ze({...oe,enabled:I}),ve=et({status:re,claimed:X||void 0,...oe,enabled:!I}),je=I?ye:ve,{data:F,isLoading:Ce,error:U,refetch:ke,isFetching:Ne}=je,Se=it(`/escalations${I?"/available":""}`,{status:re,claimed:X||void 0,role:s.role||void 0,type:s.type||void 0,priority:s.priority||void 0,search:h||void 0,sort_by:x.sort_by||"created_at",order:x.order||"desc",limit:c.pageSize,offset:c.offset,facets:g.facets&&Object.keys(g.facets).length?JSON.stringify(g.facets):void 0,block:(de=g.block)!=null&&de.length?JSON.stringify(g.block):void 0,range:(ue=g.range)!=null&&ue.length?JSON.stringify(g.range):void 0,exists:(xe=g.exists)!=null&&xe.length?JSON.stringify(g.exists):void 0,roles:(me=g.roles)!=null&&me.length?JSON.stringify(g.roles):void 0,orderBy:(he=g.orderBy)!=null&&he.length?JSON.stringify(g.orderBy):void 0,available:g.available!=null?String(g.available):void 0}),w=(F==null?void 0:F.escalations)??[],ce=(F==null?void 0:F.total)??0,{canBulk:Pe}=tt(),we=p.useMemo(()=>{const d=new Set;for(const j of w)a.has(j.id)&&d.add(j.role);return[...d]},[w,a]),Ae=p.useCallback(()=>i(new Set),[]),Be=()=>{if(!u)return;const d=v==="custom"?k:parseInt(v);!d||d<=0||ae.mutate({id:u.id,durationMinutes:d},{onSuccess:()=>{b(null),t(`/escalations/detail/${u.id}`)}})},{handleSetPriority:Ee,handleBulkClaim:Oe,handleBulkEscalate:Fe,handleBulkTriage:Te,handleBulkAssign:Me,handleBulkCancel:Re}=Tt({selectedIds:a,clearSelection:Ae,setPriority:ne,bulkClaim:le,bulkEscalate:ie,bulkTriage:Y,bulkAssign:V,bulkCancel:$,closeTriageModal:()=>z(!1),closeAssignModal:()=>m(!1),closeCancelModal:()=>Q(!1)}),_e=d=>{const j=new Set(a);j.has(d)?j.delete(d):j.add(d),i(j)},ze=()=>{a.size===w.length?i(new Set):i(new Set(w.map(d=>d.id)))},Ie=[Pe?{key:"select",label:e.jsx("input",{type:"checkbox",checked:w.length>0&&a.size===w.length,onChange:ze,className:"rounded"}),render:d=>e.jsx("input",{type:"checkbox",checked:a.has(d.id),onChange:j=>{j.stopPropagation(),_e(d.id)},onClick:j=>j.stopPropagation(),className:"rounded"}),className:"w-10"}:{key:"spacer",label:"",render:()=>null,className:"w-10"},...xt,{key:"actions",label:"",render:d=>e.jsx(ht,{children:e.jsx(gt,{icon:pt,title:"Claim escalation",onClick:()=>b(d),colorClass:"text-accent/75 hover:text-accent",size:"sm"})}),className:"w-10 text-right"}];return e.jsxs("div",{children:[e.jsx(ct,{title:"Available Escalations",docsHash:"#docs:dashboard.md:all-escalations"}),e.jsx(mt,{filters:s,setFilter:o,roles:(O==null?void 0:O.roles)??[],types:(K==null?void 0:K.types)??[],showStatus:!0,showSearch:!1,actions:e.jsxs(e.Fragment,{children:[e.jsx(ft,{onRefresh:()=>ke(),isFetching:Ne,apiPath:Se}),e.jsxs("button",{onClick:()=>r(d=>!d),className:"relative ml-2 inline-flex h-7 w-7 items-center justify-center rounded text-text-tertiary hover:bg-surface-hover hover:text-text-primary transition-colors",title:"Faceted query",children:[e.jsx(bt,{className:"w-4 h-4"}),E>0&&e.jsx("span",{className:"absolute -right-1 -top-1 flex h-3.5 min-w-[14px] items-center justify-center rounded-full bg-accent px-0.5 text-[9px] font-medium text-white",children:E})]})]})}),De.createPortal(e.jsxs("div",{className:`fixed right-0 bottom-0 w-[420px] z-40 border-l border-surface-border bg-surface overflow-y-auto shadow-lg transition-transform duration-200 ease-out ${n?"translate-x-0":"pointer-events-none translate-x-full"}`,style:{top:"3.5rem"},"aria-hidden":!n,children:[e.jsxs("div",{className:"sticky top-0 z-10 flex items-center justify-between px-4 py-3 bg-surface border-b border-surface-border/50",children:[e.jsx("span",{className:"text-xs font-medium text-text-primary",children:"Faceted query"}),e.jsxs("div",{className:"flex items-center gap-2",children:[E>0&&e.jsx("button",{onClick:()=>{_({}),o("search","")},className:"text-[11px] text-text-tertiary hover:text-text-primary transition-colors",children:"Clear"}),e.jsx("button",{onClick:()=>r(!1),className:"p-1 rounded hover:bg-surface-hover text-text-tertiary hover:text-text-primary transition-colors",title:"Close",children:e.jsx(yt,{className:"w-4 h-4"})})]})]}),e.jsxs("div",{className:"px-4 py-2",children:[e.jsx("p",{className:"mb-2 text-[11px] leading-snug text-text-tertiary",children:"Free-text recall plus precise metadata facets — they compose in one SQL query. Facet keys are the ones that actually exist in your visible escalations; the whole query is shareable via the URL."}),e.jsx(wt,{value:g,onChange:_,facetKeys:(B==null?void 0:B.keys)??[],search:s.search??"",onSearchChange:d=>o("search",d)})]})]}),document.body),e.jsx(Et,{selectedCount:a.size,onClearSelection:()=>i(new Set),onSetPriority:Ee,onClaim:Oe,onAssign:()=>m(!0),onEscalate:Fe,onTriage:()=>z(!0),onCancel:()=>Q(!0),isPriorityPending:ne.isPending,isClaimPending:le.isPending,isAssignPending:V.isPending,isEscalatePending:ie.isPending,isTriagePending:Y.isPending,isCancelPending:$.isPending,availableRoles:(O==null?void 0:O.roles)??[]}),U&&e.jsx("div",{className:"mb-4 px-4 py-3 rounded-md bg-status-error/10 border border-status-error/20 text-xs text-status-error",children:U.message==="Session expired"?"Your session has expired. Please log in again.":`Failed to load escalations: ${U.message}`}),e.jsx(rt,{columns:Ie,data:w,keyFn:d=>d.id,onRowClick:d=>t(`/escalations/detail/${d.id}`,{state:{from:"/escalations/available"}}),isLoading:Ce,emptyMessage:U?"Unable to load data":"No available escalations",sort:x,onSort:f}),e.jsx(ot,{page:c.page,totalPages:c.totalPages(ce),onPageChange:c.setPage,total:ce,pageSize:c.pageSize,onPageSizeChange:c.setPageSize}),e.jsx(Mt,{claimTarget:u,onClose:()=>b(null),claimDuration:v,onDurationChange:d=>{N(d),S(0)},claimDurations:l,customClaimMinutes:k,onCustomClaimChange:C,onClaim:Be,isPending:ae.isPending}),e.jsx(Ft,{open:q,onClose:()=>z(!1),selectedCount:a.size,onSubmit:Te,isPending:Y.isPending}),e.jsx(Ot,{open:G,onClose:()=>m(!1),selectedCount:a.size,selectedRoles:we,onSubmit:Me,isPending:V.isPending}),e.jsx(at,{open:be,onClose:()=>Q(!1),onConfirm:Re,selectedCount:a.size,isPending:$.isPending,error:$.error})]})}export{is as AvailableEscalationsPage};
|
|
2
|
-
//# sourceMappingURL=AvailableEscalationsPage-ClwAle76.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AvailableEscalationsPage-ClwAle76.js","sources":["../../src/lib/facet-url.ts","../../src/pages/operator/FacetedFilterPanel.tsx","../../src/components/common/modal/BulkActionBar.tsx","../../src/components/common/modal/BulkAssignModal.tsx","../../src/components/common/modal/BulkTriageModal.tsx","../../src/pages/operator/helpers.ts","../../src/pages/operator/ClaimModal.tsx","../../src/pages/operator/AvailableEscalationsPage.tsx"],"sourcesContent":["import type { FacetFilters } from '../api/escalations';\n\n// The faceted query is DEEP-LINKED: every element lives in the URL as a JSON-encoded\n// search param (the same names the API/route use), so a shared link reproduces the\n// exact query and back/forward navigation restores it.\n\nconst parse = (v: string | null): any => {\n if (!v) return undefined;\n try { return JSON.parse(v); } catch { return undefined; }\n};\n\nconst isEmpty = (v: unknown): boolean =>\n v == null ||\n (Array.isArray(v) && v.length === 0) ||\n (typeof v === 'object' && !Array.isArray(v) && Object.keys(v as object).length === 0);\n\n/** Read the faceted query from URL search params. */\nexport function parseFacetParams(sp: URLSearchParams): FacetFilters {\n const f: FacetFilters = {};\n const facets = parse(sp.get('facets')); if (!isEmpty(facets)) f.facets = facets;\n const block = parse(sp.get('block')); if (!isEmpty(block)) f.block = block;\n const range = parse(sp.get('range')); if (!isEmpty(range)) f.range = range;\n const exists = parse(sp.get('exists')); if (!isEmpty(exists)) f.exists = exists;\n const roles = parse(sp.get('roles')); if (!isEmpty(roles)) f.roles = roles;\n const orderBy = parse(sp.get('orderBy')); if (!isEmpty(orderBy)) f.orderBy = orderBy;\n if (sp.get('available') != null) f.available = sp.get('available') === 'true';\n return f;\n}\n\n/** Write the faceted query onto URL search params (deleting empty elements). */\nexport function writeFacetParams(p: URLSearchParams, f: FacetFilters): void {\n const set = (k: string, v: unknown) => (isEmpty(v) ? p.delete(k) : p.set(k, JSON.stringify(v)));\n set('facets', f.facets);\n set('block', f.block);\n set('range', f.range);\n set('exists', f.exists);\n set('roles', f.roles);\n set('orderBy', f.orderBy);\n if (f.available == null) p.delete('available'); else p.set('available', String(f.available));\n}\n\n/** Count of active facet conditions (for the trigger badge). */\nexport function facetCount(f: FacetFilters): number {\n return (\n Object.keys(f.facets ?? {}).length +\n (f.block?.length ?? 0) +\n (f.range?.length ?? 0) +\n (f.exists?.length ?? 0) +\n (f.orderBy?.length ?? 0) +\n (f.available != null ? 1 : 0)\n );\n}\n","import type { FacetFilters, FacetRange, FacetOrder } from '../../api/escalations';\n\nconst RANGE_OPS: FacetRange['op'][] = ['<', '<=', '>', '>=', '='];\nconst SORT_COLUMNS = ['priority', 'created_at', 'updated_at', 'status', 'role'];\n\nconst inputCls =\n 'h-7 rounded border border-surface-border bg-surface px-2 text-xs text-text-primary focus:border-accent focus:outline-none';\nconst xBtn = 'text-text-tertiary hover:text-text-primary transition-colors';\n\n/** A facet value is JSONB-containment-sensitive: 0.65 (number) ≠ \"0.65\" (string). */\nfunction coerce(v: string): unknown {\n if (v === 'true') return true;\n if (v === 'false') return false;\n if (v.trim() !== '' && !Number.isNaN(Number(v))) return Number(v);\n return v;\n}\n\ntype KV = { key: string; value: string };\nconst recordRows = (rec?: Record<string, unknown>): KV[] =>\n Object.entries(rec ?? {}).map(([key, value]) => ({ key, value: String(value) }));\nconst blockRows = (arr?: Record<string, unknown>[]): KV[] =>\n (arr ?? []).map((o) => {\n const [key, value] = Object.entries(o)[0] ?? ['', ''];\n return { key, value: String(value) };\n });\n\nfunction Section({ title, hint, children }: { title: string; hint?: string; children: React.ReactNode }) {\n return (\n <div className=\"border-t border-surface-border/50 py-3 first:border-t-0 first:pt-1\">\n <div className=\"mb-1.5 flex items-baseline justify-between\">\n <span className=\"text-[11px] font-medium uppercase tracking-wide text-text-tertiary\">{title}</span>\n {hint && <span className=\"text-[10px] font-mono text-text-tertiary/70\">{hint}</span>}\n </div>\n {children}\n </div>\n );\n}\n\nfunction KeyInput({ value, onChange, placeholder }: {\n value: string; onChange: (v: string) => void; placeholder: string;\n}) {\n return (\n <input\n list=\"lt-facet-keys\" className={`${inputCls} w-40`} placeholder={placeholder}\n value={value} onChange={(e) => onChange(e.target.value)}\n />\n );\n}\n\n/**\n * Faceted query editor — the advanced operations surface (rendered inside the\n * slide-out drawer). Controlled: edits a FacetFilters value. `facetKeys` are the\n * metadata keys that actually exist in the caller's rows (from listFacetKeys), so\n * the UI never offers a non-existent facet.\n */\nexport function FacetedFilterPanel({ value, onChange, facetKeys = [], search = '', onSearchChange }: {\n value: FacetFilters;\n onChange: (next: FacetFilters) => void;\n facetKeys?: string[];\n /** Free-text term — composes with the facets as an extra ILIKE in the same SQL query. */\n search?: string;\n onSearchChange?: (next: string) => void;\n}) {\n const facets = recordRows(value.facets);\n const exclude = blockRows(value.block);\n const ranges = value.range ?? [];\n const exists = value.exists ?? [];\n const sorts = value.orderBy ?? [];\n\n const setFacets = (rows: KV[]) => {\n const rec: Record<string, unknown> = {};\n for (const r of rows) if (r.key) rec[r.key] = coerce(r.value);\n onChange({ ...value, facets: Object.keys(rec).length ? rec : undefined });\n };\n const setBlock = (rows: KV[]) => {\n const arr = rows.filter((r) => r.key).map((r) => ({ [r.key]: coerce(r.value) }));\n onChange({ ...value, block: arr.length ? arr : undefined });\n };\n const setRange = (r: FacetRange[]) => onChange({ ...value, range: r.length ? r : undefined });\n const setExists = (e: string[]) => onChange({ ...value, exists: e.length ? e : undefined });\n const setSorts = (o: FacetOrder[]) => onChange({ ...value, orderBy: o.length ? o : undefined });\n\n return (\n <div className=\"text-xs\">\n {/* Autocomplete sources rendered once (shared by all rows). */}\n <datalist id=\"lt-facet-keys\">\n {facetKeys.map((k) => <option key={k} value={k} />)}\n </datalist>\n <datalist id=\"lt-sort-fields\">\n {SORT_COLUMNS.map((c) => <option key={c} value={c} />)}\n {facetKeys.map((k) => <option key={k} value={`metadata.${k}`} />)}\n </datalist>\n\n {onSearchChange && (\n <Section title=\"Text contains\" hint=\"id · text · metadata\">\n <input\n className={`${inputCls} w-full`}\n placeholder=\"ID, workflow, origin, any text…\"\n value={search}\n onChange={(e) => onSearchChange(e.target.value)}\n />\n </Section>\n )}\n\n <Section title=\"Has facet\" hint=\"metadata @>\">\n {[...facets, { key: '', value: '' }].map((row, i) => (\n <div key={i} className=\"mb-1 flex items-center gap-1\">\n <KeyInput value={row.key} placeholder=\"key\"\n onChange={(k) => { const next = [...facets]; next[i] = { ...row, key: k }; setFacets(next); }} />\n <span className=\"text-text-tertiary\">=</span>\n <input className={`${inputCls} w-40`} placeholder=\"value\" value={row.value}\n onChange={(e) => { const next = [...facets]; next[i] = { ...row, value: e.target.value }; setFacets(next); }} />\n {i < facets.length && (\n <button className={xBtn} onClick={() => setFacets(facets.filter((_, j) => j !== i))}>×</button>\n )}\n </div>\n ))}\n </Section>\n\n <Section title=\"Range\" hint=\"numeric\">\n {[...ranges, { facet: '', op: '<=' as const, value: 0 }].map((r, i) => (\n <div key={i} className=\"mb-1 flex items-center gap-1\">\n <KeyInput value={r.facet} placeholder=\"numeric facet\"\n onChange={(f) => { const next = [...ranges]; next[i] = { ...r, facet: f }; setRange(next.filter((x) => x.facet)); }} />\n <select className={inputCls} value={r.op}\n onChange={(e) => { const next = [...ranges]; next[i] = { ...r, op: e.target.value as FacetRange['op'] }; setRange(next.filter((x) => x.facet)); }}>\n {RANGE_OPS.map((o) => <option key={o} value={o}>{o}</option>)}\n </select>\n <input type=\"number\" className={`${inputCls} w-24`} value={r.value}\n onChange={(e) => { const next = [...ranges]; next[i] = { ...r, value: Number(e.target.value) }; setRange(next.filter((x) => x.facet)); }} />\n {i < ranges.length && (\n <button className={xBtn} onClick={() => setRange(ranges.filter((_, j) => j !== i))}>×</button>\n )}\n </div>\n ))}\n </Section>\n\n <Section title=\"Has key\" hint=\"metadata ? key\">\n <div className=\"flex flex-wrap items-center gap-1\">\n {exists.map((k) => (\n <span key={k} className=\"flex items-center gap-1 rounded bg-accent/15 px-1.5 py-0.5 text-accent\">\n {k}<button className=\"text-accent/70 hover:text-accent\" onClick={() => setExists(exists.filter((x) => x !== k))}>×</button>\n </span>\n ))}\n <KeyInput value=\"\" placeholder=\"+ key\"\n onChange={(k) => { if (k && !exists.includes(k)) setExists([...exists, k]); }} />\n </div>\n </Section>\n\n <Section title=\"Exclude\" hint=\"NOT @>\">\n {[...exclude, { key: '', value: '' }].map((row, i) => (\n <div key={i} className=\"mb-1 flex items-center gap-1\">\n <KeyInput value={row.key} placeholder=\"key\"\n onChange={(k) => { const next = [...exclude]; next[i] = { ...row, key: k }; setBlock(next); }} />\n <span className=\"text-text-tertiary\">=</span>\n <input className={`${inputCls} w-40`} placeholder=\"value\" value={row.value}\n onChange={(e) => { const next = [...exclude]; next[i] = { ...row, value: e.target.value }; setBlock(next); }} />\n {i < exclude.length && (\n <button className={xBtn} onClick={() => setBlock(exclude.filter((_, j) => j !== i))}>×</button>\n )}\n </div>\n ))}\n </Section>\n\n <Section title=\"Sort by\">\n {[...sorts, { field: '', direction: 'asc' as const }].map((s, i) => (\n <div key={i} className=\"mb-1 flex items-center gap-1\">\n <input list=\"lt-sort-fields\" className={`${inputCls} w-44`} placeholder=\"column or metadata.key\"\n value={s.field}\n onChange={(e) => { const next = [...sorts]; next[i] = { ...s, field: e.target.value }; setSorts(next.filter((x) => x.field)); }} />\n <select className={inputCls} value={s.direction ?? 'asc'}\n onChange={(e) => { const next = [...sorts]; next[i] = { ...s, direction: e.target.value as 'asc' | 'desc' }; setSorts(next.filter((x) => x.field)); }}>\n <option value=\"asc\">asc</option><option value=\"desc\">desc</option>\n </select>\n <label className=\"flex items-center gap-1 text-text-tertiary\">\n <input type=\"checkbox\" checked={!!s.numeric}\n onChange={(e) => { const next = [...sorts]; next[i] = { ...s, numeric: e.target.checked }; setSorts(next.filter((x) => x.field)); }} />\n num\n </label>\n {i < sorts.length && (\n <button className={xBtn} onClick={() => setSorts(sorts.filter((_, j) => j !== i))}>×</button>\n )}\n </div>\n ))}\n </Section>\n </div>\n );\n}\n","import { PRIORITY_OPTIONS } from '../../../lib/constants';\nimport { useClaimDurations } from '../../../hooks/useClaimDurations';\nimport { useSettings } from '../../../api/settings';\n\ninterface BulkActionBarProps {\n selectedCount: number;\n onClearSelection: () => void;\n onSetPriority: (priority: 1 | 2 | 3 | 4) => void;\n onClaim: (durationMinutes: number) => void;\n onAssign: () => void;\n onEscalate: (targetRole: string) => void;\n onTriage: () => void;\n onCancel: () => void;\n isPriorityPending: boolean;\n isClaimPending: boolean;\n isAssignPending: boolean;\n isEscalatePending: boolean;\n isTriagePending: boolean;\n isCancelPending: boolean;\n availableRoles: string[];\n}\n\nconst anyPending = (props: BulkActionBarProps) =>\n props.isPriorityPending || props.isClaimPending || props.isAssignPending || props.isEscalatePending || props.isTriagePending || props.isCancelPending;\n\n// One control chrome for the whole bar — white pill-free buttons on the band,\n// hairline border, a barely-there 3px radius (square reads timeless, not dated),\n// definition on hover. Selects share it so the toolbar is one cohesive set.\nconst CTRL =\n 'inline-flex items-center h-7 px-2.5 text-[11px] font-medium text-text-secondary bg-surface border border-surface-border rounded-[4px] hover:border-accent/50 hover:text-text-primary transition-colors disabled:opacity-50 disabled:hover:border-surface-border';\nconst SELECT = `${CTRL} appearance-none cursor-pointer`;\nconst DANGER =\n 'inline-flex items-center h-7 px-2.5 text-[11px] font-medium text-status-error bg-surface border border-status-error/30 rounded-[4px] hover:border-status-error hover:bg-status-error/5 transition-colors disabled:opacity-50';\n\nexport function BulkActionBar(props: BulkActionBarProps) {\n const disabled = anyPending(props);\n const claimDurations = useClaimDurations();\n // Triage is an LLM action. `useSettings().ai.enabled` is the single source of\n // truth — it merges the server /settings flag with the persisted localStorage\n // override (lt_ai_override). Hide the button entirely when AI is off.\n const { data: settings } = useSettings();\n const aiEnabled = settings?.ai?.enabled === true;\n const open = props.selectedCount > 0;\n\n return (\n // Animated reveal — grows and opacity-fades in/out with ease-in-out as the\n // selection changes. Always mounted so it can animate on exit, not just enter.\n <div\n className={`grid transition-all duration-200 ease-in-out ${\n open ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0 pointer-events-none'\n }`}\n >\n <div className=\"overflow-hidden\">\n {/* Contextual band: neutral fill + a 2px accent left rule anchors it as a\n distinct \"selection mode\" surface without a rounded card. */}\n <div className=\"flex flex-wrap items-center gap-2 py-2.5 pl-3 pr-2 mt-4 mb-3 bg-surface-sunken/60 border-l-2 border-l-accent\">\n <span className=\"text-[11px] font-semibold uppercase tracking-wider text-accent tabular-nums\">\n {props.selectedCount} selected\n </span>\n\n <div className=\"mx-1 h-4 w-px bg-surface-border\" />\n\n {/* Priority */}\n <select\n onChange={(e) => {\n if (!e.target.value) return;\n props.onSetPriority(parseInt(e.target.value) as 1 | 2 | 3 | 4);\n e.target.value = '';\n }}\n disabled={disabled}\n className={SELECT}\n defaultValue=\"\"\n >\n <option value=\"\" disabled>Priority…</option>\n {PRIORITY_OPTIONS.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n\n {/* Claim */}\n <select\n onChange={(e) => {\n if (!e.target.value) return;\n props.onClaim(parseInt(e.target.value));\n e.target.value = '';\n }}\n disabled={disabled}\n className={SELECT}\n defaultValue=\"\"\n >\n <option value=\"\" disabled>Claim for…</option>\n {claimDurations.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n\n {/* Assign */}\n <button onClick={props.onAssign} disabled={disabled} className={CTRL}>\n {props.isAssignPending ? 'Assigning…' : 'Assign to…'}\n </button>\n\n {/* Escalate */}\n {props.availableRoles.length > 0 && (\n <select\n onChange={(e) => {\n if (!e.target.value) return;\n props.onEscalate(e.target.value);\n e.target.value = '';\n }}\n disabled={disabled}\n className={SELECT}\n defaultValue=\"\"\n >\n <option value=\"\" disabled>Escalate to…</option>\n {props.availableRoles.map((role) => (\n <option key={role} value={role}>{role}</option>\n ))}\n </select>\n )}\n\n {/* Triage — LLM-powered, shown only when AI is enabled */}\n {aiEnabled && (\n <button onClick={props.onTriage} disabled={disabled} className={CTRL}>\n {props.isTriagePending ? 'Triaging…' : 'Triage'}\n </button>\n )}\n\n {/* Cancel */}\n <button onClick={props.onCancel} disabled={disabled} className={DANGER}>\n {props.isCancelPending ? 'Cancelling…' : 'Cancel'}\n </button>\n\n <div className=\"flex-1\" />\n\n {disabled && (\n <span className=\"text-[11px] text-text-tertiary animate-pulse\">Processing…</span>\n )}\n\n {/* Clear */}\n <button\n onClick={props.onClearSelection}\n className=\"px-1 text-[11px] font-medium text-text-tertiary hover:text-text-primary transition-colors\"\n >\n Clear\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import { useState, useCallback } from 'react';\nimport { Modal } from './Modal';\nimport { CustomDurationPicker } from '../form/CustomDurationPicker';\nimport { useUsers } from '../../../api/users';\nimport { useAuth } from '../../../hooks/useAuth';\nimport { useClaimDurations } from '../../../hooks/useClaimDurations';\nimport { useDebouncedValue } from '../../../hooks/useDebouncedValue';\nimport type { LTUserRecord } from '../../../api/types';\n\ninterface BulkAssignModalProps {\n open: boolean;\n onClose: () => void;\n selectedCount: number;\n /** Distinct roles of the selected escalations; scopes user list for admins */\n selectedRoles: string[];\n onSubmit: (targetUserId: string, durationMinutes: number) => void;\n isPending: boolean;\n}\n\nexport function BulkAssignModal({\n open,\n onClose,\n selectedCount,\n selectedRoles,\n onSubmit,\n isPending,\n}: BulkAssignModalProps) {\n const { isSuperAdmin } = useAuth();\n const claimDurations = useClaimDurations();\n const [step, setStep] = useState<'user' | 'duration'>('user');\n const [selectedUser, setSelectedUser] = useState<LTUserRecord | null>(null);\n const [search, setSearch] = useState('');\n const [duration, setDuration] = useState('30');\n const [customMinutes, setCustomMinutes] = useState(0);\n const onCustomChange = useCallback((m: number) => setCustomMinutes(m), []);\n\n // Admins with a single role: scope to that role. Otherwise show all active users.\n const roleFilter =\n !isSuperAdmin && selectedRoles.length === 1 ? selectedRoles[0] : undefined;\n\n // Search is resolved server-side (ILIKE on name/email/external_id) so it matches\n // every user, not just a fetched slice — no client-side filtering over a cap.\n const debouncedSearch = useDebouncedValue(search, 250);\n const { data: usersData, isLoading: usersLoading } = useUsers({\n role: roleFilter,\n status: 'active',\n search: debouncedSearch.trim() || undefined,\n limit: 200,\n });\n\n const users = usersData?.users ?? [];\n\n const handleClose = () => {\n setStep('user');\n setSelectedUser(null);\n setSearch('');\n setDuration('30');\n setCustomMinutes(0);\n onClose();\n };\n\n const handleSelectUser = (user: LTUserRecord) => {\n setSelectedUser(user);\n setStep('duration');\n };\n\n const handleBack = () => {\n setStep('user');\n };\n\n const handleSubmit = () => {\n if (!selectedUser) return;\n const minutes = duration === 'custom' ? customMinutes : parseInt(duration);\n if (!minutes || minutes <= 0) return;\n onSubmit(selectedUser.id, minutes);\n };\n\n return (\n <Modal open={open} onClose={handleClose} title=\"Assign Escalations\">\n <div className=\"space-y-4\">\n {step === 'user' && (\n <>\n <p className=\"text-sm text-text-secondary\">\n Select a user to assign{' '}\n <span className=\"font-medium text-text-primary\">\n {selectedCount}\n </span>{' '}\n escalation(s) to:\n </p>\n\n <input\n type=\"text\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search by name or email...\"\n className=\"input text-xs w-full\"\n autoFocus\n />\n\n <div className=\"max-h-60 overflow-y-auto border border-surface-border rounded-lg divide-y divide-surface-border\">\n {usersLoading && (\n <p className=\"text-xs text-text-tertiary p-3\">\n Loading users...\n </p>\n )}\n {!usersLoading && users.length === 0 && (\n <p className=\"text-xs text-text-tertiary p-3\">\n No users found\n </p>\n )}\n {users.map((user) => (\n <button\n key={user.id}\n onClick={() => handleSelectUser(user)}\n className=\"w-full text-left px-3 py-2 hover:bg-surface-hover transition-colors\"\n >\n <p className=\"text-xs font-medium text-text-primary\">\n {user.display_name || user.external_id}\n </p>\n {user.email && (\n <p className=\"text-[10px] text-text-tertiary\">\n {user.email}\n </p>\n )}\n </button>\n ))}\n </div>\n\n <div className=\"flex justify-end pt-2\">\n <button onClick={handleClose} className=\"btn-secondary text-xs\">\n Cancel\n </button>\n </div>\n </>\n )}\n\n {step === 'duration' && selectedUser && (\n <>\n <p className=\"text-sm text-text-secondary\">\n Assign to{' '}\n <span className=\"font-medium text-text-primary\">\n {selectedUser.display_name || selectedUser.external_id}\n </span>{' '}\n for:\n </p>\n\n <select\n value={duration}\n onChange={(e) => { setDuration(e.target.value); setCustomMinutes(0); }}\n className=\"select w-full text-sm\"\n >\n {claimDurations.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n <option value=\"custom\">Other...</option>\n </select>\n {duration === 'custom' && (\n <CustomDurationPicker onChange={onCustomChange} autoFocus />\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={handleBack} className=\"btn-secondary text-xs\">\n Back\n </button>\n <button\n onClick={handleSubmit}\n disabled={isPending}\n className=\"btn-primary text-xs\"\n >\n {isPending ? 'Assigning...' : 'Assign'}\n </button>\n </div>\n </>\n )}\n </div>\n </Modal>\n );\n}\n","import { useState } from 'react';\nimport { Modal } from './Modal';\n\ninterface BulkTriageModalProps {\n open: boolean;\n onClose: () => void;\n selectedCount: number;\n onSubmit: (hint?: string) => void;\n isPending: boolean;\n}\n\nexport function BulkTriageModal({\n open,\n onClose,\n selectedCount,\n onSubmit,\n isPending,\n}: BulkTriageModalProps) {\n const [hint, setHint] = useState('');\n\n const handleSubmit = () => {\n onSubmit(hint || undefined);\n };\n\n return (\n <Modal open={open} onClose={onClose} title=\"Submit for AI Triage\">\n <div className=\"space-y-4\">\n <p className=\"text-sm text-text-secondary\">\n Submit <span className=\"font-medium text-text-primary\">{selectedCount}</span> escalation(s)\n for AI triage? The triage orchestrator will take over resolution.\n </p>\n\n <div>\n <label className=\"text-xs font-medium text-text-secondary block mb-1\">\n Triage hint <span className=\"text-text-tertiary\">(optional)</span>\n </label>\n <input\n type=\"text\"\n value={hint}\n onChange={(e) => setHint(e.target.value)}\n placeholder=\"e.g., image_orientation\"\n className=\"input text-xs font-mono w-full\"\n />\n <p className=\"text-[10px] text-text-tertiary mt-1\">\n Guides the triage workflow on what remediation to apply\n </p>\n </div>\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={onClose} className=\"btn-secondary text-xs\">\n Cancel\n </button>\n <button\n onClick={handleSubmit}\n disabled={isPending}\n className=\"btn-primary text-xs\"\n >\n {isPending ? 'Submitting...' : 'Submit for Triage'}\n </button>\n </div>\n </div>\n </Modal>\n );\n}\n","import type { UseMutationResult } from '@tanstack/react-query';\n\n/**\n * Create a bulk-action handler that calls a mutation and clears selection on success.\n */\nfunction bulkHandler<TData, TVariables>(\n mutation: UseMutationResult<TData, Error, TVariables>,\n clearSelection: () => void,\n afterSuccess?: () => void,\n) {\n return (variables: TVariables) => {\n mutation.mutate(variables, {\n onSuccess: () => {\n clearSelection();\n afterSuccess?.();\n },\n });\n };\n}\n\nexport function createBulkHandlers(deps: {\n selectedIds: Set<string>;\n clearSelection: () => void;\n setPriority: UseMutationResult<{ updated: number }, Error, { ids: string[]; priority: 1 | 2 | 3 | 4 }>;\n bulkClaim: UseMutationResult<{ claimed: number; skipped: number }, Error, { ids: string[]; durationMinutes: number }>;\n bulkEscalate: UseMutationResult<{ updated: number }, Error, { ids: string[]; targetRole: string }>;\n bulkTriage: UseMutationResult<{ triaged: number }, Error, { ids: string[]; hint?: string }>;\n bulkAssign: UseMutationResult<{ assigned: number; skipped: number }, Error, { ids: string[]; targetUserId: string; durationMinutes: number }>;\n bulkCancel: UseMutationResult<{ cancelled: number; skipped: number }, Error, { ids: string[] }>;\n closeTriageModal: () => void;\n closeAssignModal: () => void;\n closeCancelModal: () => void;\n}) {\n const ids = () => [...deps.selectedIds];\n\n const handleSetPriority = (priority: 1 | 2 | 3 | 4) => {\n bulkHandler(\n deps.setPriority,\n deps.clearSelection,\n )({ ids: ids(), priority });\n };\n\n const handleBulkClaim = (durationMinutes: number) => {\n bulkHandler(\n deps.bulkClaim,\n deps.clearSelection,\n )({ ids: ids(), durationMinutes });\n };\n\n const handleBulkEscalate = (targetRole: string) => {\n bulkHandler(\n deps.bulkEscalate,\n deps.clearSelection,\n )({ ids: ids(), targetRole });\n };\n\n const handleBulkTriage = (hint?: string) => {\n bulkHandler(\n deps.bulkTriage,\n deps.clearSelection,\n deps.closeTriageModal,\n )({ ids: ids(), hint });\n };\n\n const handleBulkAssign = (targetUserId: string, durationMinutes: number) => {\n bulkHandler(\n deps.bulkAssign,\n deps.clearSelection,\n deps.closeAssignModal,\n )({ ids: ids(), targetUserId, durationMinutes });\n };\n\n const handleBulkCancel = () => {\n bulkHandler(\n deps.bulkCancel,\n deps.clearSelection,\n deps.closeCancelModal,\n )({ ids: ids() });\n };\n\n return { handleSetPriority, handleBulkClaim, handleBulkEscalate, handleBulkTriage, handleBulkAssign, handleBulkCancel };\n}\n","import { Modal } from '../../components/common/modal/Modal';\nimport { CustomDurationPicker } from '../../components/common/form/CustomDurationPicker';\nimport type { LTEscalationRecord } from '../../api/types';\n\ninterface ClaimModalProps {\n claimTarget: LTEscalationRecord | null;\n onClose: () => void;\n claimDuration: string;\n onDurationChange: (value: string) => void;\n claimDurations: Array<{ value: string; label: string }>;\n customClaimMinutes: number;\n onCustomClaimChange: (minutes: number) => void;\n onClaim: () => void;\n isPending: boolean;\n}\n\nexport function ClaimModal({\n claimTarget,\n onClose,\n claimDuration,\n onDurationChange,\n claimDurations,\n onCustomClaimChange,\n onClaim,\n isPending,\n}: ClaimModalProps) {\n return (\n <Modal\n open={!!claimTarget}\n onClose={onClose}\n title=\"Claim Escalation\"\n >\n <div className=\"space-y-4\">\n <p className=\"text-sm text-text-secondary\">\n Claim <span className=\"font-medium text-text-primary\">{claimTarget?.type}</span> for:\n </p>\n <select\n value={claimDuration}\n onChange={(e) => { onDurationChange(e.target.value); }}\n className=\"select w-full text-sm\"\n >\n {claimDurations.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n <option value=\"custom\">Other...</option>\n </select>\n {claimDuration === 'custom' && (\n <CustomDurationPicker onChange={onCustomClaimChange} autoFocus />\n )}\n <div className=\"flex justify-end gap-3 pt-2\">\n <button onClick={onClose} className=\"btn-secondary text-xs\">\n Cancel\n </button>\n <button\n onClick={onClaim}\n className=\"btn-primary text-xs\"\n disabled={isPending}\n >\n {isPending ? 'Claiming...' : 'Claim'}\n </button>\n </div>\n </div>\n </Modal>\n );\n}\n","import { useState, useEffect, useMemo, useCallback } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useNavigate, useSearchParams } from 'react-router-dom';\nimport { parseFacetParams, writeFacetParams, facetCount } from '../../lib/facet-url';\nimport { useAccess } from '../../hooks/useAccess';\nimport { useEscalationListEvents } from '../../hooks/useEventHooks';\nimport {\n useEscalations,\n useAvailableEscalations,\n useEscalationTypes,\n useFacetKeys,\n useClaimEscalation,\n useSetEscalationPriority,\n useBulkClaimEscalations,\n useBulkAssignEscalations,\n useBulkEscalateToRole,\n useBulkTriageEscalations,\n useBulkCancelEscalations,\n type FacetFilters,\n} from '../../api/escalations';\nimport { FacetedFilterPanel } from './FacetedFilterPanel';\nimport { ConfirmCancelModal } from '../../components/common/modal/ConfirmCancelModal';\nimport { useRoles } from '../../api/roles';\nimport { useFilterParams } from '../../hooks/useFilterParams';\nimport { useDebouncedValue } from '../../hooks/useDebouncedValue';\nimport { buildApiPath } from '../../lib/api-path';\nimport { DataTable, type Column } from '../../components/common/data/DataTable';\nimport { StickyPagination } from '../../components/common/data/StickyPagination';\nimport { PageHeader } from '../../components/common/layout/PageHeader';\nimport { BulkActionBar } from '../../components/common/modal/BulkActionBar';\nimport { BulkAssignModal } from '../../components/common/modal/BulkAssignModal';\nimport { BulkTriageModal } from '../../components/common/modal/BulkTriageModal';\nimport { useClaimDurations } from '../../hooks/useClaimDurations';\nimport { Lock, SlidersHorizontal, X } from 'lucide-react';\nimport { ESCALATION_COLUMNS, EscalationFilterBar } from './escalation-columns';\nimport { RowAction, RowActionGroup } from '../../components/common/layout/RowActions';\nimport { ListToolbar } from '../../components/common/data/ListToolbar';\nimport { createBulkHandlers } from './helpers';\nimport { ClaimModal } from './ClaimModal';\nimport type { LTEscalationRecord } from '../../api/types';\n\nexport function AvailableEscalationsPage() {\n useEscalationListEvents();\n const navigate = useNavigate();\n const { filters, setFilter, pagination, sort, setSort } = useFilterParams({\n filters: { role: '', type: '', priority: '', status: 'available', search: '' },\n });\n // Debounce so server-side search fires once the user pauses, not per keystroke.\n const debouncedSearch = useDebouncedValue(filters.search, 300);\n const claimDurations = useClaimDurations();\n const [claimTarget, setClaimTarget] = useState<LTEscalationRecord | null>(null);\n const [claimDuration, setClaimDuration] = useState('30');\n const [customClaimMinutes, setCustomClaimMinutes] = useState(0);\n const onCustomClaimChange = useCallback((m: number) => setCustomClaimMinutes(m), []);\n const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());\n // Faceted query — DEEP-LINKED in the URL (a shared link reproduces the exact query).\n // The drawer is the editor surface; fetched keys feed the autocomplete.\n const [facetDrawerOpen, setFacetDrawerOpen] = useState(false);\n const [searchParams, setSearchParams] = useSearchParams();\n const facetFilters = useMemo<FacetFilters>(() => parseFacetParams(searchParams), [searchParams]);\n const setFacetFilters = useCallback((next: FacetFilters) => {\n setSearchParams((prev) => {\n const p = new URLSearchParams(prev);\n writeFacetParams(p, next);\n p.delete('page');\n return p;\n }, { replace: true });\n }, [setSearchParams]);\n const { data: facetKeysData } = useFacetKeys(facetDrawerOpen);\n // The free-text term now lives in the drawer alongside the facets, so it counts\n // toward the active-query badge and is cleared by the drawer's Clear.\n const activeFacetCount = facetCount(facetFilters) + (filters.search ? 1 : 0);\n const [triageModalOpen, setTriageModalOpen] = useState(false);\n const [assignModalOpen, setAssignModalOpen] = useState(false);\n const [cancelModalOpen, setCancelModalOpen] = useState(false);\n\n const claim = useClaimEscalation();\n const setPriority = useSetEscalationPriority();\n const bulkClaim = useBulkClaimEscalations();\n const bulkAssign = useBulkAssignEscalations();\n const bulkEscalate = useBulkEscalateToRole();\n const bulkTriage = useBulkTriageEscalations();\n const bulkCancel = useBulkCancelEscalations();\n const { data: rolesData } = useRoles();\n const { data: typesData } = useEscalationTypes();\n\n // Clear selections on filter/page changes\n useEffect(() => {\n setSelectedIds(new Set());\n }, [filters.role, filters.type, filters.priority, filters.status, debouncedSearch, pagination.page, pagination.pageSize]);\n\n const statusFilter = filters.status || '';\n const isAvailable = statusFilter === 'available';\n const isClaimed = statusFilter === 'claimed';\n const apiStatus = isClaimed ? 'pending'\n : statusFilter === 'resolved' ? 'resolved'\n : statusFilter === 'cancelled' ? 'cancelled'\n : isAvailable ? undefined\n : undefined;\n\n const sharedFilters = {\n role: filters.role || undefined,\n type: filters.type || undefined,\n priority: filters.priority ? parseInt(filters.priority) : undefined,\n limit: pagination.pageSize,\n offset: pagination.offset,\n sort_by: sort.sort_by || 'created_at',\n order: sort.order || 'desc',\n search: debouncedSearch || undefined,\n // Faceted metadata query (composes with role-scope + the basic filters in SQL).\n ...facetFilters,\n };\n\n const availableQuery = useAvailableEscalations({\n ...sharedFilters,\n enabled: isAvailable,\n });\n\n const escalationsQuery = useEscalations({\n status: apiStatus,\n claimed: isClaimed || undefined,\n ...sharedFilters,\n enabled: !isAvailable,\n });\n\n const activeQuery = isAvailable ? availableQuery : escalationsQuery;\n const { data, isLoading, error: queryError, refetch, isFetching } = activeQuery;\n\n // Copy-URL/curl path built from the SAME params the active query sends, so the\n // generated command always reproduces the real request (filters + search + sort).\n const apiPath = buildApiPath(`/escalations${isAvailable ? '/available' : ''}`, {\n status: apiStatus,\n claimed: isClaimed || undefined,\n role: filters.role || undefined,\n type: filters.type || undefined,\n priority: filters.priority || undefined,\n search: debouncedSearch || undefined,\n sort_by: sort.sort_by || 'created_at',\n order: sort.order || 'desc',\n limit: pagination.pageSize,\n offset: pagination.offset,\n // Faceted query — JSON-encoded so the copy-URL/curl reproduces the exact query.\n facets: facetFilters.facets && Object.keys(facetFilters.facets).length ? JSON.stringify(facetFilters.facets) : undefined,\n block: facetFilters.block?.length ? JSON.stringify(facetFilters.block) : undefined,\n range: facetFilters.range?.length ? JSON.stringify(facetFilters.range) : undefined,\n exists: facetFilters.exists?.length ? JSON.stringify(facetFilters.exists) : undefined,\n roles: facetFilters.roles?.length ? JSON.stringify(facetFilters.roles) : undefined,\n orderBy: facetFilters.orderBy?.length ? JSON.stringify(facetFilters.orderBy) : undefined,\n available: facetFilters.available != null ? String(facetFilters.available) : undefined,\n });\n\n // Search is server-side (full result set), so results and total come straight\n // from the query — no client-side filtering of the current page.\n const escalations = data?.escalations ?? [];\n const total = data?.total ?? 0;\n const { canBulk: canBulkManage } = useAccess();\n\n const selectedRoles = useMemo(() => {\n const roles = new Set<string>();\n for (const esc of escalations) {\n if (selectedIds.has(esc.id)) roles.add(esc.role);\n }\n return [...roles];\n }, [escalations, selectedIds]);\n\n const clearSelection = useCallback(() => setSelectedIds(new Set()), []);\n\n const handleClaim = () => {\n if (!claimTarget) return;\n const minutes = claimDuration === 'custom' ? customClaimMinutes : parseInt(claimDuration);\n if (!minutes || minutes <= 0) return;\n claim.mutate(\n { id: claimTarget.id, durationMinutes: minutes },\n {\n onSuccess: () => {\n setClaimTarget(null);\n navigate(`/escalations/detail/${claimTarget.id}`);\n },\n },\n );\n };\n\n const {\n handleSetPriority,\n handleBulkClaim,\n handleBulkEscalate,\n handleBulkTriage,\n handleBulkAssign,\n handleBulkCancel,\n } = createBulkHandlers({\n selectedIds,\n clearSelection,\n setPriority,\n bulkClaim,\n bulkEscalate,\n bulkTriage,\n bulkAssign,\n bulkCancel,\n closeTriageModal: () => setTriageModalOpen(false),\n closeAssignModal: () => setAssignModalOpen(false),\n closeCancelModal: () => setCancelModalOpen(false),\n });\n\n const toggleSelect = (id: string) => {\n const next = new Set(selectedIds);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n setSelectedIds(next);\n };\n\n const toggleAll = () => {\n if (selectedIds.size === escalations.length) {\n setSelectedIds(new Set());\n } else {\n setSelectedIds(new Set(escalations.map((e) => e.id)));\n }\n };\n\n const columns: Column<LTEscalationRecord>[] = [\n canBulkManage ? {\n key: 'select',\n label: (\n <input\n type=\"checkbox\"\n checked={escalations.length > 0 && selectedIds.size === escalations.length}\n onChange={toggleAll}\n className=\"rounded\"\n />\n ) as any,\n render: (row: LTEscalationRecord) => (\n <input\n type=\"checkbox\"\n checked={selectedIds.has(row.id)}\n onChange={(e) => {\n e.stopPropagation();\n toggleSelect(row.id);\n }}\n onClick={(e) => e.stopPropagation()}\n className=\"rounded\"\n />\n ),\n className: 'w-10',\n } : {\n key: 'spacer',\n label: '',\n render: () => null,\n className: 'w-10',\n },\n ...ESCALATION_COLUMNS,\n {\n key: 'actions',\n label: '',\n render: (row) => (\n <RowActionGroup>\n <RowAction\n icon={Lock}\n title=\"Claim escalation\"\n onClick={() => setClaimTarget(row)}\n colorClass=\"text-accent/75 hover:text-accent\"\n size=\"sm\"\n />\n </RowActionGroup>\n ),\n className: 'w-10 text-right',\n },\n ];\n\n return (\n <div>\n <PageHeader title=\"Available Escalations\" docsHash=\"#docs:dashboard.md:all-escalations\" />\n\n <EscalationFilterBar\n filters={filters}\n setFilter={setFilter}\n roles={rolesData?.roles ?? []}\n types={typesData?.types ?? []}\n showStatus\n showSearch={false}\n actions={\n <>\n <ListToolbar\n onRefresh={() => refetch()}\n isFetching={isFetching}\n apiPath={apiPath}\n />\n <button\n onClick={() => setFacetDrawerOpen((v) => !v)}\n className=\"relative ml-2 inline-flex h-7 w-7 items-center justify-center rounded text-text-tertiary hover:bg-surface-hover hover:text-text-primary transition-colors\"\n title=\"Faceted query\"\n >\n <SlidersHorizontal className=\"w-4 h-4\" />\n {activeFacetCount > 0 && (\n <span className=\"absolute -right-1 -top-1 flex h-3.5 min-w-[14px] items-center justify-center rounded-full bg-accent px-0.5 text-[9px] font-medium text-white\">\n {activeFacetCount}\n </span>\n )}\n </button>\n </>\n }\n />\n\n {/* Faceted query — slide-out drawer (deep-linked state), portaled so fixed positioning\n works. Always mounted so it slides open/closed with a subtle transition. */}\n {createPortal(\n <div\n className={`fixed right-0 bottom-0 w-[420px] z-40 border-l border-surface-border bg-surface overflow-y-auto shadow-lg transition-transform duration-200 ease-out ${facetDrawerOpen ? 'translate-x-0' : 'pointer-events-none translate-x-full'}`}\n style={{ top: '3.5rem' }}\n aria-hidden={!facetDrawerOpen}\n >\n <div className=\"sticky top-0 z-10 flex items-center justify-between px-4 py-3 bg-surface border-b border-surface-border/50\">\n <span className=\"text-xs font-medium text-text-primary\">Faceted query</span>\n <div className=\"flex items-center gap-2\">\n {activeFacetCount > 0 && (\n <button\n onClick={() => { setFacetFilters({}); setFilter('search', ''); }}\n className=\"text-[11px] text-text-tertiary hover:text-text-primary transition-colors\"\n >\n Clear\n </button>\n )}\n <button\n onClick={() => setFacetDrawerOpen(false)}\n className=\"p-1 rounded hover:bg-surface-hover text-text-tertiary hover:text-text-primary transition-colors\"\n title=\"Close\"\n >\n <X className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n <div className=\"px-4 py-2\">\n <p className=\"mb-2 text-[11px] leading-snug text-text-tertiary\">\n Free-text recall plus precise metadata facets — they compose in one SQL query.\n Facet keys are the ones that actually exist in your visible escalations; the\n whole query is shareable via the URL.\n </p>\n <FacetedFilterPanel\n value={facetFilters}\n onChange={setFacetFilters}\n facetKeys={facetKeysData?.keys ?? []}\n search={filters.search ?? ''}\n onSearchChange={(v) => setFilter('search', v)}\n />\n </div>\n </div>,\n document.body,\n )}\n\n {/* Always mounted so the bar can animate in AND out as the selection changes. */}\n <BulkActionBar\n selectedCount={selectedIds.size}\n onClearSelection={() => setSelectedIds(new Set())}\n onSetPriority={handleSetPriority}\n onClaim={handleBulkClaim}\n onAssign={() => setAssignModalOpen(true)}\n onEscalate={handleBulkEscalate}\n onTriage={() => setTriageModalOpen(true)}\n onCancel={() => setCancelModalOpen(true)}\n isPriorityPending={setPriority.isPending}\n isClaimPending={bulkClaim.isPending}\n isAssignPending={bulkAssign.isPending}\n isEscalatePending={bulkEscalate.isPending}\n isTriagePending={bulkTriage.isPending}\n isCancelPending={bulkCancel.isPending}\n availableRoles={rolesData?.roles ?? []}\n />\n\n {queryError && (\n <div className=\"mb-4 px-4 py-3 rounded-md bg-status-error/10 border border-status-error/20 text-xs text-status-error\">\n {(queryError as Error).message === 'Session expired'\n ? 'Your session has expired. Please log in again.'\n : `Failed to load escalations: ${(queryError as Error).message}`}\n </div>\n )}\n\n <DataTable\n columns={columns}\n data={escalations}\n keyFn={(row) => row.id}\n onRowClick={(row) => navigate(`/escalations/detail/${row.id}`, { state: { from: '/escalations/available' } })}\n isLoading={isLoading}\n emptyMessage={queryError ? 'Unable to load data' : 'No available escalations'}\n sort={sort}\n onSort={setSort}\n />\n\n <StickyPagination\n page={pagination.page}\n totalPages={pagination.totalPages(total)}\n onPageChange={pagination.setPage}\n total={total}\n pageSize={pagination.pageSize}\n onPageSizeChange={pagination.setPageSize}\n />\n\n <ClaimModal\n claimTarget={claimTarget}\n onClose={() => setClaimTarget(null)}\n claimDuration={claimDuration}\n onDurationChange={(v) => { setClaimDuration(v); setCustomClaimMinutes(0); }}\n claimDurations={claimDurations}\n customClaimMinutes={customClaimMinutes}\n onCustomClaimChange={onCustomClaimChange}\n onClaim={handleClaim}\n isPending={claim.isPending}\n />\n\n <BulkTriageModal\n open={triageModalOpen}\n onClose={() => setTriageModalOpen(false)}\n selectedCount={selectedIds.size}\n onSubmit={handleBulkTriage}\n isPending={bulkTriage.isPending}\n />\n\n <BulkAssignModal\n open={assignModalOpen}\n onClose={() => setAssignModalOpen(false)}\n selectedCount={selectedIds.size}\n selectedRoles={selectedRoles}\n onSubmit={handleBulkAssign}\n isPending={bulkAssign.isPending}\n />\n\n <ConfirmCancelModal\n open={cancelModalOpen}\n onClose={() => setCancelModalOpen(false)}\n onConfirm={handleBulkCancel}\n selectedCount={selectedIds.size}\n isPending={bulkCancel.isPending}\n error={bulkCancel.error as Error | null}\n />\n </div>\n );\n}\n"],"names":["parse","v","isEmpty","parseFacetParams","sp","f","facets","block","range","exists","roles","orderBy","writeFacetParams","p","set","k","facetCount","_a","_b","_c","_d","RANGE_OPS","SORT_COLUMNS","inputCls","xBtn","coerce","recordRows","rec","key","value","blockRows","arr","o","Section","title","hint","children","jsxs","jsx","KeyInput","onChange","placeholder","e","FacetedFilterPanel","facetKeys","search","onSearchChange","exclude","ranges","sorts","setFacets","rows","r","setBlock","setRange","setExists","setSorts","c","row","next","_","j","x","s","anyPending","props","CTRL","SELECT","DANGER","BulkActionBar","disabled","claimDurations","useClaimDurations","settings","useSettings","aiEnabled","open","PRIORITY_OPTIONS","opt","role","BulkAssignModal","onClose","selectedCount","selectedRoles","onSubmit","isPending","isSuperAdmin","useAuth","step","setStep","useState","selectedUser","setSelectedUser","setSearch","duration","setDuration","customMinutes","setCustomMinutes","onCustomChange","useCallback","roleFilter","debouncedSearch","useDebouncedValue","usersData","usersLoading","useUsers","users","handleClose","handleSelectUser","user","handleBack","handleSubmit","minutes","Modal","Fragment","CustomDurationPicker","BulkTriageModal","setHint","bulkHandler","mutation","clearSelection","afterSuccess","variables","createBulkHandlers","deps","ids","priority","durationMinutes","targetRole","targetUserId","ClaimModal","claimTarget","claimDuration","onDurationChange","onCustomClaimChange","onClaim","AvailableEscalationsPage","useEscalationListEvents","navigate","useNavigate","filters","setFilter","pagination","sort","setSort","useFilterParams","setClaimTarget","setClaimDuration","customClaimMinutes","setCustomClaimMinutes","m","selectedIds","setSelectedIds","facetDrawerOpen","setFacetDrawerOpen","searchParams","setSearchParams","useSearchParams","facetFilters","useMemo","setFacetFilters","prev","facetKeysData","useFacetKeys","activeFacetCount","triageModalOpen","setTriageModalOpen","assignModalOpen","setAssignModalOpen","cancelModalOpen","setCancelModalOpen","claim","useClaimEscalation","setPriority","useSetEscalationPriority","bulkClaim","useBulkClaimEscalations","bulkAssign","useBulkAssignEscalations","bulkEscalate","useBulkEscalateToRole","bulkTriage","useBulkTriageEscalations","bulkCancel","useBulkCancelEscalations","rolesData","useRoles","typesData","useEscalationTypes","useEffect","statusFilter","isAvailable","isClaimed","apiStatus","sharedFilters","availableQuery","useAvailableEscalations","escalationsQuery","useEscalations","activeQuery","data","isLoading","queryError","refetch","isFetching","apiPath","buildApiPath","_e","escalations","total","canBulkManage","useAccess","esc","handleClaim","handleSetPriority","handleBulkClaim","handleBulkEscalate","handleBulkTriage","handleBulkAssign","handleBulkCancel","toggleSelect","id","toggleAll","columns","ESCALATION_COLUMNS","RowActionGroup","RowAction","Lock","PageHeader","EscalationFilterBar","ListToolbar","SlidersHorizontal","createPortal","X","DataTable","StickyPagination","ConfirmCancelModal"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a as l,j as e}from"./vendor-query-B2UbickB.js";import{j as oe,v as re,s as ce,t as le,b as P,R as de}from"./index-B1kc6itM.js";import{b as xe}from"./workflows-C4rjvQbI.js";import{u as pe}from"./pipelines-C_x0LTBN.js";import{u as me}from"./controlplane-D9HaFZsC.js";import{u as ue}from"./tasks-1eTuP02d.js";import{e as he,b as fe,u as je}from"./useEventHooks-BNZky4xM.js";import{R as O}from"./RolePill-B-V-31lC.js";import{W as p}from"./WorkflowPill-DDR0B6DN.js";import{L as m}from"./ListToolbar-DIJZfEgu.js";import{I as k,ad as u,v as U,aK as G,u as J,B as ge}from"./vendor-icons--Ivmp-RX.js";import{c as X,f as be}from"./vendor-react-CXumBFUA.js";const ve={completed:"bg-status-success",active:"bg-status-active",running:"bg-status-active",pending:"bg-status-pending",error:"bg-status-error",failed:"bg-status-error"};function K(t){return ve[t]??"bg-text-tertiary"}function h({icon:t,color:a,docsHash:n,count:i,children:r,actions:c}){return e.jsxs("div",{className:"flex items-center justify-between mb-4 pb-2 border-b border-surface-border",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(t,{className:`w-4.5 h-4.5 ${a||"text-accent/60"}`,strokeWidth:1.5}),e.jsx("h2",{className:"section-h2",children:r}),i!==void 0&&i>0&&e.jsx("span",{className:"text-[10px] text-text-quaternary tabular-nums",children:de(i)})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[n&&e.jsx("button",{onClick:()=>{window.location.hash=n},className:"text-text-quaternary hover:text-accent transition-colors",title:"Docs",children:e.jsx(ge,{className:"w-2.5 h-2.5",strokeWidth:1.5})}),c]})]})}function f({icon:t,text:a}){return e.jsxs("div",{className:"flex flex-col items-center justify-center py-10 text-center",children:[e.jsx(t,{className:"w-6 h-6 text-text-quaternary/50 mb-2",strokeWidth:1}),e.jsx("p",{className:"text-xs text-text-quaternary",children:a})]})}function ye(t,a=37){if(!t||t.length<=a)return t;const n=Math.floor((a-3)/2);return`${t.slice(0,n)}...${t.slice(-n)}`}function E({dot:t,pill:a,id:n,date:i,onClick:r}){return e.jsxs("button",{onClick:r,className:"w-full text-left hover:bg-surface-hover/50 rounded-md px-1 py-1.5 transition-colors",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-0.5",children:[e.jsx("span",{className:`w-1.5 h-1.5 rounded-full shrink-0 ${t}`}),e.jsx("span",{className:"text-[12px] text-text-primary font-mono truncate max-w-[60%]",children:ye(n)}),e.jsx("span",{className:"text-[10px] text-text-quaternary shrink-0 ml-auto whitespace-nowrap",children:e.jsx(P,{date:i})})]}),e.jsx("div",{className:"pl-3.5 flex items-center gap-1 overflow-hidden",children:a})]})}function j({to:t,icon:a,title:n}){const i=X();return e.jsx("button",{onClick:()=>i(t),className:"text-text-quaternary hover:text-accent transition-colors",title:n,children:e.jsx(a,{className:"w-2.5 h-2.5",strokeWidth:1.5})})}function V({appIds:t,selected:a,onSelect:n}){const[i,r]=l.useState(!1),c=l.useRef(null);return l.useEffect(()=>{if(!i)return;const o=g=>{c.current&&!c.current.contains(g.target)&&r(!1)};return document.addEventListener("mousedown",o),()=>document.removeEventListener("mousedown",o)},[i]),t.length<=1?null:e.jsxs("div",{className:"relative mb-3 -mt-2",ref:c,children:[e.jsxs("button",{onClick:()=>r(o=>!o),className:"flex items-center gap-1 px-2 py-0.5 text-[10px] rounded bg-accent/10 text-accent hover:bg-accent/20 transition-colors",children:[a,e.jsx("svg",{className:`w-2.5 h-2.5 transition-transform ${i?"rotate-180":""}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2.5,children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"})})]}),i&&e.jsx("div",{className:"absolute top-full left-0 mt-1 bg-surface-raised border border-surface-border rounded-md shadow-lg z-30 py-1 min-w-[120px]",children:t.map(o=>e.jsx("button",{onClick:()=>{n(o),r(!1)},className:`w-full text-left px-3 py-1.5 text-[11px] transition-colors ${a===o?"text-accent bg-accent/5":"text-text-secondary hover:bg-surface-hover"}`,children:o},o))})]})}function Fe(){var F,I,S,L,W,z,B,H,M,Q;const t=X(),{user:a}=oe(),{isBuilder:n}=re(),[i,r]=be(),{data:c}=me(),o=l.useMemo(()=>((c==null?void 0:c.apps)??[]).map(s=>s.appId).sort(),[c]),g=o[0]??"",b=i.get("pipelinenamespace")||g,_=i.get("durablenamespace")||g,A=l.useCallback((s,w)=>{r(ne=>{const D=new URLSearchParams(ne);return D.set(s,w),D},{replace:!1})},[r]);he(),fe(),je();const v=ue({limit:5}),y=xe({limit:5,sort_by:"updated_at",order:"desc",namespace:_}),Y=o,Z=o,N=pe({limit:5,app_id:b,sort_by:"updated_at",order:"desc"}),d=ce({limit:5,sort_by:"created_at",order:"desc"}),x=le({assigned_to:a==null?void 0:a.userId,status:"pending",limit:5,sort_by:"created_at",order:"desc"});l.useEffect(()=>{const s=setTimeout(()=>{x.refetch(),d.refetch()},2e3);return()=>clearTimeout(s)},[]);const C=((F=v.data)==null?void 0:F.processes)??[],ee=(I=v.data)==null?void 0:I.total,R=((S=y.data)==null?void 0:S.jobs)??[],se=(L=y.data)==null?void 0:L.total,$=((W=N.data)==null?void 0:W.jobs)??[],te=(z=N.data)==null?void 0:z.total,q=((B=d.data)==null?void 0:B.escalations)??[],ae=(H=d.data)==null?void 0:H.total,T=((M=x.data)==null?void 0:M.escalations)??[],ie=(Q=x.data)==null?void 0:Q.total;return e.jsxs("div",{children:[e.jsx("h1",{className:"text-3xl font-light text-text-primary mb-10",children:"Recent Activity"}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-x-14 min-h-[35vh]",children:[e.jsxs("div",{children:[e.jsx(h,{icon:k,color:"text-blue-400",count:ae,docsHash:"#docs:dashboard.md:all-escalations",actions:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(m,{onRefresh:()=>d.refetch(),isFetching:d.isFetching,apiPath:"/escalations?status=pending&limit=5&sort_by=created_at&order=desc"}),e.jsx(j,{to:"/escalations/available",icon:u,title:"All available escalations"})]}),children:"Available Escalations"}),q.length===0?e.jsx(f,{icon:k,text:"No pending escalations"}):e.jsx("div",{className:"space-y-1",children:q.map(s=>e.jsxs("button",{onClick:()=>t(`/escalations/detail/${s.id}`),className:"w-full text-left hover:bg-surface-hover/50 rounded-md px-1 py-1.5 transition-colors",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-0.5",children:[e.jsxs("span",{className:"text-[9px] text-text-quaternary font-medium shrink-0",children:["P",s.priority??2]}),e.jsx("span",{className:"text-[12px] text-text-primary truncate flex-1 max-w-[65%]",children:s.description||s.subtype||s.type}),e.jsx("span",{className:"text-[10px] text-text-quaternary shrink-0 ml-auto",children:e.jsx(P,{date:s.updated_at??s.created_at})})]}),e.jsxs("div",{className:"flex items-center gap-2 pl-5",children:[e.jsx(p,{type:s.type||"unknown",size:"xs"}),e.jsx("span",{className:"flex-1"}),e.jsx(O,{role:s.role})]})]},s.id))})]}),e.jsxs("div",{children:[e.jsx(h,{icon:k,color:"text-orange-400",count:ie,docsHash:"#docs:dashboard.md:escalations-overview",actions:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(m,{onRefresh:()=>x.refetch(),isFetching:x.isFetching,apiPath:`/escalations?assigned_to=${(a==null?void 0:a.userId)??""}&status=pending&limit=5&sort_by=created_at&order=desc`}),e.jsx(j,{to:"/escalations/queue",icon:u,title:"My escalation queue"})]}),children:"My Escalations"}),T.length===0?e.jsx(f,{icon:k,text:"No assigned escalations"}):e.jsx("div",{className:"space-y-1",children:T.map(s=>e.jsxs("button",{onClick:()=>t(`/escalations/detail/${s.id}`),className:"w-full text-left hover:bg-surface-hover/50 rounded-md px-1 py-1.5 transition-colors",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-0.5",children:[e.jsxs("span",{className:"text-[9px] text-text-quaternary font-medium shrink-0",children:["P",s.priority??2]}),e.jsx("span",{className:"text-[12px] text-text-primary truncate flex-1 max-w-[65%]",children:s.description||s.subtype||s.type}),e.jsx("span",{className:"text-[10px] text-text-quaternary shrink-0 ml-auto",children:e.jsx(P,{date:s.updated_at??s.created_at})})]}),e.jsxs("div",{className:"flex items-center gap-2 pl-5",children:[e.jsx(p,{type:s.type||"unknown",size:"xs"}),e.jsx("span",{className:"flex-1"}),e.jsx(O,{role:s.role})]})]},s.id))})]})]}),n&&e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-3 gap-x-14 mt-14",children:[e.jsxs("div",{children:[e.jsx(h,{icon:U,color:"text-emerald-400",count:ee,docsHash:"#docs:dashboard.md:processes-overview",actions:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(m,{onRefresh:()=>v.refetch(),isFetching:v.isFetching,apiPath:"/tasks/processes?limit=5"}),e.jsx(j,{to:"/processes/all",icon:u,title:"All processes"})]}),children:"Certified Processes"}),e.jsx("div",{className:"mb-3 -mt-2",children:e.jsx("span",{className:"px-2 py-0.5 text-[10px] rounded text-text-quaternary uppercase tracking-widest",children:"all namespaces"})}),C.length===0?e.jsx(f,{icon:U,text:"No recent processes"}):e.jsx("div",{className:"space-y-1",children:C.map(s=>e.jsx(E,{dot:(s.task_count??0)>0&&(s.completed??0)>=(s.task_count??0)?"bg-status-success":(s.escalated??0)>0?"border border-status-error":"bg-status-active",pill:e.jsx(e.Fragment,{children:(s.workflow_types??[s.workflow_type]).filter(Boolean).map(w=>e.jsx(p,{type:w,size:"xs"},w))}),id:s.origin_id,date:s.last_activity??s.started_at,onClick:()=>t(`/processes/detail/${s.origin_id}`)},s.origin_id))})]}),e.jsxs("div",{children:[e.jsx(h,{icon:G,color:"text-blue-400",count:se,docsHash:"#docs:dashboard.md:durable-executions",actions:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(m,{onRefresh:()=>y.refetch(),isFetching:y.isFetching,apiPath:`/workflow-states/jobs?namespace=${_}&limit=5`}),e.jsx(j,{to:"/workflows/executions",icon:u,title:"All durable executions"})]}),children:"Workflow Executions"}),e.jsx(V,{appIds:Y,selected:_,onSelect:s=>A("durablenamespace",s)}),R.length===0?e.jsx(f,{icon:G,text:"No recent executions"}):e.jsx("div",{className:"space-y-1",children:R.map(s=>e.jsx(E,{dot:K(s.status),pill:e.jsx(p,{type:s.entity||s.type||"workflow",size:"xs"}),id:s.workflow_id,date:s.updated_at??s.created_at,onClick:()=>t(`/workflows/executions/${s.workflow_id}`)},s.workflow_id))})]}),e.jsxs("div",{children:[e.jsx(h,{icon:J,color:"text-violet-400",count:te,docsHash:"#docs:dashboard.md:mcp-pipeline-tools",actions:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(m,{onRefresh:()=>N.refetch(),isFetching:N.isFetching,apiPath:`/pipelines?app_id=${b}&limit=5`}),e.jsx(j,{to:"/mcp/executions",icon:u,title:"All pipeline executions"})]}),children:"Pipeline Executions"}),e.jsx(V,{appIds:Z,selected:b,onSelect:s=>A("pipelinenamespace",s)}),$.length===0?e.jsx(f,{icon:J,text:"No recent pipeline runs"}):e.jsx("div",{className:"space-y-1",children:$.map(s=>e.jsx(E,{dot:K(s.status),pill:e.jsx(p,{type:s.entity||s.workflow_name||"pipeline",variant:"pipeline",size:"xs"}),id:s.workflow_id,date:s.updated_at??s.created_at,onClick:()=>t(`/mcp/executions/${s.workflow_id}?namespace=${b}`)},s.workflow_id))})]})]})]})}export{Fe as HomePage};
|
|
2
|
-
//# sourceMappingURL=HomePage-BZ1YTrjR.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"HomePage-BZ1YTrjR.js","sources":["../../src/pages/home/HomePage.tsx"],"sourcesContent":["import { useState, useRef, useCallback, useEffect, useMemo } from 'react';\nimport { useNavigate, useSearchParams } from 'react-router-dom';\nimport {\n Inbox, ScrollText, GitBranch, Layers, ExternalLink, BookOpen,\n} from 'lucide-react';\nimport { formatCountCompact } from '../../lib/format';\nimport { useAvailableEscalations, useEscalations } from '../../api/escalations';\nimport { useJobs } from '../../api/workflows';\nimport { useMcpRuns } from '../../api/pipelines';\nimport { useControlPlaneApps } from '../../api/controlplane';\nimport { useProcesses } from '../../api/tasks';\nimport { useAuth } from '../../hooks/useAuth';\nimport { useAccess } from '../../hooks/useAccess';\nimport { useEscalationStatsEvents, useWorkflowListEvents, useProcessListEvents } from '../../hooks/useEventHooks';\nimport { DateValue } from '../../components/common/display/DateValue';\nimport { RolePill } from '../../components/common/display/RolePill';\nimport { WorkflowPill } from '../../components/common/display/WorkflowPill';\nimport { ListToolbar } from '../../components/common/data/ListToolbar';\n\nconst STATUS_DOT: Record<string, string> = {\n completed: 'bg-status-success',\n active: 'bg-status-active',\n running: 'bg-status-active',\n pending: 'bg-status-pending',\n error: 'bg-status-error',\n failed: 'bg-status-error',\n};\nfunction statusDotClass(status: string): string {\n return STATUS_DOT[status] ?? 'bg-text-tertiary';\n}\n\n// ── Section header ──────────────────────────────────────────────────────────\n\nfunction SectionHeader({ icon: Icon, color, docsHash, count, children, actions }: { icon: React.ElementType; color?: string; docsHash?: string; count?: number; children: React.ReactNode; actions?: React.ReactNode }) {\n return (\n <div className=\"flex items-center justify-between mb-4 pb-2 border-b border-surface-border\">\n <div className=\"flex items-center gap-2\">\n <Icon className={`w-4.5 h-4.5 ${color || 'text-accent/60'}`} strokeWidth={1.5} />\n <h2 className=\"section-h2\">{children}</h2>\n {count !== undefined && count > 0 && (\n <span className=\"text-[10px] text-text-quaternary tabular-nums\">{formatCountCompact(count)}</span>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {docsHash && (\n <button onClick={() => { window.location.hash = docsHash; }} className=\"text-text-quaternary hover:text-accent transition-colors\" title=\"Docs\">\n <BookOpen className=\"w-2.5 h-2.5\" strokeWidth={1.5} />\n </button>\n )}\n {actions}\n </div>\n </div>\n );\n}\n\nfunction EmptyPanel({ icon: Icon, text }: { icon: React.ElementType; text: string }) {\n return (\n <div className=\"flex flex-col items-center justify-center py-10 text-center\">\n <Icon className=\"w-6 h-6 text-text-quaternary/50 mb-2\" strokeWidth={1} />\n <p className=\"text-xs text-text-quaternary\">{text}</p>\n </div>\n );\n}\n\n/** Middle-ellipsis: keep first N and last N chars with ... in between */\nfunction midEllipsis(s: string, maxLen = 37): string {\n if (!s || s.length <= maxLen) return s;\n const keep = Math.floor((maxLen - 3) / 2);\n return `${s.slice(0, keep)}...${s.slice(-keep)}`;\n}\n\n/** Consistent row for all execution lists in row 1 */\nfunction ExecutionRow({ dot, pill, id, date, onClick }: {\n dot: string;\n pill: React.ReactNode;\n id: string;\n date: string;\n onClick: () => void;\n}) {\n return (\n <button onClick={onClick} className=\"w-full text-left hover:bg-surface-hover/50 rounded-md px-1 py-1.5 transition-colors\">\n <div className=\"flex items-center gap-2 mb-0.5\">\n <span className={`w-1.5 h-1.5 rounded-full shrink-0 ${dot}`} />\n <span className=\"text-[12px] text-text-primary font-mono truncate max-w-[60%]\">{midEllipsis(id)}</span>\n <span className=\"text-[10px] text-text-quaternary shrink-0 ml-auto whitespace-nowrap\"><DateValue date={date} /></span>\n </div>\n <div className=\"pl-3.5 flex items-center gap-1 overflow-hidden\">{pill}</div>\n </button>\n );\n}\n\nfunction NavIcon({ to, icon: Icon, title }: { to: string; icon: React.ElementType; title: string }) {\n const navigate = useNavigate();\n return (\n <button\n onClick={() => navigate(to)}\n className=\"text-text-quaternary hover:text-accent transition-colors\"\n title={title}\n >\n <Icon className=\"w-2.5 h-2.5\" strokeWidth={1.5} />\n </button>\n );\n}\n\n// ── Namespace Picker ────────────────────────────────────────────────────────\n\nfunction AppPicker({ appIds, selected, onSelect }: {\n appIds: string[];\n selected: string;\n onSelect: (id: string) => void;\n}) {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!open) return;\n const handler = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [open]);\n\n if (appIds.length <= 1) return null;\n\n return (\n <div className=\"relative mb-3 -mt-2\" ref={ref}>\n <button\n onClick={() => setOpen((v) => !v)}\n className=\"flex items-center gap-1 px-2 py-0.5 text-[10px] rounded bg-accent/10 text-accent hover:bg-accent/20 transition-colors\"\n >\n {selected}\n <svg className={`w-2.5 h-2.5 transition-transform ${open ? 'rotate-180' : ''}`} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </button>\n {open && (\n <div className=\"absolute top-full left-0 mt-1 bg-surface-raised border border-surface-border rounded-md shadow-lg z-30 py-1 min-w-[120px]\">\n {appIds.map((id) => (\n <button\n key={id}\n onClick={() => { onSelect(id); setOpen(false); }}\n className={`w-full text-left px-3 py-1.5 text-[11px] transition-colors ${\n selected === id ? 'text-accent bg-accent/5' : 'text-text-secondary hover:bg-surface-hover'\n }`}\n >\n {id}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n// ── Page ─────────────────────────────────────────────────────────────────────\n\nexport function HomePage() {\n const navigate = useNavigate();\n const { user } = useAuth();\n const { isBuilder } = useAccess();\n const [searchParams, setSearchParams] = useSearchParams();\n const { data: cpData } = useControlPlaneApps();\n const allAppIds = useMemo(() => (cpData?.apps ?? []).map((a: any) => a.appId).sort(), [cpData]);\n const firstAppId = allAppIds[0] ?? '';\n const pipelineNs = searchParams.get('pipelinenamespace') || firstAppId;\n const durableNs = searchParams.get('durablenamespace') || firstAppId;\n const setNs = useCallback((key: string, ns: string) => {\n setSearchParams((prev) => {\n const next = new URLSearchParams(prev);\n next.set(key, ns);\n return next;\n }, { replace: false });\n }, [setSearchParams]);\n useEscalationStatsEvents();\n useWorkflowListEvents();\n useProcessListEvents();\n\n const procQ = useProcesses({ limit: 5 });\n const jobsQ = useJobs({ limit: 5, sort_by: 'updated_at', order: 'desc', namespace: durableNs });\n const durableAppIds = allAppIds;\n const pipelineAppIds = allAppIds;\n const mcpQ = useMcpRuns({ limit: 5, app_id: pipelineNs, sort_by: 'updated_at', order: 'desc' });\n const allEscQ = useAvailableEscalations({ limit: 5, sort_by: 'created_at', order: 'desc' });\n const myEscQ = useEscalations({ assigned_to: user?.userId, status: 'pending', limit: 5, sort_by: 'created_at', order: 'desc' });\n\n // Delayed refetch — allows signal-routed escalation resolutions\n // (durable activity) time to commit before refreshing the list\n useEffect(() => {\n const timer = setTimeout(() => {\n myEscQ.refetch();\n allEscQ.refetch();\n }, 2000);\n return () => clearTimeout(timer);\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n const processes = procQ.data?.processes ?? [];\n const processTotal = (procQ.data as any)?.total as number | undefined;\n const jobs = jobsQ.data?.jobs ?? [];\n const jobsTotal = jobsQ.data?.total;\n const mcpRuns = (mcpQ.data as any)?.jobs ?? [];\n const mcpTotal = (mcpQ.data as any)?.total as number | undefined;\n const allEscalations = allEscQ.data?.escalations ?? [];\n const allEscTotal = allEscQ.data?.total;\n const myEscalations = myEscQ.data?.escalations ?? [];\n const myEscTotal = myEscQ.data?.total;\n\n return (\n <div>\n <h1 className=\"text-3xl font-light text-text-primary mb-10\">Recent Activity</h1>\n\n {/* ── Row 1: Available Escalations | My Escalations ────────────────── */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-x-14 min-h-[35vh]\">\n\n {/* Col 1: Available Escalations */}\n <div>\n <SectionHeader icon={Inbox} color=\"text-blue-400\" count={allEscTotal} docsHash=\"#docs:dashboard.md:all-escalations\" actions={\n <div className=\"flex items-center gap-2\">\n <ListToolbar onRefresh={() => allEscQ.refetch()} isFetching={allEscQ.isFetching} apiPath=\"/escalations?status=pending&limit=5&sort_by=created_at&order=desc\" />\n <NavIcon to=\"/escalations/available\" icon={ExternalLink} title=\"All available escalations\" />\n </div>\n }>\n Available Escalations\n </SectionHeader>\n {allEscalations.length === 0 ? (\n <EmptyPanel icon={Inbox} text=\"No pending escalations\" />\n ) : (\n <div className=\"space-y-1\">\n {allEscalations.map((esc: any) => (\n <button\n key={esc.id}\n onClick={() => navigate(`/escalations/detail/${esc.id}`)}\n className=\"w-full text-left hover:bg-surface-hover/50 rounded-md px-1 py-1.5 transition-colors\"\n >\n <div className=\"flex items-center gap-2 mb-0.5\">\n <span className=\"text-[9px] text-text-quaternary font-medium shrink-0\">P{esc.priority ?? 2}</span>\n <span className=\"text-[12px] text-text-primary truncate flex-1 max-w-[65%]\">{esc.description || esc.subtype || esc.type}</span>\n <span className=\"text-[10px] text-text-quaternary shrink-0 ml-auto\"><DateValue date={esc.updated_at ?? esc.created_at} /></span>\n </div>\n <div className=\"flex items-center gap-2 pl-5\">\n <WorkflowPill type={esc.type || 'unknown'} size=\"xs\" />\n <span className=\"flex-1\" />\n <RolePill role={esc.role} />\n </div>\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Col 2: My Escalations */}\n <div>\n <SectionHeader icon={Inbox} color=\"text-orange-400\" count={myEscTotal} docsHash=\"#docs:dashboard.md:escalations-overview\" actions={\n <div className=\"flex items-center gap-2\">\n <ListToolbar onRefresh={() => myEscQ.refetch()} isFetching={myEscQ.isFetching} apiPath={`/escalations?assigned_to=${user?.userId ?? ''}&status=pending&limit=5&sort_by=created_at&order=desc`} />\n <NavIcon to=\"/escalations/queue\" icon={ExternalLink} title=\"My escalation queue\" />\n </div>\n }>\n My Escalations\n </SectionHeader>\n {myEscalations.length === 0 ? (\n <EmptyPanel icon={Inbox} text=\"No assigned escalations\" />\n ) : (\n <div className=\"space-y-1\">\n {myEscalations.map((esc: any) => (\n <button\n key={esc.id}\n onClick={() => navigate(`/escalations/detail/${esc.id}`)}\n className=\"w-full text-left hover:bg-surface-hover/50 rounded-md px-1 py-1.5 transition-colors\"\n >\n <div className=\"flex items-center gap-2 mb-0.5\">\n <span className=\"text-[9px] text-text-quaternary font-medium shrink-0\">P{esc.priority ?? 2}</span>\n <span className=\"text-[12px] text-text-primary truncate flex-1 max-w-[65%]\">{esc.description || esc.subtype || esc.type}</span>\n <span className=\"text-[10px] text-text-quaternary shrink-0 ml-auto\"><DateValue date={esc.updated_at ?? esc.created_at} /></span>\n </div>\n <div className=\"flex items-center gap-2 pl-5\">\n <WorkflowPill type={esc.type || 'unknown'} size=\"xs\" />\n <span className=\"flex-1\" />\n <RolePill role={esc.role} />\n </div>\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n\n {/* ── Row 2: Processes | Workflow Executions | Pipeline Executions (builders only) */}\n {isBuilder && <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-x-14 mt-14\">\n\n {/* Col 1: Processes */}\n <div>\n <SectionHeader icon={Layers} color=\"text-emerald-400\" count={processTotal} docsHash=\"#docs:dashboard.md:processes-overview\" actions={\n <div className=\"flex items-center gap-2\">\n <ListToolbar onRefresh={() => procQ.refetch()} isFetching={procQ.isFetching} apiPath=\"/tasks/processes?limit=5\" />\n <NavIcon to=\"/processes/all\" icon={ExternalLink} title=\"All processes\" />\n </div>\n }>\n Certified Processes\n </SectionHeader>\n <div className=\"mb-3 -mt-2\">\n <span className=\"px-2 py-0.5 text-[10px] rounded text-text-quaternary uppercase tracking-widest\">all namespaces</span>\n </div>\n {processes.length === 0 ? (\n <EmptyPanel icon={Layers} text=\"No recent processes\" />\n ) : (\n <div className=\"space-y-1\">\n {processes.map((p: any) => (\n <ExecutionRow\n key={p.origin_id}\n dot={(p.task_count ?? 0) > 0 && (p.completed ?? 0) >= (p.task_count ?? 0) ? 'bg-status-success' : (p.escalated ?? 0) > 0 ? 'border border-status-error' : 'bg-status-active'}\n pill={<>{(p.workflow_types ?? [p.workflow_type]).filter(Boolean).map((wt: string) => <WorkflowPill key={wt} type={wt} size=\"xs\" />)}</>}\n id={p.origin_id}\n date={p.last_activity ?? p.started_at}\n onClick={() => navigate(`/processes/detail/${p.origin_id}`)}\n />\n ))}\n </div>\n )}\n </div>\n\n {/* Col 2: Workflow Executions */}\n <div>\n <SectionHeader icon={ScrollText} color=\"text-blue-400\" count={jobsTotal} docsHash=\"#docs:dashboard.md:durable-executions\" actions={\n <div className=\"flex items-center gap-2\">\n <ListToolbar onRefresh={() => jobsQ.refetch()} isFetching={jobsQ.isFetching} apiPath={`/workflow-states/jobs?namespace=${durableNs}&limit=5`} />\n <NavIcon to=\"/workflows/executions\" icon={ExternalLink} title=\"All durable executions\" />\n </div>\n }>\n Workflow Executions\n </SectionHeader>\n <AppPicker appIds={durableAppIds} selected={durableNs} onSelect={(ns) => setNs('durablenamespace', ns)} />\n {jobs.length === 0 ? (\n <EmptyPanel icon={ScrollText} text=\"No recent executions\" />\n ) : (\n <div className=\"space-y-1\">\n {jobs.map((job: any) => (\n <ExecutionRow\n key={job.workflow_id}\n dot={statusDotClass(job.status)}\n pill={<WorkflowPill type={job.entity || job.type || 'workflow'} size=\"xs\" />}\n id={job.workflow_id}\n date={job.updated_at ?? job.created_at}\n onClick={() => navigate(`/workflows/executions/${job.workflow_id}`)}\n />\n ))}\n </div>\n )}\n </div>\n\n {/* Col 3: Pipeline Executions */}\n <div>\n <SectionHeader icon={GitBranch} color=\"text-violet-400\" count={mcpTotal} docsHash=\"#docs:dashboard.md:mcp-pipeline-tools\" actions={\n <div className=\"flex items-center gap-2\">\n <ListToolbar onRefresh={() => mcpQ.refetch()} isFetching={mcpQ.isFetching} apiPath={`/pipelines?app_id=${pipelineNs}&limit=5`} />\n <NavIcon to=\"/mcp/executions\" icon={ExternalLink} title=\"All pipeline executions\" />\n </div>\n }>\n Pipeline Executions\n </SectionHeader>\n <AppPicker appIds={pipelineAppIds} selected={pipelineNs} onSelect={(ns) => setNs('pipelinenamespace', ns)} />\n {mcpRuns.length === 0 ? (\n <EmptyPanel icon={GitBranch} text=\"No recent pipeline runs\" />\n ) : (\n <div className=\"space-y-1\">\n {mcpRuns.map((run: any) => (\n <ExecutionRow\n key={run.workflow_id}\n dot={statusDotClass(run.status)}\n pill={<WorkflowPill type={run.entity || run.workflow_name || 'pipeline'} variant=\"pipeline\" size=\"xs\" />}\n id={run.workflow_id}\n date={run.updated_at ?? run.created_at}\n onClick={() => navigate(`/mcp/executions/${run.workflow_id}?namespace=${pipelineNs}`)}\n />\n ))}\n </div>\n )}\n </div>\n </div>}\n </div>\n );\n}\n"],"names":["STATUS_DOT","statusDotClass","status","SectionHeader","Icon","color","docsHash","count","children","actions","jsxs","jsx","formatCountCompact","BookOpen","EmptyPanel","text","midEllipsis","s","maxLen","keep","ExecutionRow","dot","pill","id","date","onClick","DateValue","NavIcon","to","title","navigate","useNavigate","AppPicker","appIds","selected","onSelect","open","setOpen","useState","ref","useRef","useEffect","handler","e","v","HomePage","user","useAuth","isBuilder","useAccess","searchParams","setSearchParams","useSearchParams","cpData","useControlPlaneApps","allAppIds","useMemo","a","firstAppId","pipelineNs","durableNs","setNs","useCallback","key","ns","prev","next","useEscalationStatsEvents","useWorkflowListEvents","useProcessListEvents","procQ","useProcesses","jobsQ","useJobs","durableAppIds","pipelineAppIds","mcpQ","useMcpRuns","allEscQ","useAvailableEscalations","myEscQ","useEscalations","timer","processes","_a","processTotal","_b","jobs","_c","jobsTotal","_d","mcpRuns","_e","mcpTotal","_f","allEscalations","_g","allEscTotal","_h","myEscalations","_i","myEscTotal","_j","Inbox","ListToolbar","ExternalLink","esc","WorkflowPill","RolePill","Layers","p","wt","ScrollText","job","GitBranch","run"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a as i,j as e}from"./vendor-query-B2UbickB.js";import{b as y,c as b,d as v,e as C,f as w,g as k}from"./roles-QaGFZQ58.js";import{D as S}from"./DataTable-ZWgVQg7F.js";import{C as _}from"./ConfirmDeleteModal-D9_1b4MW.js";import{P as R}from"./PageHeader-B_1zTx2q.js";import{M as P}from"./Modal-CSrxpXeM.js";import{R as A,a as D}from"./RowActions-BA9L9djf.js";import{e as E,o as M,aa as T}from"./vendor-icons--Ivmp-RX.js";import"./index-B1kc6itM.js";import"./vendor-react-CXumBFUA.js";import"./EmptyState-BcsfPq9T.js";function F({open:t,onClose:s}){const a=y(),[c,u]=i.useState(""),[n,x]=i.useState(t);t!==n&&(x(t),t&&(u(""),a.reset()));const d=()=>{const l=c.trim().toLowerCase();l&&a.mutate(l,{onSuccess:s})};return e.jsx(P,{open:t,onClose:s,title:"Create Role",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Role Name (required)"}),e.jsx("input",{type:"text",value:c,onChange:l=>u(l.target.value),placeholder:"e.g., reviewer",className:"input text-xs w-full",onKeyDown:l=>{l.key==="Enter"&&d()}}),e.jsx("p",{className:"text-[10px] text-text-tertiary mt-1",children:"Lowercase letters, numbers, hyphens, and underscores only."})]}),a.error&&e.jsx("p",{className:"text-xs text-status-error",children:a.error.message}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:s,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:d,disabled:!c.trim()||a.isPending,className:"btn-primary text-xs",children:a.isPending?"Creating...":"Create"})]})]})})}function L({selectedRole:t,allRoles:s}){const{data:a}=b(),c=v(),u=C(),[n,x]=i.useState(""),d=(a==null?void 0:a.chains)??[],l=i.useMemo(()=>t?d.filter(r=>r.source_role===t).map(r=>r.target_role):[],[d,t]),p=i.useMemo(()=>t?s.filter(r=>r!==t&&r!=="superadmin"&&!l.includes(r)):[],[s,t,l]),h=()=>{!t||!n.trim()||c.mutate({source_role:t,target_role:n.trim()},{onSuccess:()=>x("")})},m=r=>{t&&u.mutate({source_role:t,target_role:r})},f=t==="superadmin";return e.jsxs("div",{className:"border-l border-surface-border pl-6 min-h-[300px]",children:[e.jsx("p",{className:"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-4",children:"Escalation Routing"}),t?f?e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-mono text-text-primary mb-2",children:t}),e.jsx("p",{className:"text-xs text-text-tertiary",children:"Superadmins can escalate to any role implicitly."})]}):e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-mono text-text-primary",children:t}),e.jsx("p",{className:"text-[10px] text-text-tertiary mt-0.5",children:"Can escalate to:"})]}),l.length===0?e.jsx("p",{className:"text-xs text-text-tertiary",children:"No escalation targets configured."}):e.jsx("div",{className:"flex flex-wrap gap-2",children:l.map(r=>e.jsxs("span",{className:"inline-flex items-center gap-1.5 px-2.5 py-1 text-xs bg-surface-sunken rounded-full text-text-secondary font-mono",children:[r,e.jsx("button",{onClick:()=>m(r),className:"text-text-tertiary hover:text-status-error transition-colors",title:`Remove ${r}`,children:"×"})]},r))}),p.length>0&&e.jsxs("div",{className:"pt-3 border-t border-surface-border",children:[e.jsx("p",{className:"text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-2",children:"Add Target"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("select",{value:n,onChange:r=>x(r.target.value),className:"select text-xs font-mono flex-1",children:[e.jsx("option",{value:"",children:"Select a role..."}),p.map(r=>e.jsx("option",{value:r,children:r},r))]}),e.jsx("button",{onClick:h,disabled:!n||c.isPending,className:"btn-primary text-xs",children:c.isPending?"Adding...":"Add"})]})]})]}):e.jsx("p",{className:"text-xs text-text-tertiary",children:"Select a role to manage its escalation targets."})]})}function q(t){return[{key:"role",label:"Role",render:s=>e.jsxs("div",{className:"flex items-center gap-2.5",children:[e.jsx(E,{className:"w-4 h-4 text-accent/60 shrink-0"}),e.jsx("span",{className:"text-sm text-text-primary",children:s.role})]})},{key:"user_count",label:"Users",render:s=>s.user_count>0?e.jsx("span",{className:"text-text-primary",children:s.user_count}):e.jsx("span",{className:"text-text-tertiary",children:"0"}),className:"w-24 text-right"},{key:"chain_count",label:"Escalations",render:s=>s.chain_count>0?e.jsx("span",{className:"text-text-primary",children:s.chain_count}):e.jsx("span",{className:"text-text-tertiary",children:"0"}),className:"w-28 text-right"},{key:"workflow_count",label:"Workflows",render:s=>s.workflow_count>0?e.jsx("span",{className:"text-text-primary",children:s.workflow_count}):e.jsx("span",{className:"text-text-tertiary",children:"0"}),className:"w-28 text-right"},{key:"actions",label:"",render:s=>s.user_count>0||s.chain_count>0||s.workflow_count>0?null:e.jsx(A,{children:e.jsx(D,{icon:M,title:"Delete role",onClick:()=>t(s),colorClass:"text-text-tertiary hover:text-status-error"})}),className:"w-16 text-right"}]}function Q(){const{data:t,isLoading:s}=w(),a=k(),[c,u]=i.useState(!1),[n,x]=i.useState(null),[d,l]=i.useState(null),[p,h]=i.useState(""),m=(t==null?void 0:t.roles)??[],f=i.useMemo(()=>m.map(o=>o.role),[m]),r=i.useMemo(()=>{if(!p.trim())return m;const o=p.toLowerCase();return m.filter(N=>N.role.toLowerCase().includes(o))},[m,p]),j=q(o=>x(o)),g=()=>{n&&a.mutate(n.role,{onSuccess:()=>x(null)})};return e.jsxs("div",{children:[e.jsx(R,{title:"Roles",docsHash:"#docs:dashboard.md:roles-and-permissions",actions:e.jsx("button",{onClick:()=>u(!0),className:"btn-primary text-xs",children:"Add Role"})}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-[1fr_320px] gap-6 items-start",children:[e.jsxs("div",{children:[e.jsx("div",{className:"sticky top-0 z-20 bg-surface pt-3 pb-3",children:e.jsx("div",{className:"bg-[#F7F7F7] rounded-lg px-5 py-2",children:e.jsxs("div",{className:"relative w-1/2",children:[e.jsx(T,{className:"absolute left-0 top-1/2 -translate-y-1/2 w-3 h-3 text-text-quaternary"}),e.jsx("input",{type:"text",value:p,onChange:o=>h(o.target.value),placeholder:`Search ${m.length} roles…`,className:"w-full pl-5 py-1 text-sm bg-transparent border-b border-surface-border/60 text-text-primary placeholder:text-text-quaternary focus:outline-none focus:border-accent/50 transition-colors"})]})})}),e.jsx(S,{columns:j,data:r,keyFn:o=>o.role,isLoading:s,emptyMessage:"No roles found",onRowClick:o=>l(o.role),activeRowKey:d})]}),e.jsx("div",{className:"sticky top-4",children:e.jsx(L,{selectedRole:d,allRoles:f})})]}),e.jsx(F,{open:c,onClose:()=>u(!1)}),e.jsx(_,{open:!!n,onClose:()=>x(null),onConfirm:g,title:"Delete Role",description:e.jsxs(e.Fragment,{children:["Delete role"," ",e.jsx("span",{className:"font-medium font-mono text-text-primary",children:n==null?void 0:n.role}),"? This action cannot be undone."]}),isPending:a.isPending,error:a.error})]})}export{Q as RolesPage};
|
|
2
|
-
//# sourceMappingURL=RolesPage-DLnaW6iD.js.map
|