@hotmeshio/long-tail 0.8.4 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/api/escalations/index.d.ts +1 -1
- package/build/api/escalations/index.js +2 -1
- package/build/api/escalations/resolve.d.ts +28 -0
- package/build/api/escalations/resolve.js +98 -0
- package/build/api/roles.d.ts +21 -0
- package/build/api/roles.js +50 -0
- package/build/lib/db/index.js +12 -1
- package/build/lib/db/migrate.js +27 -0
- package/build/lib/db/schemas/021_role_list_schema.sql +27 -0
- package/build/modules/defaults.d.ts +2 -0
- package/build/modules/defaults.js +3 -1
- package/build/routes/escalations/resolve.js +18 -0
- package/build/routes/roles.js +20 -0
- package/build/sdk/index.d.ts +8 -0
- package/build/sdk/index.js +1 -0
- package/build/services/escalation/crud.d.ts +36 -0
- package/build/services/escalation/crud.js +53 -0
- package/build/services/maintenance/index.js +22 -0
- package/build/services/role/index.d.ts +13 -1
- package/build/services/role/index.js +27 -0
- package/build/services/role/sql.d.ts +14 -2
- package/build/services/role/sql.js +51 -3
- package/build/services/role/types.d.ts +27 -0
- package/build/types/maintenance.d.ts +6 -1
- package/dashboard/dist/assets/{AdminDashboard-B-JptT54.js → AdminDashboard-5bWcBxyS.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-B-JptT54.js.map → AdminDashboard-5bWcBxyS.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-B1Jc6iJk.js → AgentConfigPage-CVg_tFbf.js} +6 -6
- package/dashboard/dist/assets/{AgentConfigPage-B1Jc6iJk.js.map → AgentConfigPage-CVg_tFbf.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-CWpclCOY.js → AgentDetailPage-CLlkIoRQ.js} +4 -4
- package/dashboard/dist/assets/{AgentDetailPage-CWpclCOY.js.map → AgentDetailPage-CLlkIoRQ.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-DyAf5GA2.js → AgentsPage-CjruF_ek.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-DyAf5GA2.js.map → AgentsPage-CjruF_ek.js.map} +1 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-h6awiuVk.js +2 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-h6awiuVk.js.map +1 -0
- package/dashboard/dist/assets/{BotPicker-B1RdaNuY.js → BotPicker-CGEFHHDE.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-B1RdaNuY.js.map → BotPicker-CGEFHHDE.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-CxHDnyjX.js → CapabilitiesPage-BI1tNYun.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-CxHDnyjX.js.map → CapabilitiesPage-BI1tNYun.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-Ds0e8cCO.js → CollapsibleSection-B9f52Z2K.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-Ds0e8cCO.js.map → CollapsibleSection-B9f52Z2K.js.map} +1 -1
- package/dashboard/dist/assets/{CopyableId-blg-gZvT.js → CopyableId-uot2mE_g.js} +2 -2
- package/dashboard/dist/assets/{CopyableId-blg-gZvT.js.map → CopyableId-uot2mE_g.js.map} +1 -1
- package/dashboard/dist/assets/CountdownTimer-C71erQ67.js +2 -0
- package/dashboard/dist/assets/CountdownTimer-C71erQ67.js.map +1 -0
- package/dashboard/dist/assets/{CredentialsPage-D8UVO-3A.js → CredentialsPage-smk5H_mP.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-D8UVO-3A.js.map → CredentialsPage-smk5H_mP.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-ZesYXxCH.js → CronLabel-CCJLmkIq.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-ZesYXxCH.js.map → CronLabel-CCJLmkIq.js.map} +1 -1
- package/dashboard/dist/assets/CustomDurationPicker-DQ28g5GB.js +2 -0
- package/dashboard/dist/assets/CustomDurationPicker-DQ28g5GB.js.map +1 -0
- package/dashboard/dist/assets/DataTable-Byn3oyT9.js +2 -0
- package/dashboard/dist/assets/DataTable-Byn3oyT9.js.map +1 -0
- package/dashboard/dist/assets/{DropZone-SgiK1WOl.js → DropZone-C_Mc4UrO.js} +2 -2
- package/dashboard/dist/assets/{DropZone-SgiK1WOl.js.map → DropZone-C_Mc4UrO.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-CO8S6vdb.js → ElapsedCell-Cw1uvJKx.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-CO8S6vdb.js.map → ElapsedCell-Cw1uvJKx.js.map} +1 -1
- package/dashboard/dist/assets/EscalationListSchemaPage-3v2tiCnq.js +20 -0
- package/dashboard/dist/assets/EscalationListSchemaPage-3v2tiCnq.js.map +1 -0
- package/dashboard/dist/assets/EscalationSchemaPage-DIq2pMED.js +9 -0
- package/dashboard/dist/assets/EscalationSchemaPage-DIq2pMED.js.map +1 -0
- package/dashboard/dist/assets/{EscalationsOverview-DMpRvVql.js → EscalationsOverview-BqOZ1v8w.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-DMpRvVql.js.map → EscalationsOverview-BqOZ1v8w.js.map} +1 -1
- package/dashboard/dist/assets/EventTable-CyfHfOWj.js +2 -0
- package/dashboard/dist/assets/EventTable-CyfHfOWj.js.map +1 -0
- package/dashboard/dist/assets/{FilterBar-B4Mk2PvT.js → FilterBar-DDIn8TOs.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-B4Mk2PvT.js.map → FilterBar-DDIn8TOs.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-CTuul-av.js → GraphInvokePage-DbNUaWhH.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-CTuul-av.js.map → GraphInvokePage-DbNUaWhH.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-BKFpOaHX.js → HomePage-Cj9sLt4Z.js} +2 -2
- package/dashboard/dist/assets/{HomePage-BKFpOaHX.js.map → HomePage-Cj9sLt4Z.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-Dz2_neVF.js → ListToolbar-D7PoQOZC.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-Dz2_neVF.js.map → ListToolbar-D7PoQOZC.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-Do-vaEqV.js → McpOverview-D9g1iJyn.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-Do-vaEqV.js.map → McpOverview-D9g1iJyn.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-HwDGNSbN.js → McpQueryDetailPage-DwS1pXdT.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-HwDGNSbN.js.map → McpQueryDetailPage-DwS1pXdT.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-DxMUpQ7R.js → McpQueryPage-DZQ1z6-H.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-DxMUpQ7R.js.map → McpQueryPage-DZQ1z6-H.js.map} +1 -1
- package/dashboard/dist/assets/McpRunDetailPage-Bx6w39lr.js +2 -0
- package/dashboard/dist/assets/{McpRunDetailPage-BzzZIXIk.js.map → McpRunDetailPage-Bx6w39lr.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-D3J42d2i.js → McpRunsPage-C-oS_tTh.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-D3J42d2i.js.map → McpRunsPage-C-oS_tTh.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-SErKwgkb.js → NamespacePill-DhgC3EUO.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-SErKwgkb.js.map → NamespacePill-DhgC3EUO.js.map} +1 -1
- package/dashboard/dist/assets/OperationsPage-CQzX6jM1.js +2 -0
- package/dashboard/dist/assets/OperationsPage-CQzX6jM1.js.map +1 -0
- package/dashboard/dist/assets/OperatorDashboard-Cqf87ojd.js +2 -0
- package/dashboard/dist/assets/{OperatorDashboard-BqJn8wEZ.js.map → OperatorDashboard-Cqf87ojd.js.map} +1 -1
- package/dashboard/dist/assets/PageHeader-sGNTmSXX.js +2 -0
- package/dashboard/dist/assets/PageHeader-sGNTmSXX.js.map +1 -0
- package/dashboard/dist/assets/{PageHeaderWithStats-W3akV6nB.js → PageHeaderWithStats-87STTAJX.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-W3akV6nB.js.map → PageHeaderWithStats-87STTAJX.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-C8sT2xuE.js → ProcessDetailPage-CplnDXkz.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-C8sT2xuE.js.map → ProcessDetailPage-CplnDXkz.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-eA8buUgd.js → ProcessesListPage-DFOJC27f.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-eA8buUgd.js.map → ProcessesListPage-DFOJC27f.js.map} +1 -1
- package/dashboard/dist/assets/RoleDetailPage-VrWOaPlg.js +8 -0
- package/dashboard/dist/assets/RoleDetailPage-VrWOaPlg.js.map +1 -0
- package/dashboard/dist/assets/{RolePill-DHWixsQR.js → RolePill-C91qbDOW.js} +2 -2
- package/dashboard/dist/assets/{RolePill-DHWixsQR.js.map → RolePill-C91qbDOW.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-BQNQxsMY.js → RolesPage-DdI1rVAP.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-BQNQxsMY.js.map → RolesPage-DdI1rVAP.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-mhusrlYE.js → RunAsSelector-C6EozzKV.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-mhusrlYE.js.map → RunAsSelector-C6EozzKV.js.map} +1 -1
- package/dashboard/dist/assets/SlidePanel-BpWveV1T.js +2 -0
- package/dashboard/dist/assets/SlidePanel-BpWveV1T.js.map +1 -0
- package/dashboard/dist/assets/{StatusBadge-DZ9137bI.js → StatusBadge-CEQMRmSQ.js} +2 -2
- package/dashboard/dist/assets/StatusBadge-CEQMRmSQ.js.map +1 -0
- package/dashboard/dist/assets/{StickyPagination-CqT9Q1I6.js → StickyPagination-BEgkYJ0-.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-CqT9Q1I6.js.map → StickyPagination-BEgkYJ0-.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-jOJaoupp.js → StreamMessageDetail-DWVPtzj7.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-jOJaoupp.js.map → StreamMessageDetail-DWVPtzj7.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-BrfmWgAj.js → SwimlaneTimeline-4NrDJNYc.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-BrfmWgAj.js.map → SwimlaneTimeline-4NrDJNYc.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-CGGC3DTR.js → TagInput-Csm36_pS.js} +2 -2
- package/dashboard/dist/assets/{TagInput-CGGC3DTR.js.map → TagInput-Csm36_pS.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-Cus_JHIC.js → TaskDetailPage-BvdaAUtF.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-Cus_JHIC.js.map → TaskDetailPage-BvdaAUtF.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-D6omQJNY.js → TaskQueuePill-5XdNaqwM.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-D6omQJNY.js.map → TaskQueuePill-5XdNaqwM.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-B7GK8AoX.js → TasksListPage-BxA161LH.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-B7GK8AoX.js.map → TasksListPage-BxA161LH.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-C606LzT3.js → TimeAgo-ChwJ4fjZ.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-C606LzT3.js.map → TimeAgo-ChwJ4fjZ.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-hfh6zvH-.js → TimestampCell-C7KzmvyC.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-hfh6zvH-.js.map → TimestampCell-C7KzmvyC.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-BW0iRwZu.js → ToolPill-CAwj7EPw.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-BW0iRwZu.js.map → ToolPill-CAwj7EPw.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-CsPsyvQq.js → ToolTestPanel-ISkuXtkT.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-CsPsyvQq.js.map → ToolTestPanel-ISkuXtkT.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-Diz6r7zr.js → TopicDetailPage-D8uZ8Wbs.js} +3 -3
- package/dashboard/dist/assets/{TopicDetailPage-Diz6r7zr.js.map → TopicDetailPage-D8uZ8Wbs.js.map} +1 -1
- package/dashboard/dist/assets/TopicsPage-rj88vA_1.js +2 -0
- package/dashboard/dist/assets/{TopicsPage-B6fn7fFh.js.map → TopicsPage-rj88vA_1.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-Cc-5QH5q.js → UserName-D03Lh6Aj.js} +2 -2
- package/dashboard/dist/assets/{UserName-Cc-5QH5q.js.map → UserName-D03Lh6Aj.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowExecutionPage-LD9WzPee.js +2 -0
- package/dashboard/dist/assets/WorkflowExecutionPage-LD9WzPee.js.map +1 -0
- package/dashboard/dist/assets/{WorkflowPill-BtNBSplz.js → WorkflowPill-fodIWnT3.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-BtNBSplz.js.map → WorkflowPill-fodIWnT3.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-CHCM6hUa.js → WorkflowsDashboard-DH0jitAb.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-CHCM6hUa.js.map → WorkflowsDashboard-DH0jitAb.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-WeOvl8-_.js → WorkflowsOverview-D6BVaH9e.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-WeOvl8-_.js.map → WorkflowsOverview-D6BVaH9e.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-6GfhVDpv.js → YamlWorkflowDetailPage-D_CfNEqW.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-6GfhVDpv.js.map → YamlWorkflowDetailPage-D_CfNEqW.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-DqcY3ocP.js → YamlWorkflowsPage-BMJgtcAq.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-DqcY3ocP.js.map → YamlWorkflowsPage-BMJgtcAq.js.map} +1 -1
- package/dashboard/dist/assets/{agents-DlzvjNxE.js → agents-Ci0tZDO3.js} +2 -2
- package/dashboard/dist/assets/{agents-DlzvjNxE.js.map → agents-Ci0tZDO3.js.map} +1 -1
- package/dashboard/dist/assets/{bots-CWMN-KUI.js → bots-DZyt1oO4.js} +2 -2
- package/dashboard/dist/assets/{bots-CWMN-KUI.js.map → bots-DZyt1oO4.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-_WSZ7cxO.js → capabilities-DzVKeWyC.js} +2 -2
- package/dashboard/dist/assets/{capabilities-_WSZ7cxO.js.map → capabilities-DzVKeWyC.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-_k9nWZy3.js → controlplane-CQzrn-rD.js} +2 -2
- package/dashboard/dist/assets/{controlplane-_k9nWZy3.js.map → controlplane-CQzrn-rD.js.map} +1 -1
- package/dashboard/dist/assets/escalation-columns-s29Q4mrF.js +2 -0
- package/dashboard/dist/assets/{escalation-columns-Dyrf6Tdp.js.map → escalation-columns-s29Q4mrF.js.map} +1 -1
- package/dashboard/dist/assets/{index-kKufOPLo.js → index-3SrgIA7w.js} +2 -2
- package/dashboard/dist/assets/{index-kKufOPLo.js.map → index-3SrgIA7w.js.map} +1 -1
- package/dashboard/dist/assets/{index-Dd4Si1Rl.js → index-B2dB90aC.js} +2 -2
- package/dashboard/dist/assets/{index-Dd4Si1Rl.js.map → index-B2dB90aC.js.map} +1 -1
- package/dashboard/dist/assets/index-BSOcWfeR.js +5 -0
- package/dashboard/dist/assets/index-BSOcWfeR.js.map +1 -0
- package/dashboard/dist/assets/{index-uUYXmvFf.js → index-BWy4UvaT.js} +2 -2
- package/dashboard/dist/assets/{index-uUYXmvFf.js.map → index-BWy4UvaT.js.map} +1 -1
- package/dashboard/dist/assets/{index-C3h0qGzG.js → index-BqKxJ2fB.js} +2 -2
- package/dashboard/dist/assets/{index-C3h0qGzG.js.map → index-BqKxJ2fB.js.map} +1 -1
- package/dashboard/dist/assets/{index-DwWP-Z_c.js → index-C9moIiIq.js} +5 -5
- package/dashboard/dist/assets/{index-DwWP-Z_c.js.map → index-C9moIiIq.js.map} +1 -1
- package/dashboard/dist/assets/{index-Dc-Ye2wk.js → index-CcKXMU-s.js} +2 -2
- package/dashboard/dist/assets/{index-Dc-Ye2wk.js.map → index-CcKXMU-s.js.map} +1 -1
- package/dashboard/dist/assets/index-DIPe82gq.css +1 -0
- package/dashboard/dist/assets/{index-D8GcHxNJ.js → index-DOHGHMP7.js} +2 -2
- package/dashboard/dist/assets/{index-D8GcHxNJ.js.map → index-DOHGHMP7.js.map} +1 -1
- package/dashboard/dist/assets/{index-C5Yc3TT7.js → index-DTn4XzYN.js} +2 -2
- package/dashboard/dist/assets/{index-C5Yc3TT7.js.map → index-DTn4XzYN.js.map} +1 -1
- package/dashboard/dist/assets/index-Dv8mzG9B.js +2 -0
- package/dashboard/dist/assets/index-Dv8mzG9B.js.map +1 -0
- package/dashboard/dist/assets/{index-Ex5tEte8.js → index-LwodswlU.js} +2 -2
- package/dashboard/dist/assets/{index-Ex5tEte8.js.map → index-LwodswlU.js.map} +1 -1
- package/dashboard/dist/assets/{index-C7VXLKJs.js → index-kPipMHZx.js} +2 -2
- package/dashboard/dist/assets/{index-C7VXLKJs.js.map → index-kPipMHZx.js.map} +1 -1
- package/dashboard/dist/assets/{index-BiApvBEz.js → index-sdc9ecdW.js} +2 -2
- package/dashboard/dist/assets/{index-BiApvBEz.js.map → index-sdc9ecdW.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-fYoEF4Lx.js → knowledge-fi5z5YLq.js} +2 -2
- package/dashboard/dist/assets/{knowledge-fYoEF4Lx.js.map → knowledge-fi5z5YLq.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-1lzlgtS8.js → mcp-CH8Tj9Pw.js} +2 -2
- package/dashboard/dist/assets/{mcp-1lzlgtS8.js.map → mcp-CH8Tj9Pw.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-nlrAz7m_.js → mcp-query-6alwNh7K.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-nlrAz7m_.js.map → mcp-query-6alwNh7K.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-Ihi7EKXi.js → pipelines-Dqh9PLUw.js} +2 -2
- package/dashboard/dist/assets/{pipelines-Ihi7EKXi.js.map → pipelines-Dqh9PLUw.js.map} +1 -1
- package/dashboard/dist/assets/roles-dJKBZUBh.js +2 -0
- package/dashboard/dist/assets/roles-dJKBZUBh.js.map +1 -0
- package/dashboard/dist/assets/{tasks-Crk9Y3C4.js → tasks-BYz490un.js} +2 -2
- package/dashboard/dist/assets/{tasks-Crk9Y3C4.js.map → tasks-BYz490un.js.map} +1 -1
- package/dashboard/dist/assets/{topics-CtfcCyw9.js → topics-Dt975EWi.js} +2 -2
- package/dashboard/dist/assets/{topics-CtfcCyw9.js.map → topics-Dt975EWi.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-Dn_vN2xE.js → useEventHooks-ZT6RV2Gj.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-Dn_vN2xE.js.map → useEventHooks-ZT6RV2Gj.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-Cfs3vKWk.js → useNamespace-B_G1iE9i.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-Cfs3vKWk.js.map → useNamespace-B_G1iE9i.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-ymobxH47.js → useYamlActivityEvents-DGkvIadL.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-ymobxH47.js.map → useYamlActivityEvents-DGkvIadL.js.map} +1 -1
- package/dashboard/dist/assets/{users-DngGIiC_.js → users-C2jopvM1.js} +2 -2
- package/dashboard/dist/assets/{users-DngGIiC_.js.map → users-C2jopvM1.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-DOIDKgo6.js → vendor-icons-BXhWQC7l.js} +161 -121
- package/dashboard/dist/assets/vendor-icons-BXhWQC7l.js.map +1 -0
- package/dashboard/dist/assets/{workflows-DuUspMAl.js → workflows-By8Wgvig.js} +2 -2
- package/dashboard/dist/assets/{workflows-DuUspMAl.js.map → workflows-By8Wgvig.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-DXQCiOsP.js → yaml-workflows-Cq_vp41d.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-DXQCiOsP.js.map → yaml-workflows-Cq_vp41d.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/api/http/escalations.md +20 -0
- package/docs/api/sdk/escalations.md +37 -2
- package/docs/dashboard.md +16 -3
- package/docs/data.md +1 -1
- package/docs/hitl-guide.md +240 -21
- package/docs/maintenance.md +6 -3
- package/docs/oauth-and-delegation.md +1 -1
- package/package.json +3 -3
- package/dashboard/dist/assets/AvailableEscalationsPage-DDwAgklw.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-DDwAgklw.js.map +0 -1
- package/dashboard/dist/assets/CustomDurationPicker-OKlwH5a_.js +0 -2
- package/dashboard/dist/assets/CustomDurationPicker-OKlwH5a_.js.map +0 -1
- package/dashboard/dist/assets/DataTable-ZWgVQg7F.js +0 -2
- package/dashboard/dist/assets/DataTable-ZWgVQg7F.js.map +0 -1
- package/dashboard/dist/assets/EscalationSchemaPage-Br5sD8-N.js +0 -9
- package/dashboard/dist/assets/EscalationSchemaPage-Br5sD8-N.js.map +0 -1
- package/dashboard/dist/assets/EventTable-BARJeiS2.js +0 -2
- package/dashboard/dist/assets/EventTable-BARJeiS2.js.map +0 -1
- package/dashboard/dist/assets/McpRunDetailPage-BzzZIXIk.js +0 -2
- package/dashboard/dist/assets/OperationsPage-BaM-QDhy.js +0 -2
- package/dashboard/dist/assets/OperationsPage-BaM-QDhy.js.map +0 -1
- package/dashboard/dist/assets/OperatorDashboard-BqJn8wEZ.js +0 -2
- package/dashboard/dist/assets/PageHeader-DJo7yMUR.js +0 -2
- package/dashboard/dist/assets/PageHeader-DJo7yMUR.js.map +0 -1
- package/dashboard/dist/assets/RoleDetailPage-aR-ror5v.js +0 -11
- package/dashboard/dist/assets/RoleDetailPage-aR-ror5v.js.map +0 -1
- package/dashboard/dist/assets/StatusBadge-DZ9137bI.js.map +0 -1
- package/dashboard/dist/assets/TopicsPage-B6fn7fFh.js +0 -2
- package/dashboard/dist/assets/WorkflowExecutionPage-BFq7UdhA.js +0 -2
- package/dashboard/dist/assets/WorkflowExecutionPage-BFq7UdhA.js.map +0 -1
- package/dashboard/dist/assets/escalation-CK8ElYzD.js +0 -2
- package/dashboard/dist/assets/escalation-CK8ElYzD.js.map +0 -1
- package/dashboard/dist/assets/escalation-columns-Dyrf6Tdp.js +0 -2
- package/dashboard/dist/assets/index-BdqKh0UK.css +0 -1
- package/dashboard/dist/assets/index-OV1JoB_P.js +0 -6
- package/dashboard/dist/assets/index-OV1JoB_P.js.map +0 -1
- package/dashboard/dist/assets/index-ZBj6Xgim.js +0 -2
- package/dashboard/dist/assets/index-ZBj6Xgim.js.map +0 -1
- package/dashboard/dist/assets/roles-D4Wn7kE9.js +0 -2
- package/dashboard/dist/assets/roles-D4Wn7kE9.js.map +0 -1
- package/dashboard/dist/assets/useCollapsedSections-BU5HULGs.js +0 -2
- package/dashboard/dist/assets/useCollapsedSections-BU5HULGs.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-DOIDKgo6.js.map +0 -1
|
@@ -387,7 +387,7 @@ export async function stationWorker(envelope: LTEnvelope) {
|
|
|
387
387
|
workflowType: 'stationWorker',
|
|
388
388
|
metadata: { orderId: envelope.data.orderId, station: 'qc' },
|
|
389
389
|
envelope: { instructions: 'Review and approve or reject' },
|
|
390
|
-
timeout: '24h', // SLA for this worklist row
|
|
390
|
+
timeout: '24h', // SLA for this worklist row
|
|
391
391
|
});
|
|
392
392
|
|
|
393
393
|
if (decision === false) {
|
|
@@ -405,7 +405,7 @@ export async function stationWorker(envelope: LTEnvelope) {
|
|
|
405
405
|
|
|
406
406
|
### SLA-gated waits (`timeout`)
|
|
407
407
|
|
|
408
|
-
`ConditionQueueConfig.timeout`
|
|
408
|
+
`ConditionQueueConfig.timeout` arms the same resume timer as
|
|
409
409
|
`condition(signalId, '24h')` **in the same single Leg1 write** that creates the
|
|
410
410
|
escalation row. The race is resolved atomically on both sides: a signal that
|
|
411
411
|
arrives first resolves the row normally and the timer is inert; a timer that
|
|
@@ -823,6 +823,41 @@ const result = await lt.escalations.resolveByIds({
|
|
|
823
823
|
|
|
824
824
|
**Returns:** `LTApiResult<{ resolved: number; escalationIds: string[] }>` — only still-`pending` rows are resolved.
|
|
825
825
|
|
|
826
|
+
## resolveAllOrNone
|
|
827
|
+
|
|
828
|
+
Atomic bulk resolve with per-row payloads: every listed escalation resolves with its own `resolverPayload` in one SQL statement, or nothing resolves. Rows backing a live `condition()` waiter are first-class — each waiter's wake commits with its resolve, delivering that row's payload as the condition's return value (the same wake contract as `resolve`). Use it for gang handoffs where each member must receive a distinct mandate and a partial batch is unacceptable.
|
|
829
|
+
|
|
830
|
+
RBAC matches `resolveByIds`: per-item write scope, and any missing or out-of-scope id returns 404 with nothing resolved. `requireClaimed` additionally asserts — inside the same guarded statement — that every row is currently assigned to the caller, closing the window where another principal re-claims a member between the caller's claim and the resolve.
|
|
831
|
+
|
|
832
|
+
```typescript
|
|
833
|
+
const result = await lt.escalations.resolveAllOrNone({
|
|
834
|
+
items: [
|
|
835
|
+
{ id: 'esc_left', resolverPayload: { gcodeRef: 'gcode-left', unit: 'left' } },
|
|
836
|
+
{ id: 'esc_right', resolverPayload: { gcodeRef: 'gcode-right', unit: 'right' } },
|
|
837
|
+
],
|
|
838
|
+
metadata: { outcome: 'gang-dispatched' },
|
|
839
|
+
requireClaimed: true,
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
if (result.status === 409) {
|
|
843
|
+
// nothing resolved — result.data.failed names exactly the blocking rows
|
|
844
|
+
// (not-found | already-resolved | already-cancelled | already-expired |
|
|
845
|
+
// assignee-mismatch | unsupported-resolution-path); re-gang around them
|
|
846
|
+
}
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
| Field | Type | Required | Description |
|
|
850
|
+
|-------|------|----------|-------------|
|
|
851
|
+
| `items` | `Array<{ id, resolverPayload }>` | Yes | The batch — each row resolves with its own payload. Ids must be unique; max 100 items (`LT_ESCALATION_BULK_RESOLVE_MAX`) |
|
|
852
|
+
| `metadata` | `Record<string, any>` | No | Shared outcome patch merged into every row's GIN-indexed metadata |
|
|
853
|
+
| `requireClaimed` | `boolean` | No | Assert every row is currently assigned to the caller, inside the atomic statement |
|
|
854
|
+
|
|
855
|
+
**Returns:** `LTApiResult<{ resolved: number; escalationIds: string[] }>` on success. On 409 the data carries `{ error, failedIds, failed: [{ id, reason }] }` — only the rows that blocked the batch are listed; resolvable members stay pending, untouched.
|
|
856
|
+
|
|
857
|
+
Rows that resolve through legacy signal routing (`metadata.signal_id` / `metadata.signal_routing`) require the single `resolve` path, which delivers their workflow signal; including one blocks the batch with reason `unsupported-resolution-path`. Password-format fields are redacted per row against that row's own `form_schema` before the payload enters the signal store.
|
|
858
|
+
|
|
859
|
+
**Auth:** Required
|
|
860
|
+
|
|
826
861
|
## resolveBySignalKey
|
|
827
862
|
|
|
828
863
|
Resolve an efficient (atomic) escalation directly by its `signal_key` and resume the waiting workflow in place. For callers that know the deterministic signal id and want to skip the id lookup. RBAC-scoped to the escalation's role.
|
package/docs/dashboard.md
CHANGED
|
@@ -6,7 +6,7 @@ The Long Tail dashboard is a React single-page application for managing procedur
|
|
|
6
6
|
|
|
7
7
|
The sidebar organizes pages into six groups.
|
|
8
8
|
|
|
9
|
-
###
|
|
9
|
+
### Monitor
|
|
10
10
|
|
|
11
11
|
The reactive, event-driven surface — where operations watch the floor and builders configure choreography.
|
|
12
12
|
|
|
@@ -196,7 +196,9 @@ Lists all procedural workflow runs across the system.
|
|
|
196
196
|
|
|
197
197
|
- **Tier filter** (top) — switch between All, Certified, and Durable to focus on specific workflow types.
|
|
198
198
|
- **Columns:** Workflow name, workflow ID, status (running/completed/failed), start time, and duration.
|
|
199
|
-
- **Click any row** to see the full execution detail:
|
|
199
|
+
- **Click any row** to see the full execution detail: the swimlane timeline and events fill the main column, and a full-height side panel carries the record's facts. The main header stays quiet — just the title and a panel toggle; status, the refresh/copy toolbar, and the **Actions** menu (a small caret anchor at the right of the panel's icon row) all live in the panel. The panel and main column share the width as a flex set — the main column narrows as the panel expands.
|
|
200
|
+
- **Details** — status, workflow identity (type, ID, parent), task queue, start/end times, duration, history size, and activity counts.
|
|
201
|
+
- **Escalations** — every escalation the workflow raised, each a row with type, role, age, and status badge, so multiple escalations across the run's lifecycle read as a table rather than running on; related child tasks list the same way below.
|
|
200
202
|
- **Duration** is computed from start to completion — useful for identifying slow workflows or comparing performance across versions.
|
|
201
203
|
|
|
202
204
|
**API:** `GET /api/workflows/executions` lists runs with tier, status, and pagination filters.
|
|
@@ -265,6 +267,15 @@ Accessible at `/admin/roles/:role/schema`. The versioned form behind a role's es
|
|
|
265
267
|
|
|
266
268
|
**API:** `GET /api/roles/:role/schema` fetches the latest or a pinned version. `GET /api/roles/:role/schema/versions` lists the history. `PATCH /api/roles/:role` with `form_schema` (+ optional `change_summary`) saves a new version.
|
|
267
269
|
|
|
270
|
+
### Escalations List Schema
|
|
271
|
+
|
|
272
|
+
Accessible at `/admin/roles/:role/list-schema`. The versioned rich view for the role's escalation **list** page — the list-page analog of the resolve form. Opt-in: when a role owns a `list_schema`, its list page renders a role-authored view (the live item as a card plus a load-on-demand history) instead of the engineer table, scoped to that one role. See the [HITL guide](hitl-guide.md#escalations-list-schema) for the `x-lt-layout` / `x-lt-active` / `x-lt-history` vocabulary.
|
|
273
|
+
|
|
274
|
+
- **Editor + version rail** — same shape as the Escalation Schema editor, but on its own **independent** version timeline: editing the list view never advances the resolve form's version.
|
|
275
|
+
- The list always renders the latest version — no pinning (a display template, not a payload contract).
|
|
276
|
+
|
|
277
|
+
**API:** `GET /api/roles/:role/list-schema` (latest or `?version=`), `GET /api/roles/:role/list-schema/versions`, and `PATCH /api/roles/:role` with `list_schema` (+ optional `change_summary`).
|
|
278
|
+
|
|
268
279
|
### DB Maintenance
|
|
269
280
|
|
|
270
281
|
Database housekeeping tools for keeping PostgreSQL healthy under sustained workflow load.
|
|
@@ -294,7 +305,7 @@ Browse individual stream messages from the Postgres engine and worker stream tab
|
|
|
294
305
|
|
|
295
306
|
- **Namespace & Source** — required filters. Engine streams carry internal orchestration messages; worker streams carry task messages with workflow metadata (job ID, activity, message type).
|
|
296
307
|
- **Filters** — narrow by status (pending, claimed, processed, dead-lettered) and stream name (partial match).
|
|
297
|
-
- **Message detail** — click any row to open the inspector panel. Shows timestamps, retry info, worker metadata, and the full JSON payload with expandable tree view.
|
|
308
|
+
- **Message detail** — click any row to slide open the inspector panel: a full-height column beside the table with its own scroll, like the left nav. The table narrows to make room, so no cells are covered. Shows timestamps, retry info, worker metadata, and the full JSON payload with expandable tree view.
|
|
298
309
|
- **Pagination & sorting** — standard controls. Sort by created time, stream name, or priority.
|
|
299
310
|
|
|
300
311
|
Messages are read-only. Status is derived from timestamps: pending (no timestamps set), claimed (reserved), processed (expired), or dead-lettered.
|
|
@@ -307,9 +318,11 @@ The central queue for all escalation activity across every workflow.
|
|
|
307
318
|
|
|
308
319
|
- **Filter bar** — filter by status (pending/claimed/resolved), role, workflow type, priority, and time window.
|
|
309
320
|
- **Columns:** Escalation ID, workflow type, role, status, priority, created time, and claimed-by user.
|
|
321
|
+
- **Rich list view** — when the list is scoped to exactly one role (`?role=<role>`) and that role owns a [list schema](#escalations-list-schema), a role-authored view renders in place of the table (the live item as a card, plus a load-on-demand history), with a **Table view** toggle back to the columns.
|
|
310
322
|
- **Claim** — click the claim action to lock an escalation to your user. Only users with matching roles see pending escalations. The queue list and aggregate stats reflect `read_all` memberships — a member scoped to `read_self` lands directly on their own assigned item in user mode rather than browsing the full queue.
|
|
311
323
|
- **Resolve** — after claiming, submit a resolver payload. The form is pre-filled from the role's versioned `form_schema` field defaults and from the workflow's seeded `envelope.formDefaults` (reverse-mapped through each field's `x-lt-bind`). The dashboard maps the flat form to the nested payload via `x-lt-bind` and the submitted payload is stored as-is. Resolution triggers a workflow re-run with the resolver data injected. A `member` whose `write_scope` is `self` can resolve only items already assigned to them; `write_scope=none` is read-only.
|
|
312
324
|
- **Escalate** — forward a claimed escalation to a higher-tier role via the escalation chain.
|
|
325
|
+
- **Side panel** — a slide-in beside the resolve form with switchable views, selected by the icon set at its top: **Help** (the form's `x-lt-help` markdown, `{{domain.path}}`-interpolated against the live record, or a state-aware hint such as "Claim this escalation to enable the form"), **Details** (status, role, priority, claim provenance, timestamps, and — for builders — identifier links), **AI Analysis** (what triage diagnosed and corrected — shown when AI is enabled and triage data is present), **Metadata** (the row's metadata values), **Context** (input envelope, escalation context, resolver payload), and **Record** (the raw escalation JSON, builders only). The panel and form share the width as a flex set — the form column narrows as the panel expands. It opens expanded on Help when the form carries `x-lt-help`, stays hidden otherwise, and the page-header panel button toggles it either way.
|
|
313
326
|
|
|
314
327
|
**API:** `GET /api/escalations` lists with filters. `POST /api/escalations/:id/claim` claims. `POST /api/escalations/:id/resolve` resolves.
|
|
315
328
|
|
package/docs/data.md
CHANGED
|
@@ -104,7 +104,7 @@ Records human intervention requests. Created when a workflow returns
|
|
|
104
104
|
workflow calls `condition(signalId, config)` / `conditionLT(signalId, config)`.
|
|
105
105
|
Updated when claimed or resolved.
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
The storage is the **shared HotMesh table `public.hmsh_escalations`**
|
|
108
108
|
(written by both long-tail and the HotMesh SDK). `lt_escalations` remains as a
|
|
109
109
|
backward-compatible **view** over it — `SELECT *` plus a computed `available`
|
|
110
110
|
column — so existing read queries and the public API are unchanged. Indexes are
|
package/docs/hitl-guide.md
CHANGED
|
@@ -83,9 +83,24 @@ export async function approvalWorkflow(envelope: LTEnvelope) {
|
|
|
83
83
|
}
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
The `timeout` field
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
The `timeout` field makes the wait SLA-gated in the same single Leg1 write:
|
|
87
|
+
one `conditionLT` call yields the worklist row AND the resume timer. Omit it
|
|
88
|
+
for an open-ended wait.
|
|
89
|
+
|
|
90
|
+
Two engine contracts worth building on:
|
|
91
|
+
|
|
92
|
+
- **The row is complete from its first visible moment.** Every field of the
|
|
93
|
+
config — including `metadata` facets — commits inside the Leg1 checkpoint.
|
|
94
|
+
A claim-by-metadata router or a version-pinned facet (e.g. a
|
|
95
|
+
`schema_version` the resolver UI renders) can trust every row it reads;
|
|
96
|
+
there is no window where a row is visible but its metadata is still en route.
|
|
97
|
+
- **Early signals are buffered.** A resolve that races ahead of the
|
|
98
|
+
`condition()` registration (a fast webhook, a payload deposited before the
|
|
99
|
+
workflow starts) is held as a pending signal and delivered when the wait
|
|
100
|
+
registers — 10 minutes by default; pass `expire` to `signal()` (e.g. `'1h'`)
|
|
101
|
+
when signaling early on purpose. Fan-out (`Promise.all` over many waits)
|
|
102
|
+
scales the same way: buffering covers every signal that outruns its
|
|
103
|
+
registration.
|
|
89
104
|
|
|
90
105
|
#### Two-step form
|
|
91
106
|
|
|
@@ -209,12 +224,48 @@ await lt.escalations.resolve({
|
|
|
209
224
|
|
|
210
225
|
The patch is distinct from the resolver payload: the payload resumes the paused workflow and is not indexed; the metadata patch is the durable, queryable record on the row. Use it for the audit trail and analytics — disposition, reviewer, time-to-resolve — so the escalation table answers *what was asked, what was decided, and how long it took* without a parallel log.
|
|
211
226
|
|
|
227
|
+
### Resolving a set atomically
|
|
228
|
+
|
|
229
|
+
When one decision settles a SET of waits — each with its own payload — use
|
|
230
|
+
`lt.escalations.resolveAllOrNone({ items })` (`POST /api/escalations/resolve-all-or-none`).
|
|
231
|
+
Every listed row resolves with its own `resolverPayload` in one SQL statement,
|
|
232
|
+
waking each parked workflow with its own value, or nothing resolves and the
|
|
233
|
+
409 body names exactly the rows that blocked (`failedIds` + reasons). Pass
|
|
234
|
+
`requireClaimed: true` in claim-then-resolve flows to assert, inside the same
|
|
235
|
+
statement, that every row is still assigned to the caller. See the
|
|
236
|
+
[SDK reference](./api/sdk/escalations.md#resolveallornone) for the full contract.
|
|
237
|
+
|
|
212
238
|
---
|
|
213
239
|
|
|
214
240
|
## JSON Schema Form Authoring
|
|
215
241
|
|
|
216
242
|
The dashboard renders forms automatically from JSON Schema. No frontend code needed.
|
|
217
243
|
|
|
244
|
+
The full custom vocabulary at a glance — every `x-lt-*` keyword and extension key the renderer honors:
|
|
245
|
+
|
|
246
|
+
| Keyword | Level | Purpose |
|
|
247
|
+
|---------|-------|---------|
|
|
248
|
+
| `x-lt-widget` | field | Rich control: `file-upload`, `code-editor`, `signature`, `rich-text`, `markdown` |
|
|
249
|
+
| `x-lt-language` | field | Syntax hint shown by the `code-editor` widget |
|
|
250
|
+
| `accept` | field | File-type filter for the `file-upload` widget (e.g. `".pdf,.png"`) |
|
|
251
|
+
| `x-lt-bind` | field | Path this field's value occupies in the resolver payload (e.g. `"customer.email"`) |
|
|
252
|
+
| `x-lt-span` | field | Column span in a `two-column` layout (`2` = full width) |
|
|
253
|
+
| `x-lt-order` | schema | Field render sequence |
|
|
254
|
+
| `x-lt-layout` | schema | `"two-column"` grid layout |
|
|
255
|
+
| `x-lt-help` | schema | Markdown guidance for the side panel's Help view; `{{domain.path}}` tokens interpolate live record values |
|
|
256
|
+
| `x-lt-context` | schema | Plain-text fallback for the Help view when `x-lt-help` is absent |
|
|
257
|
+
| `x-lt-viewport` | schema | Replace the generated form with a custom iframe UI |
|
|
258
|
+
| `format` | field | Input specialization: `password`, `date`, `date-time`, `email`, `uri`, `textarea` |
|
|
259
|
+
| `readOnly` | field | Static display (or a rendered content block with the `markdown` widget) |
|
|
260
|
+
| `required` | schema | Fields that must be filled before submit |
|
|
261
|
+
| `title` / `description` | both | Section header / helper text |
|
|
262
|
+
|
|
263
|
+
The working reference is `examples/workflows/rich-form/` — the `intake-reviewer` role's
|
|
264
|
+
versioned `form_schema` (seeded by `examples/seed-rich-form.ts`) exercises the whole
|
|
265
|
+
vocabulary in one form: side-panel help (`x-lt-help` with a checklist, table, tokens,
|
|
266
|
+
and a relative link), two-column layout, ordering, date and email formats, enum, file
|
|
267
|
+
upload, spans, required fields, and `x-lt-bind` mapping into a nested payload.
|
|
268
|
+
|
|
218
269
|
### Supported Field Types
|
|
219
270
|
|
|
220
271
|
| JSON Type | Renders As |
|
|
@@ -260,6 +311,7 @@ For rich inputs beyond standard HTML types:
|
|
|
260
311
|
| `"code-editor"` | Monospace textarea with tab-key support. Use `x-lt-language` for syntax hint. |
|
|
261
312
|
| `"signature"` | HTML5 Canvas drawing pad. Outputs PNG data URL. |
|
|
262
313
|
| `"rich-text"` | Tall textarea for formatted text input. |
|
|
314
|
+
| `"markdown"` | Markdown source, rendered with the same engine as the docs drawer (headings, tables, lists, code blocks, callouts). Editable fields get a Write/Preview toggle; with `readOnly: true` the field is a pure content block — see below. |
|
|
263
315
|
|
|
264
316
|
```json
|
|
265
317
|
{
|
|
@@ -285,6 +337,101 @@ For rich inputs beyond standard HTML types:
|
|
|
285
337
|
}
|
|
286
338
|
```
|
|
287
339
|
|
|
340
|
+
#### Markdown content blocks
|
|
341
|
+
|
|
342
|
+
`readOnly: true` + `x-lt-widget: "markdown"` turns a field into a rendered content
|
|
343
|
+
block: the markdown in its `default` displays as HTML inside the form — headings,
|
|
344
|
+
tables, checklists, callouts. The versioned schema carries the page source itself,
|
|
345
|
+
so review instructions and SOPs version with the form they belong to, and the
|
|
346
|
+
source rides along in the resolver payload like any read-only field.
|
|
347
|
+
|
|
348
|
+
```json
|
|
349
|
+
{
|
|
350
|
+
"properties": {
|
|
351
|
+
"review_guide": {
|
|
352
|
+
"type": "string",
|
|
353
|
+
"readOnly": true,
|
|
354
|
+
"x-lt-widget": "markdown",
|
|
355
|
+
"x-lt-span": 2,
|
|
356
|
+
"default": "### Review checklist\n\n1. Confirm the **legal name** matches.\n2. Send a test message before approving.\n\n> Escalate non-standard contract language to legal."
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Without `readOnly`, the field is a markdown *editor* — the resolver writes source in
|
|
363
|
+
a Write/Preview toggle and the submitted value is the markdown text.
|
|
364
|
+
|
|
365
|
+
### Help Panel (`x-lt-help`)
|
|
366
|
+
|
|
367
|
+
Schema-level `x-lt-help` carries the form's guidance — checklists, tier tables,
|
|
368
|
+
callouts, links — as markdown. The dashboard renders it in the side panel beside the
|
|
369
|
+
form, so the form itself stays a clean title and fields while the SOP sits one glance
|
|
370
|
+
to the right. The help versions with the form: it lives in the same `form_schema`
|
|
371
|
+
snapshot in `lt_role_schemas`.
|
|
372
|
+
|
|
373
|
+
```json
|
|
374
|
+
{
|
|
375
|
+
"title": "Customer Intake",
|
|
376
|
+
"x-lt-help": "### Review checklist\n\n1. Confirm the **legal name** matches.\n2. Send a test message before approving.\n\nThis escalation is **{{escalation.status}}** in the **{{escalation.role}}** queue.\n\n[Back to the queue](/escalations/queue?role=intake-reviewer)",
|
|
377
|
+
"properties": { ... }
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
`{{domain.path}}` tokens interpolate live values from the escalation surface using the
|
|
382
|
+
`x-lt-bind` path syntax (dot keys, optional `[n]` indices). Five domains are available:
|
|
383
|
+
|
|
384
|
+
| Domain | Resolves against |
|
|
385
|
+
|--------|------------------|
|
|
386
|
+
| `escalation` | The escalation row (`{{escalation.role}}`, `{{escalation.status}}`) |
|
|
387
|
+
| `metadata` | The row's metadata dict (`{{metadata.schema_version}}`) |
|
|
388
|
+
| `envelope` | The workflow-sent input envelope (`{{envelope.formDefaults.customer.name}}`) |
|
|
389
|
+
| `payload` | The escalation context payload (`{{payload.category}}`) |
|
|
390
|
+
| `resolver` | The submitted resolver payload (`{{resolver.notes}}`) |
|
|
391
|
+
|
|
392
|
+
A missing value renders as an em dash. Links whose href starts with `/` navigate
|
|
393
|
+
inside the dashboard.
|
|
394
|
+
|
|
395
|
+
The Help view falls back in order: `x-lt-help` → `x-lt-context` (plain text) → a
|
|
396
|
+
state-aware hint ("Claim this escalation to enable the form", "Fill out the form and
|
|
397
|
+
submit to resolve it", and so on), so the panel always tells the resolver what the
|
|
398
|
+
page expects of them. The panel's other views surface the record itself: **Metadata**
|
|
399
|
+
(the row's metadata values), **Context** (input envelope, escalation context, resolver
|
|
400
|
+
payload), and **Record** (the raw escalation JSON, builders only).
|
|
401
|
+
|
|
402
|
+
### Payload Binding (`x-lt-bind`)
|
|
403
|
+
|
|
404
|
+
The form is flat; the payload the workflow consumes rarely is. A field may declare
|
|
405
|
+
`x-lt-bind` — the path its value occupies in the resolver payload (dot keys, optional
|
|
406
|
+
`[n]` indices). The dashboard maps the flat form through the binds on submit, and
|
|
407
|
+
reverse-maps workflow-seeded `envelope.formDefaults` through them to prefill. A field
|
|
408
|
+
with no bind lands at its own name at the payload root (1:1).
|
|
409
|
+
|
|
410
|
+
```json
|
|
411
|
+
{
|
|
412
|
+
"properties": {
|
|
413
|
+
"customer_name": { "type": "string", "x-lt-bind": "customer.name" },
|
|
414
|
+
"contact_email": { "type": "string", "format": "email", "x-lt-bind": "customer.email" },
|
|
415
|
+
"tier": { "type": "string", "enum": ["starter", "professional"], "x-lt-bind": "contract.tier" },
|
|
416
|
+
"notes": { "type": "string", "format": "textarea" }
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
Submitting `{ customer_name, contact_email, tier, notes }` stores:
|
|
422
|
+
|
|
423
|
+
```json
|
|
424
|
+
{
|
|
425
|
+
"customer": { "name": "…", "email": "…" },
|
|
426
|
+
"contract": { "tier": "…" },
|
|
427
|
+
"notes": "…"
|
|
428
|
+
}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
Only the FORM is versioned on the role — the payload shape is the workflow's own
|
|
432
|
+
contract, produced by the binds. Evolve the form and its binds together, and the
|
|
433
|
+
workflow's resolver type in the same commit.
|
|
434
|
+
|
|
288
435
|
### Layout Options (`x-lt-layout`)
|
|
289
436
|
|
|
290
437
|
Control how fields are arranged:
|
|
@@ -349,8 +496,9 @@ Fields with `readOnly: true` display as static text. Useful for showing context
|
|
|
349
496
|
### Schema Title and Description
|
|
350
497
|
|
|
351
498
|
The `title` and `description` at the schema root are used in the UI:
|
|
352
|
-
- **`title`**: Shown as the section header
|
|
353
|
-
- **`description
|
|
499
|
+
- **`title`**: Shown as the form's section header
|
|
500
|
+
- **`description`**: Shown as helper text beneath the title — keep it to a short phrase; longer guidance belongs in `x-lt-help`
|
|
501
|
+
- **`x-lt-help`**: Rendered as markdown in the side panel beside the form
|
|
354
502
|
|
|
355
503
|
```json
|
|
356
504
|
{
|
|
@@ -469,27 +617,36 @@ Communication happens via `window.postMessage`.
|
|
|
469
617
|
|
|
470
618
|
---
|
|
471
619
|
|
|
472
|
-
##
|
|
620
|
+
## The Escalation Detail Page
|
|
473
621
|
|
|
474
|
-
The escalation detail page has
|
|
622
|
+
The escalation detail page has one view, built for the person resolving the item: the
|
|
623
|
+
escalation's description is the page title, the form starts directly beneath it, and
|
|
624
|
+
the action bar closes the page. The lifecycle sparkline (waiting / claimed / resolved
|
|
625
|
+
ratios) sits as a short persistent row above the side panel. Everything else lives in
|
|
626
|
+
the side panel, ordered by specificity:
|
|
475
627
|
|
|
476
|
-
|
|
|
477
|
-
|
|
478
|
-
| **
|
|
479
|
-
| **
|
|
480
|
-
| **
|
|
481
|
-
| **
|
|
628
|
+
| View | Shows | Available to |
|
|
629
|
+
|------|-------|--------------|
|
|
630
|
+
| **Help** | The form's `x-lt-help` markdown, or a state-aware hint | Everyone |
|
|
631
|
+
| **Details** | Status, role, priority, claim provenance, timestamps; identifier links below a divider | Everyone (identifiers: builders) |
|
|
632
|
+
| **AI Analysis** | What triage diagnosed and corrected | When AI is enabled and triage data is present |
|
|
633
|
+
| **Metadata** | The row's metadata values | Everyone |
|
|
634
|
+
| **Context** | Input envelope, escalation context, resolver payload | Everyone |
|
|
635
|
+
| **Record** | The raw escalation JSON | Builders (admins, superadmins, engineers) |
|
|
482
636
|
|
|
483
|
-
|
|
637
|
+
The page is two fixed-height columns beneath the global toolbar — the form column and
|
|
638
|
+
the panel each scroll independently, so the panel stays pinned like the left nav while
|
|
639
|
+
long forms or long panel content scroll. The form column narrows as the panel expands
|
|
640
|
+
(the panel is capped at half the page). When the form carries `x-lt-help`, the panel
|
|
641
|
+
opens expanded on the Help view; otherwise it stays hidden until the page-header panel
|
|
642
|
+
button summons it.
|
|
484
643
|
|
|
485
|
-
|
|
644
|
+
### Designing the Form
|
|
486
645
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
To create a polished user mode experience:
|
|
646
|
+
To create a polished resolve experience:
|
|
490
647
|
|
|
491
648
|
1. Set `title` on your schema — it replaces the section header
|
|
492
|
-
2. Set `
|
|
649
|
+
2. Set `x-lt-help` — checklists, tables, and links render as markdown in the side panel, with `{{domain.path}}` tokens for live record values; keep `description` to a short subtitle
|
|
493
650
|
3. Use `readOnly` fields for context the human needs to see but shouldn't edit
|
|
494
651
|
4. Use `x-lt-order` to put the most important fields first
|
|
495
652
|
5. Use `required` to guide users on what must be filled
|
|
@@ -497,6 +654,68 @@ To create a polished user mode experience:
|
|
|
497
654
|
|
|
498
655
|
---
|
|
499
656
|
|
|
657
|
+
## Escalations List Schema
|
|
658
|
+
|
|
659
|
+
The form schema formats one escalation on the detail page. A role can also own a
|
|
660
|
+
`list_schema` that formats its whole **list** page — the list-page analog of the
|
|
661
|
+
resolve form. It is opt-in and applies only when the list is scoped to exactly one
|
|
662
|
+
role (`/escalations/available?role=<role>`). Absent, the list renders the standard
|
|
663
|
+
engineer table; present, a rich role-authored view renders with a "Table view" toggle
|
|
664
|
+
one click away. It is versioned **independently** of the form schema (its own timeline;
|
|
665
|
+
a list edit never bumps the form version) and edited on its own page,
|
|
666
|
+
`/admin/roles/:role/list-schema`. The list always renders the latest version.
|
|
667
|
+
|
|
668
|
+
This is what turns a queue like a `policy-document` role — where a looped workflow
|
|
669
|
+
keeps exactly one escalation live and each resolved one is a revision — into a document
|
|
670
|
+
with a history, instead of a one-row table.
|
|
671
|
+
|
|
672
|
+
### Vocabulary
|
|
673
|
+
|
|
674
|
+
Every string is a markdown/text template run through the same `{{domain.path}}` token
|
|
675
|
+
binding as `x-lt-help` (domains `escalation | metadata | envelope | payload | resolver`,
|
|
676
|
+
evaluated against each row); `body` strings render through the markdown renderer.
|
|
677
|
+
|
|
678
|
+
| Key | Level | Purpose |
|
|
679
|
+
|-----|-------|---------|
|
|
680
|
+
| `x-lt-layout` | schema | `"active-history"` (two columns), `"active"` (card only), or `"table"` (fallback) |
|
|
681
|
+
| `x-lt-help` | schema | Optional markdown header, interpolated with the active row |
|
|
682
|
+
| `x-lt-active` | schema | The live item card: `{ title, subtitle?, body?, fields?: [{label, value}] }` |
|
|
683
|
+
| `x-lt-history` | schema | History column: `{ row: { title, subtitle?, meta? }, limit?, status? }` |
|
|
684
|
+
|
|
685
|
+
The **active** item is the first non-terminal escalation. The **history** column is not
|
|
686
|
+
auto-loaded — a "Load full history" link fetches resolved items on demand (`status`
|
|
687
|
+
defaults to `resolved`, `limit` to 25). Unknown/absent `x-lt-layout` is a safe no-op
|
|
688
|
+
that falls back to the table.
|
|
689
|
+
|
|
690
|
+
### Example — a policy-document role
|
|
691
|
+
|
|
692
|
+
```json
|
|
693
|
+
{
|
|
694
|
+
"x-lt-layout": "active-history",
|
|
695
|
+
"x-lt-help": "# {{metadata.title}}\nThe authoritative policy. One revision is live at a time.",
|
|
696
|
+
"x-lt-active": {
|
|
697
|
+
"title": "{{metadata.title}}",
|
|
698
|
+
"subtitle": "Revision {{metadata.revision}} · effective {{metadata.effective_date}}",
|
|
699
|
+
"body": "{{metadata.document_markdown}}",
|
|
700
|
+
"fields": [
|
|
701
|
+
{ "label": "Owner", "value": "{{metadata.owner}}" },
|
|
702
|
+
{ "label": "Claimed by", "value": "{{escalation.assigned_to}}" }
|
|
703
|
+
]
|
|
704
|
+
},
|
|
705
|
+
"x-lt-history": {
|
|
706
|
+
"row": { "title": "{{metadata.title}} — revision {{metadata.revision}}" },
|
|
707
|
+
"limit": 25
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
The working reference is `examples/workflows/policy-document/` (role seeded by
|
|
713
|
+
`examples/seed-policy-document.ts`): a looped workflow opens one policy-review
|
|
714
|
+
escalation, parks on it, and folds each resolution into the next revision — so the
|
|
715
|
+
policy facts ride the row's metadata and the list view reads them with `{{metadata.*}}`.
|
|
716
|
+
|
|
717
|
+
---
|
|
718
|
+
|
|
500
719
|
## Role-Based Routing
|
|
501
720
|
|
|
502
721
|
Escalations are routed by role. Users only see escalations for roles they hold.
|
|
@@ -782,10 +1001,10 @@ When you author a HITL-backed workflow, the platform handles:
|
|
|
782
1001
|
- **Claim/release** — soft-lock with TTL, prevents duplicate work
|
|
783
1002
|
- **Real-time updates** — NATS/Socket.IO events push changes to the dashboard instantly
|
|
784
1003
|
- **Form rendering** — JSON Schema to rich form controls, no frontend code needed
|
|
785
|
-
- **
|
|
1004
|
+
- **Side panel** — help, AI analysis, metadata, context, and raw-record views beside the form
|
|
786
1005
|
- **Section state persistence** — collapsed sections remembered across navigation
|
|
787
1006
|
- **Escalation chains** — users can re-route work to other roles
|
|
788
|
-
- **AI triage** — optional auto-resolution for common patterns
|
|
1007
|
+
- **AI triage** — optional auto-resolution for common patterns
|
|
789
1008
|
- **Signal routing** — 5 resolution paths (conditionLT, waitFor, triage, re-run, notification-only)
|
|
790
1009
|
- **Credential security** — password fields use ephemeral tokens, never stored in plain text
|
|
791
1010
|
- **Telemetry** — trace IDs link escalations to OpenTelemetry traces
|
package/docs/maintenance.md
CHANGED
|
@@ -28,6 +28,7 @@ await start({
|
|
|
28
28
|
{ target: 'jobs', olderThan: '14 days', action: 'delete', hasEntity: false },
|
|
29
29
|
{ target: 'jobs', olderThan: '14 days', action: 'prune', hasEntity: true },
|
|
30
30
|
{ target: 'jobs', olderThan: '180 days', action: 'delete', pruned: true },
|
|
31
|
+
{ target: 'escalations', olderThan: '180 days', action: 'delete' },
|
|
31
32
|
],
|
|
32
33
|
},
|
|
33
34
|
});
|
|
@@ -42,14 +43,15 @@ await start({
|
|
|
42
43
|
|
|
43
44
|
## What gets cleaned
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
Five categories of data are subject to maintenance:
|
|
46
47
|
|
|
47
48
|
| Category | Description |
|
|
48
49
|
|---|---|
|
|
49
|
-
| **Streams** |
|
|
50
|
+
| **Streams** | Stream messages used internally by HotMesh to coordinate activities. These are pure infrastructure; no user-facing data resides here. |
|
|
50
51
|
| **Transient jobs** | Job rows where the `entity` column is `NULL`. These represent activity executions, signal deliveries, and other bookkeeping that is not tied to a named workflow entity. They serve no purpose after execution completes. |
|
|
51
52
|
| **Entity jobs** | Job rows where `entity` is set. These represent actual workflow instances -- the rows that back `Durable.Client.workflow.search()` calls and execution exports. Deleting them removes the workflow record entirely. |
|
|
52
53
|
| **Pruned jobs** | Entity jobs that have already had their execution artifacts stripped (the `pruned_at` column is not `NULL`). These retain core data but no longer carry execution scaffolding. They can be hard-deleted after a longer retention window. |
|
|
54
|
+
| **Terminal escalations** | Escalation rows in a terminal status (`resolved`, `cancelled`, `expired`). Terminal rows are inert audit records -- every engine state transition guards on `status = 'pending'`, so aging them out is safe for live waiters, claims, and signal delivery. The engine-owned prune deletes in atomic batches until the retention horizon is drained. Pending rows are never touched. |
|
|
53
55
|
|
|
54
56
|
## Prune vs. delete
|
|
55
57
|
|
|
@@ -93,11 +95,12 @@ Defined in `types/maintenance.ts`. Each rule describes a single cleanup operatio
|
|
|
93
95
|
|
|
94
96
|
| Field | Type | Required | Description |
|
|
95
97
|
|---|---|---|---|
|
|
96
|
-
| `target` | `'streams' \| 'jobs'` | Yes | The resource type to act on. |
|
|
98
|
+
| `target` | `'streams' \| 'jobs' \| 'escalations'` | Yes | The resource type to act on. |
|
|
97
99
|
| `action` | `'delete' \| 'prune'` | Yes | Whether to remove entirely or strip execution artifacts. |
|
|
98
100
|
| `olderThan` | `string` | Yes | A PostgreSQL interval expression: `'7 days'`, `'24 hours'`, `'90 days'`. |
|
|
99
101
|
| `hasEntity` | `boolean` | No | When `target` is `'jobs'`: `true` selects entity jobs, `false` selects transient jobs (where `entity IS NULL`). |
|
|
100
102
|
| `pruned` | `boolean` | No | When `true`, only targets jobs where `pruned_at IS NOT NULL` -- jobs that have already been pruned. |
|
|
103
|
+
| `statuses` | `Array<'resolved' \| 'cancelled' \| 'expired'>` | No | When `target` is `'escalations'`: which terminal statuses to age out. Defaults to all three. |
|
|
101
104
|
|
|
102
105
|
### `LTMaintenanceConfig`
|
|
103
106
|
|
|
@@ -143,7 +143,7 @@ if (ctx) {
|
|
|
143
143
|
}
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
-
The MCP client (`callServerTool`) also reads `ToolContext` automatically. When no explicit `authContext` is passed, it derives `_auth` from the ambient context
|
|
146
|
+
The MCP client (`callServerTool`) also reads `ToolContext` automatically. When no explicit `authContext` is passed, it derives `_auth` from the ambient context — YAML workflow workers get auth propagation this way without any explicit wiring.
|
|
147
147
|
|
|
148
148
|
## Delegation Tokens
|
|
149
149
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hotmeshio/long-tail",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"build": "tsc --build tsconfig.json && cp -r lib/db/schemas build/lib/db/schemas",
|
|
26
26
|
"clean-build": "npm run clean && npm run build",
|
|
27
27
|
"start": "ts-node index.ts",
|
|
28
|
-
"start:dev": "ts-node-dev --respawn index.ts",
|
|
28
|
+
"start:dev": "ts-node-dev --respawn --transpile-only index.ts",
|
|
29
29
|
"migrate": "ts-node lib/db/migrate.ts",
|
|
30
30
|
"lint": "eslint . --ext .ts",
|
|
31
31
|
"lint:fix": "eslint . --fix --ext .ts",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"@anthropic-ai/sdk": "^0.92.0",
|
|
73
73
|
"@aws-sdk/client-s3": "^3.1017.0",
|
|
74
74
|
"@aws-sdk/s3-request-presigner": "^3.1045.0",
|
|
75
|
-
"@hotmeshio/hotmesh": "^0.
|
|
75
|
+
"@hotmeshio/hotmesh": "^0.26.1",
|
|
76
76
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
77
77
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.215.0",
|
|
78
78
|
"@opentelemetry/resources": "^2.5.1",
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{j as e,a as p}from"./vendor-query-B2UbickB.js";import{c as Ie,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-DwWP-Z_c.js";import{f as st}from"./useEventHooks-Dn_vN2xE.js";import{u as te,C as fe,a as at}from"./CustomDurationPicker-OKlwH5a_.js";import{u as nt}from"./roles-D4Wn7kE9.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-CqT9Q1I6.js";import{P as ct}from"./PageHeader-DJo7yMUR.js";import{P as dt}from"./constants-BHkpVaqx.js";import{M as se}from"./Modal-CSrxpXeM.js";import{u as ut}from"./users-DngGIiC_.js";import{E as xt,a as mt}from"./escalation-columns-Dyrf6Tdp.js";import{R as ht,a as gt}from"./RowActions-BA9L9djf.js";import{L as ft}from"./ListToolbar-Dz2_neVF.js";import{a4 as pt,S as bt,X as yt}from"./vendor-icons-DOIDKgo6.js";import"./EmptyState-BcsfPq9T.js";import"./FilterBar-B4Mk2PvT.js";import"./PriorityBadge-B4ykBH7f.js";import"./RolePill-DHWixsQR.js";import"./WorkflowPill-BtNBSplz.js";import"./escalation-CK8ElYzD.js";const F=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=F(t.get("facets"));A(o)||(s.facets=o);const c=F(t.get("block"));A(c)||(s.block=c);const x=F(t.get("range"));A(x)||(s.range=x);const f=F(t.get("exists"));A(f)||(s.exists=f);const h=F(t.get("roles"));A(h)||(s.roles=h);const l=F(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 T({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(T,{title:"Match id",hint:"id · workflow · origin",children:e.jsx("input",{className:`${P} w-full`,placeholder:"Exact escalation, workflow, or origin id…",value:c,onChange:a=>x(a.target.value)})}),e.jsx(T,{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(T,{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(T,{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(T,{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(T,{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,$=pe(k,250),{data:g,isLoading:_}=ut({role:y,status:"active",search:$.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 Mt({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 Ft(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 Tt({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=Ie(),{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,$]=$e(),g=p.useMemo(()=>vt(y),[y]),_=p.useCallback(d=>{$(j=>{const W=new URLSearchParams(j);return jt(W,d),W.delete("page"),W},{replace:!0})},[$]),{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(),D=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 L=s.status||"",I=L==="available",X=L==="claimed",re=X?"pending":L==="resolved"?"resolved":L==="cancelled"?"cancelled":L==="expired"?"expired":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:M,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=(M==null?void 0:M.escalations)??[],ce=(M==null?void 0:M.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:Me,handleBulkTriage:Fe,handleBulkAssign:Te,handleBulkCancel:Re}=Ft({selectedIds:a,clearSelection:Ae,setPriority:ne,bulkClaim:le,bulkEscalate:ie,bulkTriage:Y,bulkAssign:V,bulkCancel:D,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)))},Le=[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:"All 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.jsxs("p",{className:"mb-2 text-[11px] leading-snug text-text-tertiary",children:["Precise metadata facets plus exact correlation-id lookup — they compose in one SQL query. Facet keys are the ones that actually exist in your visible escalations. Set status to ",e.jsx("span",{className:"font-medium",children:"All"})," to find an order across every status; 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:Me,onTriage:()=>z(!0),onCancel:()=>Q(!0),isPriorityPending:ne.isPending,isClaimPending:le.isPending,isAssignPending:V.isPending,isEscalatePending:ie.isPending,isTriagePending:Y.isPending,isCancelPending:D.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:Le,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 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(Tt,{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(Mt,{open:q,onClose:()=>z(!1),selectedCount:a.size,onSubmit:Fe,isPending:Y.isPending}),e.jsx(Ot,{open:G,onClose:()=>m(!1),selectedCount:a.size,selectedRoles:we,onSubmit:Te,isPending:V.isPending}),e.jsx(at,{open:be,onClose:()=>Q(!1),onConfirm:Re,selectedCount:a.size,isPending:D.isPending,error:D.error})]})}export{is as AvailableEscalationsPage};
|
|
2
|
-
//# sourceMappingURL=AvailableEscalationsPage-DDwAgklw.js.map
|