@hotmeshio/long-tail 0.11.1 → 0.12.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/domain.d.ts +14 -0
- package/build/api/domain.js +76 -0
- package/build/api/escalations/cancel.js +16 -1
- package/build/api/escalations/helpers.js +5 -0
- package/build/lib/db/schemas/030_domain_dictionary.sql +18 -0
- package/build/lib/events/escalation-wire.d.ts +9 -0
- package/build/lib/events/escalation-wire.js +69 -0
- package/build/lib/events/system-events.js +13 -5
- package/build/lib/json-path/pick.d.ts +14 -0
- package/build/lib/json-path/pick.js +51 -0
- package/build/routes/domain.d.ts +2 -0
- package/build/routes/domain.js +62 -0
- package/build/routes/index.js +2 -0
- package/build/services/domain/index.d.ts +4 -0
- package/build/services/domain/index.js +14 -0
- package/build/services/domain/read.d.ts +21 -0
- package/build/services/domain/read.js +78 -0
- package/build/services/domain/seed.d.ts +11 -0
- package/build/services/domain/seed.js +65 -0
- package/build/services/domain/sql.d.ts +10 -0
- package/build/services/domain/sql.js +29 -0
- package/build/services/domain/validate.d.ts +29 -0
- package/build/services/domain/validate.js +50 -0
- package/build/services/domain/write.d.ts +23 -0
- package/build/services/domain/write.js +43 -0
- package/build/services/escalation/crud.js +16 -12
- package/build/services/mcp/db-server/schemas.d.ts +1 -1
- package/build/services/mcp/external-server.js +31 -1
- package/build/services/role/index.d.ts +2 -0
- package/build/services/role/index.js +7 -0
- package/build/services/role/sql.d.ts +1 -0
- package/build/services/role/sql.js +3 -1
- package/build/services/role/types.d.ts +17 -1
- package/build/services/role/types.js +16 -0
- package/build/start/workers.js +6 -0
- package/build/system/mcp-servers/admin/domain-context.d.ts +14 -0
- package/build/system/mcp-servers/admin/domain-context.js +220 -0
- package/build/system/mcp-servers/admin/exports.js +7 -4
- package/build/system/mcp-servers/admin/index.js +5 -3
- package/build/system/mcp-servers/admin/pipelines.js +9 -3
- package/build/system/mcp-servers/admin/schemas.d.ts +61 -32
- package/build/system/mcp-servers/admin/schemas.js +23 -5
- package/build/system/mcp-servers/admin/workflows.js +26 -0
- package/build/system/mcp-servers/db-query/schemas.d.ts +1 -1
- package/build/system/mcp-servers/human-queue-schemas.d.ts +1 -1
- package/build/system/seed/tool-manifests-admin.d.ts +286 -3
- package/build/system/seed/tool-manifests-admin.js +8 -5
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/domain-manifest.d.ts +77 -0
- package/build/types/domain-manifest.js +16 -0
- package/build/types/index.d.ts +2 -1
- package/build/types/index.js +2 -1
- package/build/types/startup.d.ts +10 -0
- package/dashboard/dist/assets/{AdminDashboard-D4ebrcNR.js → AdminDashboard-CahUELrr.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-D4ebrcNR.js.map → AdminDashboard-CahUELrr.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-DP4KUuCX.js → AgentConfigPage-CkMv-cTV.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-DP4KUuCX.js.map → AgentConfigPage-CkMv-cTV.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-ktYiR1kq.js → AgentDetailPage-ZGea3Z4A.js} +2 -2
- package/dashboard/dist/assets/{AgentDetailPage-ktYiR1kq.js.map → AgentDetailPage-ZGea3Z4A.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-B4iqm4-h.js → AgentsPage-BMWSUJGi.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-B4iqm4-h.js.map → AgentsPage-BMWSUJGi.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-tL3mM1RG.js → AvailableEscalationsPage-BjsbfsWW.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-tL3mM1RG.js.map → AvailableEscalationsPage-BjsbfsWW.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-CLrJuHnW.js → BotPicker-DN8tq7pz.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-CLrJuHnW.js.map → BotPicker-DN8tq7pz.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-DG5V0tMT.js → CapabilitiesPage-EAO3Ae0S.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-DG5V0tMT.js.map → CapabilitiesPage-EAO3Ae0S.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-CvLHvVfU.js → CollapsibleSection-J-RejbjG.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-CvLHvVfU.js.map → CollapsibleSection-J-RejbjG.js.map} +1 -1
- package/dashboard/dist/assets/{CountdownTimer-Co57-iLY.js → CountdownTimer-Dw8N9tmQ.js} +2 -2
- package/dashboard/dist/assets/{CountdownTimer-Co57-iLY.js.map → CountdownTimer-Dw8N9tmQ.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-qCJZ3rdi.js → CredentialsPage-CTurxwRn.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-qCJZ3rdi.js.map → CredentialsPage-CTurxwRn.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-C3iKifDN.js → CronLabel-DZ5TmIQG.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-C3iKifDN.js.map → CronLabel-DZ5TmIQG.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-C-Szl4rU.js → CustomDurationPicker-BES_FTrm.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-C-Szl4rU.js.map → CustomDurationPicker-BES_FTrm.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-CamZk5o1.js → ElapsedCell-CIGRporU.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-CamZk5o1.js.map → ElapsedCell-CIGRporU.js.map} +1 -1
- package/dashboard/dist/assets/EntityTimelinePanel-CKIFsDOB.js +2 -0
- package/dashboard/dist/assets/EntityTimelinePanel-CKIFsDOB.js.map +1 -0
- package/dashboard/dist/assets/{EscalationListSchemaPage-BddDSfjl.js → EscalationListSchemaPage-DOrv-quD.js} +2 -2
- package/dashboard/dist/assets/{EscalationListSchemaPage-BddDSfjl.js.map → EscalationListSchemaPage-DOrv-quD.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-BRyCtw9R.js → EscalationSchemaPage-DAOVAxAM.js} +2 -2
- package/dashboard/dist/assets/{EscalationSchemaPage-BRyCtw9R.js.map → EscalationSchemaPage-DAOVAxAM.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-DUWYxJyD.js → EscalationsOverview-B27sDn5O.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-DUWYxJyD.js.map → EscalationsOverview-B27sDn5O.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-CtVuCgq6.js → EventTable-Co1d40Qq.js} +2 -2
- package/dashboard/dist/assets/{EventTable-CtVuCgq6.js.map → EventTable-Co1d40Qq.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-BYsBgOiE.js → FilterBar-2ZfU21EA.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-BYsBgOiE.js.map → FilterBar-2ZfU21EA.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-CA4skPN2.js → GraphInvokePage-pdvc9VSv.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-CA4skPN2.js.map → GraphInvokePage-pdvc9VSv.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-DwG-AnjQ.js → HomePage-CLlDsBnw.js} +2 -2
- package/dashboard/dist/assets/{HomePage-DwG-AnjQ.js.map → HomePage-CLlDsBnw.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-D86IN_hQ.js → ListToolbar-DMremj2e.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-D86IN_hQ.js.map → ListToolbar-DMremj2e.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-CoEHGseD.js → McpOverview-BhztmhoL.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-CoEHGseD.js.map → McpOverview-BhztmhoL.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-C9hMgJe1.js → McpQueryDetailPage-BseZfrhc.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-C9hMgJe1.js.map → McpQueryDetailPage-BseZfrhc.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-B20Zn4QX.js → McpQueryPage-DMzkble7.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-B20Zn4QX.js.map → McpQueryPage-DMzkble7.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-DDKHf-3R.js → McpRunDetailPage-DqaBQAnn.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-DDKHf-3R.js.map → McpRunDetailPage-DqaBQAnn.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-Puyn3iJr.js → McpRunsPage-Du8GnHFv.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-Puyn3iJr.js.map → McpRunsPage-Du8GnHFv.js.map} +1 -1
- package/dashboard/dist/assets/OperationsPage-CL2feqwS.js +3 -0
- package/dashboard/dist/assets/OperationsPage-CL2feqwS.js.map +1 -0
- package/dashboard/dist/assets/{OperatorDashboard-CXBbFLAL.js → OperatorDashboard-BHiGQZN_.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-CXBbFLAL.js.map → OperatorDashboard-BHiGQZN_.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-BN5xNDDX.js → PersonaDetailPage-D6GGZgUS.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-BN5xNDDX.js.map → PersonaDetailPage-D6GGZgUS.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-Bdtv6HPZ.js → PersonasPage-BQYCdmAs.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-Bdtv6HPZ.js.map → PersonasPage-BQYCdmAs.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-BMg70ZAJ.js → ProcessDetailPage-P45jOLim.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-BMg70ZAJ.js.map → ProcessDetailPage-P45jOLim.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-_KvdxGhL.js → ProcessesListPage-CgdzgCY6.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-_KvdxGhL.js.map → ProcessesListPage-CgdzgCY6.js.map} +1 -1
- package/dashboard/dist/assets/{RoleDetailPage-BM5BXc7j.js → RoleDetailPage-Dme2pa9z.js} +2 -2
- package/dashboard/dist/assets/{RoleDetailPage-BM5BXc7j.js.map → RoleDetailPage-Dme2pa9z.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-Bv23VmUi.js → RolesPage-Ci7_PbPt.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-Bv23VmUi.js.map → RolesPage-Ci7_PbPt.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-D-Sjr7uB.js → RunAsSelector-CB0pV097.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-D-Sjr7uB.js.map → RunAsSelector-CB0pV097.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-s3OEMJno.js → ScanCodesPage-DpbPhAj1.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-s3OEMJno.js.map → ScanCodesPage-DpbPhAj1.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-D8WQkZmw.js → ScanSchemeDetailPage-CGnMGlt0.js} +2 -2
- package/dashboard/dist/assets/{ScanSchemeDetailPage-D8WQkZmw.js.map → ScanSchemeDetailPage-CGnMGlt0.js.map} +1 -1
- package/dashboard/dist/assets/{ScanStationPage-CkRQaH5G.js → ScanStationPage-BTeV7TGy.js} +2 -2
- package/dashboard/dist/assets/{ScanStationPage-CkRQaH5G.js.map → ScanStationPage-BTeV7TGy.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-BpTIMOL5.js → StickyPagination-DH-0JEyx.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-BpTIMOL5.js.map → StickyPagination-DH-0JEyx.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-ChoWrZzO.js → StreamMessageDetail-u-pDrHfS.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-ChoWrZzO.js.map → StreamMessageDetail-u-pDrHfS.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-nmIqEuEH.js → SwimlaneTimeline-vN1N8BGy.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-nmIqEuEH.js.map → SwimlaneTimeline-vN1N8BGy.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-KajZD2Cp.js → TaskDetailPage-CAQm6avs.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-KajZD2Cp.js.map → TaskDetailPage-CAQm6avs.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-CiqSfapP.js → TasksListPage-C1bT3DT9.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-CiqSfapP.js.map → TasksListPage-C1bT3DT9.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-ClauexJj.js → TimeAgo-qZxkJ8Am.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-ClauexJj.js.map → TimeAgo-qZxkJ8Am.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-CXmbCnAJ.js → TimestampCell-CC3dz6FG.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-CXmbCnAJ.js.map → TimestampCell-CC3dz6FG.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-DFUU0zGv.js → ToolTestPanel-C3sSQUvw.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-DFUU0zGv.js.map → ToolTestPanel-C3sSQUvw.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-DuN5BrsI.js → TopicDetailPage-ClI0I8Mu.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-DuN5BrsI.js.map → TopicDetailPage-ClI0I8Mu.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-DZ1NQdYG.js → TopicsPage-CNf2VZud.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-DZ1NQdYG.js.map → TopicsPage-CNf2VZud.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-BPHG_MQs.js → UserName-BdMHmyL3.js} +2 -2
- package/dashboard/dist/assets/{UserName-BPHG_MQs.js.map → UserName-BdMHmyL3.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-D_Z-tIjR.js → WorkflowExecutionPage-Ba4mYFoW.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-D_Z-tIjR.js.map → WorkflowExecutionPage-Ba4mYFoW.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-VMBW1WuR.js → WorkflowsDashboard-ImEm16tX.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-VMBW1WuR.js.map → WorkflowsDashboard-ImEm16tX.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-CUOXXcpg.js → WorkflowsOverview-BpWyV_tj.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-CUOXXcpg.js.map → WorkflowsOverview-BpWyV_tj.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CsfzbboC.js → YamlWorkflowDetailPage-BFBlw1YY.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CsfzbboC.js.map → YamlWorkflowDetailPage-BFBlw1YY.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-BpgKLSGT.js → YamlWorkflowsPage-C9gxapRg.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-BpgKLSGT.js.map → YamlWorkflowsPage-C9gxapRg.js.map} +1 -1
- package/dashboard/dist/assets/{agents-Cg2FVYQP.js → agents-BJQtJTiz.js} +2 -2
- package/dashboard/dist/assets/{agents-Cg2FVYQP.js.map → agents-BJQtJTiz.js.map} +1 -1
- package/dashboard/dist/assets/{bots-vtVLRKGt.js → bots-DDlU1gMy.js} +2 -2
- package/dashboard/dist/assets/{bots-vtVLRKGt.js.map → bots-DDlU1gMy.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-DLsXhwlD.js → capabilities-qYrUpdid.js} +2 -2
- package/dashboard/dist/assets/{capabilities-DLsXhwlD.js.map → capabilities-qYrUpdid.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-Js7dxpX4.js → controlplane-DnJ1VDTs.js} +2 -2
- package/dashboard/dist/assets/{controlplane-Js7dxpX4.js.map → controlplane-DnJ1VDTs.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-h0NLAJss.js → escalation-columns-BCnVWr_n.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-h0NLAJss.js.map → escalation-columns-BCnVWr_n.js.map} +1 -1
- package/dashboard/dist/assets/{index-DlO3bCfu.js → index-04QQsxMp.js} +2 -2
- package/dashboard/dist/assets/{index-DlO3bCfu.js.map → index-04QQsxMp.js.map} +1 -1
- package/dashboard/dist/assets/{index-Bcv5k8Dw.js → index-B5q8ksfv.js} +2 -2
- package/dashboard/dist/assets/{index-Bcv5k8Dw.js.map → index-B5q8ksfv.js.map} +1 -1
- package/dashboard/dist/assets/{index-FYQ9yPhO.js → index-BAqQSgxn.js} +2 -2
- package/dashboard/dist/assets/{index-FYQ9yPhO.js.map → index-BAqQSgxn.js.map} +1 -1
- package/dashboard/dist/assets/{index-7c7FEe5S.js → index-BHbO4F8Z.js} +2 -2
- package/dashboard/dist/assets/{index-7c7FEe5S.js.map → index-BHbO4F8Z.js.map} +1 -1
- package/dashboard/dist/assets/{index-KcaVfpWn.js → index-BUpB9ezn.js} +2 -2
- package/dashboard/dist/assets/{index-KcaVfpWn.js.map → index-BUpB9ezn.js.map} +1 -1
- package/dashboard/dist/assets/{index-CcjdA7jA.js → index-C991QfUN.js} +3 -3
- package/dashboard/dist/assets/{index-CcjdA7jA.js.map → index-C991QfUN.js.map} +1 -1
- package/dashboard/dist/assets/{index-BTzhV9ST.js → index-CFlmubaP.js} +2 -2
- package/dashboard/dist/assets/{index-BTzhV9ST.js.map → index-CFlmubaP.js.map} +1 -1
- package/dashboard/dist/assets/{index-BvVJ538E.js → index-CroJTX8g.js} +2 -2
- package/dashboard/dist/assets/{index-BvVJ538E.js.map → index-CroJTX8g.js.map} +1 -1
- package/dashboard/dist/assets/{index-BjfoWzJL.js → index-CtAPxA03.js} +2 -2
- package/dashboard/dist/assets/{index-BjfoWzJL.js.map → index-CtAPxA03.js.map} +1 -1
- package/dashboard/dist/assets/{index-DQi6CjqF.js → index-D-5F3Bw-.js} +2 -2
- package/dashboard/dist/assets/{index-DQi6CjqF.js.map → index-D-5F3Bw-.js.map} +1 -1
- package/dashboard/dist/assets/{index-DglcqBHn.js → index-DhRdWzz0.js} +2 -2
- package/dashboard/dist/assets/{index-DglcqBHn.js.map → index-DhRdWzz0.js.map} +1 -1
- package/dashboard/dist/assets/{index-vAkZ5dZe.js → index-KotwPxGB.js} +2 -2
- package/dashboard/dist/assets/{index-vAkZ5dZe.js.map → index-KotwPxGB.js.map} +1 -1
- package/dashboard/dist/assets/{index-CSpTj5DB.js → index-LiLVAQzB.js} +2 -2
- package/dashboard/dist/assets/{index-CSpTj5DB.js.map → index-LiLVAQzB.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-Bkvl3cIz.js → knowledge-CnMeg8Rw.js} +2 -2
- package/dashboard/dist/assets/{knowledge-Bkvl3cIz.js.map → knowledge-CnMeg8Rw.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-DEtDLeIQ.js → mcp-CHPSFv7m.js} +2 -2
- package/dashboard/dist/assets/{mcp-DEtDLeIQ.js.map → mcp-CHPSFv7m.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-BCRgnt0K.js → mcp-query-C19EGwdN.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-BCRgnt0K.js.map → mcp-query-C19EGwdN.js.map} +1 -1
- package/dashboard/dist/assets/{personas-CABKq-0L.js → personas-Br1Vo2S3.js} +2 -2
- package/dashboard/dist/assets/{personas-CABKq-0L.js.map → personas-Br1Vo2S3.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-fuN8dVNl.js → pipelines-QMrFoJZX.js} +2 -2
- package/dashboard/dist/assets/{pipelines-fuN8dVNl.js.map → pipelines-QMrFoJZX.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-u3YPNJBo.js → tasks-Doy_7cGX.js} +2 -2
- package/dashboard/dist/assets/{tasks-u3YPNJBo.js.map → tasks-Doy_7cGX.js.map} +1 -1
- package/dashboard/dist/assets/{topics-D37_RAIT.js → topics-BcJS4G09.js} +2 -2
- package/dashboard/dist/assets/{topics-D37_RAIT.js.map → topics-BcJS4G09.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-BbXfrFbq.js → useEventHooks-ldE5o0ok.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-BbXfrFbq.js.map → useEventHooks-ldE5o0ok.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-DvuoFTda.js → useNamespace-CCu8fZc6.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-DvuoFTda.js.map → useNamespace-CCu8fZc6.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-CL-Uf2cb.js → useYamlActivityEvents-DDrXwFXX.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-CL-Uf2cb.js.map → useYamlActivityEvents-DDrXwFXX.js.map} +1 -1
- package/dashboard/dist/assets/{users-CMxw_HzK.js → users-BvKhSq1i.js} +2 -2
- package/dashboard/dist/assets/{users-CMxw_HzK.js.map → users-BvKhSq1i.js.map} +1 -1
- package/dashboard/dist/assets/{workflows-Bez-o6fu.js → workflows-D09ysQF1.js} +2 -2
- package/dashboard/dist/assets/{workflows-Bez-o6fu.js.map → workflows-D09ysQF1.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-NrXcLsNm.js → yaml-workflows-BFHrxEl4.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-NrXcLsNm.js.map → yaml-workflows-BFHrxEl4.js.map} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/docs/domain-dictionary.md +115 -0
- package/docs/events.md +8 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/EntityTimelinePanel-CABCW2dS.js +0 -2
- package/dashboard/dist/assets/EntityTimelinePanel-CABCW2dS.js.map +0 -1
- package/dashboard/dist/assets/OperationsPage-Bsrt4XTL.js +0 -3
- package/dashboard/dist/assets/OperationsPage-Bsrt4XTL.js.map +0 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# The Domain Dictionary
|
|
2
|
+
|
|
3
|
+
Every deployment runs its own ontology on top of long-tail's primitives: the
|
|
4
|
+
operation speaks in printers, orders, batches, and resets, while the platform
|
|
5
|
+
speaks in roles, queues, workflows, escalations, and metadata facets. The domain
|
|
6
|
+
dictionary is where that translation is declared. An agent (or a teammate) that
|
|
7
|
+
knows the dictionary hears "printer PRN-001" and immediately knows the query —
|
|
8
|
+
the roles whose rows carry it, the facet that identifies it, `created_at desc`.
|
|
9
|
+
|
|
10
|
+
The dictionary lives in the database (`lt_domain`, one row per deployment). It
|
|
11
|
+
declares the **semantic overlay** — jargon terms, guidance, runbooks. Structure
|
|
12
|
+
is **derived** from the live registries when the dictionary is read: an entity's
|
|
13
|
+
id facet comes from its role's `entity_facet`, a role entry carries the live
|
|
14
|
+
row's title and verb semantics, a workflow entry carries the live config. The
|
|
15
|
+
merged view is always current.
|
|
16
|
+
|
|
17
|
+
## The shape
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"name": "acme print-farm",
|
|
22
|
+
"version": "1",
|
|
23
|
+
"overview": "One page: what this deployment runs.",
|
|
24
|
+
"terms": [
|
|
25
|
+
{
|
|
26
|
+
"term": "printer",
|
|
27
|
+
"aliases": ["machine"],
|
|
28
|
+
"kind": "entity",
|
|
29
|
+
"maps_to": { "roles": ["printer-fleet"] },
|
|
30
|
+
"guidance": "A machine on the floor, keyed by serialNumber. Find one with facets={serialNumber: value}."
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"term": "reset",
|
|
34
|
+
"kind": "action",
|
|
35
|
+
"maps_to": { "verb": "cancel", "role": "print-operator" },
|
|
36
|
+
"guidance": "Cancel the demand row — the dispatcher re-mints the attempt."
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"term": "the pipe",
|
|
40
|
+
"kind": "workflow",
|
|
41
|
+
"maps_to": { "workflow": "orderPipeline" },
|
|
42
|
+
"id_convention": "pipe-<orderId>",
|
|
43
|
+
"kill_road": "Terminate the pipe root with terminate_workflow; never cancel the demand row.",
|
|
44
|
+
"guidance": "One run per order."
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"term": "claims expire = recovery",
|
|
48
|
+
"kind": "rule",
|
|
49
|
+
"guidance": "A lapsed claim returns the row to the queue. Expiry is recovery, not an error."
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"runbooks": [
|
|
53
|
+
{ "name": "kill a test order", "steps": ["find the pipe root by id convention", "terminate_workflow on it"] }
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Term kinds: `entity` (a tracked noun; `idFacet` derives from the role's
|
|
59
|
+
`entity_facet`, declare it only to override), `role` (jargon for a queue),
|
|
60
|
+
`workflow` (carries `kill_road` and `id_convention`), `facet` (a metadata key's
|
|
61
|
+
meaning; `values` lists a closed domain), `action` (a domain verb mapped to a
|
|
62
|
+
platform verb), `rule` (a standing law, stated imperatively).
|
|
63
|
+
|
|
64
|
+
## Role verb semantics live on the role
|
|
65
|
+
|
|
66
|
+
What cancel or expiry MEANS for a row class is a property of the role itself.
|
|
67
|
+
Declare it under the reserved `lt_roles.properties` keys — editable with the
|
|
68
|
+
same `PATCH /api/roles/:role` that manages every other role dial:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{ "on_cancel": "reset — the dispatcher re-mints the attempt",
|
|
72
|
+
"on_timeout": "the gate re-parks and keeps listening",
|
|
73
|
+
"worked_by": "machines" }
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`cancel_escalation` returns the role's `on_cancel` alongside the receipt, and
|
|
77
|
+
`get_domain_context` merges all three into role entries.
|
|
78
|
+
|
|
79
|
+
## Registration and editing
|
|
80
|
+
|
|
81
|
+
Seed at boot by pointing the start config at a JSON file:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
mcp: { domainDictionaryPath: 'src/longtail/domain.json' }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Seeding is insert-if-absent: the DB row is runtime truth, and a name/version
|
|
88
|
+
mismatch between file and DB logs a drift warning. Edit live with
|
|
89
|
+
`PUT /api/domain` (admin) — the body is `{ doc, expected_version? }`;
|
|
90
|
+
`expected_version` arms optimistic concurrency (409 on conflict). Writes
|
|
91
|
+
validate references against the live registries: unknown roles and workflows
|
|
92
|
+
reject with 422 naming them; unknown facet keys warn (facets are discovered
|
|
93
|
+
from data and may simply have no rows yet). The boot seed applies the same
|
|
94
|
+
checks as warnings, so host seed ordering never blocks a boot.
|
|
95
|
+
|
|
96
|
+
## The derived floor
|
|
97
|
+
|
|
98
|
+
`get_domain_context` works on every deployment, dictionary or none. The live
|
|
99
|
+
registries already self-describe the structure — roles carry titles,
|
|
100
|
+
descriptions, `entity_facet`, and verb semantics; workflow configs carry
|
|
101
|
+
descriptions and invocability; facet keys are discovered from data. With no
|
|
102
|
+
dictionary registered the tool serves that derived view (entities are named by
|
|
103
|
+
their facet key, e.g. `serialNumber`, and roles sharing a facet form the
|
|
104
|
+
entity's system). A registered dictionary adds what only humans know: the
|
|
105
|
+
jargon nouns and aliases, guidance, kill roads, and runbooks.
|
|
106
|
+
|
|
107
|
+
## How agents consume it
|
|
108
|
+
|
|
109
|
+
- **MCP `instructions`** carry the overview plus a compact names-only index —
|
|
110
|
+
a session-sized breadcrumb pointing at the tool.
|
|
111
|
+
- **`get_domain_context`** (read-safe) returns the merged view: no args → the
|
|
112
|
+
index; `{ topic, name }` → specific entries, where `name` matches the term or
|
|
113
|
+
any alias case-insensitively and topic `term` searches every kind. Entries
|
|
114
|
+
referencing a since-removed role or workflow are annotated as dangling.
|
|
115
|
+
- **`GET /api/domain`** serves the raw document to dashboards and scripts.
|
package/docs/events.md
CHANGED
|
@@ -81,6 +81,14 @@ System families declare the fields they populate. Which fields exist is a functi
|
|
|
81
81
|
|
|
82
82
|
Escalation subjects carry the **role** (the queue) as the organizing token. Subscribe to one queue (`system.escalation.{role}.>`), one verb across queues (`system.escalation.*.*.created`), or one item across role hops (`system.escalation.*.{id}.>`). The role token is sanitized to subject-safe characters (`[A-Za-z0-9_-]`); a `reassigned` event publishes under **both** the departing and arriving role so either queue's subscribers observe the move.
|
|
83
83
|
|
|
84
|
+
#### Escalation `data` — one wire shape
|
|
85
|
+
|
|
86
|
+
A lifecycle event is a **notification**, not a transport. Its `data` is the **wire-safe projection** of the escalation row — routing/classification scalars plus the metadata **facets** — and never the heavy or sensitive JSON columns. Both publisher families (the service-mediated `crud.ts` path and the engine-mediated SDK hook) build `data` through one definition, `lib/events/escalation-wire.ts`, so the shape is identical regardless of who transitioned the row.
|
|
87
|
+
|
|
88
|
+
- **Kept:** the scalar columns (an allowlist) and every metadata facet (`orderId`, `serialNumber`, entity keys, `schema_version`, …) — the surface agent triggers filter/map on and the entity/faceted views route by. Verbs add their provenance alongside (`reason`, `released_by`, `resolved_by`, `from_role`/`to_role`).
|
|
89
|
+
- **Dropped:** `envelope`, `escalation_payload`, `resolver_payload`, and `metadata.form_schema`. A subscriber needing these fetches the row by id through the authenticated read API — the pub channel is not authenticated.
|
|
90
|
+
- **Bulk exception:** `publishBulk*` operate on many rows they don't hold in full; they publish the delta plus `bulk: true` (fetching each row to project would cost one query per row) and let subscribers fetch by id.
|
|
91
|
+
|
|
84
92
|
Consumers (adapters, the agent trigger registry, input_mapping) type against the broad **`LTEvent`** — the base plus every extension as **optional** — since they can't assume any extension is present. Producers (`lib/events/publish.ts`) construct the precise `LT*Event` family types, all assignable to `LTEvent`.
|
|
85
93
|
|
|
86
94
|
### Who mints it
|
package/package.json
CHANGED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a as o,u as P,j as t}from"./vendor-query-RUZdMvN6.js";import{a3 as $,g as D,H as Q,r as X,Q as R,aj as I}from"./index-CcjdA7jA.js";import{i as z}from"./useEventHooks-BbXfrFbq.js";import{X as Z,aT as V}from"./vendor-icons-Aw7bzBxa.js";function U(e){return JSON.stringify(e,(s,r)=>r&&typeof r=="object"&&!Array.isArray(r)?Object.fromEntries(Object.entries(r).sort(([n],[a])=>n<a?-1:1)):r)}function S(e,s=Date.now()){const r=Math.ceil(s/6e4)*6e4;return{from:new Date(r-e*36e5).toISOString(),to:new Date(r).toISOString()}}function H(e){const[s,r]=o.useState(()=>S(e));return o.useEffect(()=>{r(S(e));let n;const a=()=>{n=setTimeout(()=>{r(S(e)),a()},6e4-Date.now()%6e4+250)};return a(),()=>clearTimeout(n)},[e]),s}function J(e,s){return s instanceof $&&s.status===403?!1:e<2}function _(e,s){return P({queryKey:["escAggregate",e?U(e):"off"],queryFn:()=>D("/escalations/aggregate-by-facets",{method:"POST",body:JSON.stringify(e)}),staleTime:15e3,enabled:((s==null?void 0:s.enabled)??!0)&&!!e,retry:J})}function W(e){return D("/escalations/timeline-by-facet",{method:"POST",body:JSON.stringify(e)})}function ee(e,s){return P({queryKey:["escTimeline",e?U(e):"off"],queryFn:()=>W(e),staleTime:15e3,enabled:!!e,retry:J})}function te(e){return e instanceof $&&e.status===403}const F=["rgb(var(--lt-status-queued-graphic))","rgb(var(--lt-status-claimed-graphic))","rgb(var(--lt-status-success-graphic))","rgb(var(--lt-status-pending-graphic))","rgb(var(--lt-status-error))","rgb(var(--lt-accent))"],se="∅",re="no subtype";function ae(e){return e??se}function me(e){return e??re}function T(e){const s=new Map;for(const a of e)s.set(a.label,(s.get(a.label)??0)+a.weight);const r=[...s.entries()].sort(([a,c],[u,l])=>l-c||(a<u?-1:1)),n=new Map;return r.forEach(([a],c)=>n.set(a,F[c%F.length])),n}function fe(e){return T(e.map(s=>({label:ae(s.subtype),weight:s.dwellSeconds??s.count??0})))}function ne(e,{enabled:s=!0,periodHours:r=720}={}){const n=H(r),a=e.entity?{entity:e.entity}:e.role?{roles:[e.role]}:null,c=s&&!!a,u=_(c?{query:a,groupBy:{state:!0},measure:{kind:"dwell",window:n},orderBy:[{field:"dwellSeconds",direction:"desc"}]}:null),l=_(c?{query:a,groupBy:{state:!0},measure:{kind:"membership"}}:null),{data:x}=Q({enabled:c}),h=o.useMemo(()=>new Set(((x==null?void 0:x.roles)??[]).filter(i=>i.entity_state_source==="subtype").map(i=>i.role)),[x]),b=o.useMemo(()=>{var i,p;return T([...(((i=u.data)==null?void 0:i.groups)??[]).filter(f=>(f.dwellSeconds??0)>0),...((p=l.data)==null?void 0:p.groups)??[]].map(f=>({label:f.state??"—",weight:f.dwellSeconds??f.count??0})))},[u.data,l.data]);return o.useCallback(i=>{const p=h.has(i.role)?i.subtype??i.role:i.role;return b.get(p)},[b,h])}const k=e=>e.subtype??e.role,M=100;function pe({facetKey:e,value:s,role:r,entity:n,intervalColor:a}){var O,B;z();const{closePanel:c}=X(),u=n?{query:{entity:n}}:r?{query:{roles:[r]}}:{},{data:l,error:x,isLoading:h}=ee({facet:{key:e,value:s},...u,order:"desc",limit:M}),b=ne({entity:n,role:r},{enabled:!a}),i=a??b,p=[...(l==null?void 0:l.intervals)??[]].reverse(),[f,v]=o.useState([]),[A,C]=o.useState(!1),[j,q]=o.useState(!1),[w,N]=o.useState(null),E=l?`${s}|${l.intervals.length}|${((O=l.intervals[0])==null?void 0:O.startedAt)??""}|${((B=l.intervals[l.intervals.length-1])==null?void 0:B.startedAt)??""}`:null,L=o.useRef(null);o.useEffect(()=>{E!==L.current&&(L.current=E,v([]),C((l==null?void 0:l.overflow)??!1),N(null))},[E,l]);const m=[...f,...p],Y=T(m.map(d=>({label:k(d),weight:d.durationSeconds}))),G=async()=>{var y;const d=(y=m[0])==null?void 0:y.startedAt;if(!(!d||j)){q(!0),N(null);try{const g=await W({facet:{key:e,value:s},...u,order:"desc",before:d,limit:M});v(K=>[...[...g.intervals].reverse(),...K]),C(g.overflow)}catch(g){N(g.message)}finally{q(!1)}}};return t.jsxs("div",{className:"h-full flex flex-col",children:[t.jsxs("div",{className:"flex items-start justify-between px-5 pt-5 pb-3 border-b border-surface-border/40",children:[t.jsxs("div",{className:"min-w-0",children:[t.jsxs("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary",children:["Timeline · ",t.jsx("span",{className:"normal-case font-mono",children:e})]}),t.jsx("p",{className:"text-sm font-mono text-text-primary truncate mt-0.5",title:s,children:s}),m.length>0&&t.jsxs("p",{className:"text-2xs text-text-quaternary mt-0.5",children:[m.length," interval",m.length===1?"":"s"]})]}),t.jsxs("span",{className:"flex items-center gap-1 mt-0.5 shrink-0 ml-2",children:[n&&t.jsx(le,{entity:n,value:s}),t.jsx("button",{onClick:()=>c("entity-timeline"),className:"icon-link",children:t.jsx(Z,{className:"w-4 h-4"})})]})]}),t.jsx("div",{className:"flex-1 overflow-y-auto px-5 py-4",children:h?t.jsx("p",{className:"text-2xs text-text-tertiary italic",children:"Loading timeline…"}):te(x)?t.jsx("p",{className:"text-2xs text-text-tertiary",children:"Timeline requires full read access to this station's queue."}):x?t.jsx("p",{className:"text-2xs text-status-error",children:x.message}):m.length===0?t.jsx("p",{className:"text-2xs text-text-quaternary",children:"No escalation has carried this value."}):t.jsxs("div",{className:"relative",children:[(A||w)&&t.jsxs("div",{className:"pb-2 pl-5",children:[A&&t.jsx("button",{onClick:G,disabled:j,className:"text-2xs text-text-tertiary hover:text-accent transition-colors disabled:opacity-40",children:j?"Loading earlier…":"Load earlier"}),w&&t.jsx("p",{className:"text-2xs text-status-error mt-1",children:w})]}),t.jsx("div",{className:"absolute left-[4px] top-2 bottom-2 w-px bg-surface-border"}),t.jsx("div",{className:"space-y-0",children:m.map((d,y)=>t.jsxs(o.Fragment,{children:[y>0&&t.jsx(ie,{prev:m[y-1],next:d}),t.jsx(oe,{interval:d,color:i(d)??Y.get(k(d))})]},`${d.startedAt}-${y}`))})]})})]})}function le({entity:e,value:s}){const[r,n]=o.useState(!1),a=o.useRef(void 0);o.useEffect(()=>()=>clearTimeout(a.current),[]);const c=async()=>{const u=`${window.location.origin}/operations?lens=${encodeURIComponent(e)}&entity=${encodeURIComponent(s)}`;await navigator.clipboard.writeText(u),n(!0),clearTimeout(a.current),a.current=setTimeout(()=>n(!1),1500)};return t.jsxs("span",{className:"flex items-center gap-1",children:[r&&t.jsx("span",{className:"text-2xs text-text-quaternary",children:"copied"}),t.jsx("button",{onClick:c,className:"icon-link",title:"Copy link to this timeline",children:t.jsx(V,{className:"w-3.5 h-3.5"})})]})}function oe({interval:e,color:s}){return t.jsxs("div",{className:"relative flex gap-3 py-2",children:[t.jsx("span",{className:"w-[9px] h-[9px] rounded-full shrink-0 mt-1 relative z-10",style:{backgroundColor:s??"rgb(var(--lt-surface-border))"},title:k(e)}),t.jsxs("div",{className:"min-w-0 flex-1",children:[t.jsxs("div",{className:"flex items-baseline gap-2",children:[t.jsxs("span",{className:"text-xs font-mono text-text-primary truncate",children:[e.role,e.subtype?t.jsxs("span",{className:"text-text-tertiary",children:[" · ",e.subtype]}):null]}),t.jsx("span",{className:"text-2xs font-mono tabular-nums text-text-secondary ml-auto shrink-0",children:R(e.durationSeconds*1e3)})]}),t.jsxs("p",{className:"text-2xs font-mono text-text-tertiary mt-0.5",children:[I(e.startedAt)," → ",e.endedAt?I(e.endedAt):"now"]})]})]})}function ie({prev:e,next:s}){if(!e.endedAt)return null;const r=Date.parse(s.startedAt)-Date.parse(e.endedAt);return r<=1e3?null:t.jsxs("div",{className:"relative flex items-center gap-3 py-1",children:[t.jsx("span",{className:"w-[9px] shrink-0"}),t.jsx("div",{className:"flex-1 border-t border-dashed border-surface-border/60"}),t.jsxs("span",{className:"text-2xs text-text-quaternary shrink-0",children:["untracked · ",R(r)]}),t.jsx("div",{className:"flex-1 border-t border-dashed border-surface-border/60"})]})}export{pe as E,ae as a,H as b,T as c,fe as d,te as i,me as s,_ as u};
|
|
2
|
-
//# sourceMappingURL=EntityTimelinePanel-CABCW2dS.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EntityTimelinePanel-CABCW2dS.js","sources":["../../src/api/escalation-analytics.ts","../../src/pages/operations/mix-colors.ts","../../src/pages/operations/useEntityStateColors.ts","../../src/components/escalation/EntityTimelinePanel.tsx"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Escalation analytics hooks — grouped membership/dwell aggregates and\n// per-entity interval timelines (POST /escalations/aggregate-by-facets and\n// /timeline-by-facet). Every escalation is one open interval\n// [created_at, ended_at); these hooks read that time-series.\n//\n// Query-key discipline: inputs are canonicalized (key-sorted stringify) and\n// windows are quantized to the minute — the window end rounds UP to the next\n// minute boundary so (a) keys stay stable across renders within the minute\n// and (b) `to >= now` keeps the query in the server's now-anchored cache\n// (invalidated on escalation writes) instead of the 10-minute past cache.\n// Refresh is push-driven (useEscalationAnalyticsEvents) — never polling.\n// ---------------------------------------------------------------------------\n\nimport { useEffect, useState } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { apiFetch, ApiError } from './client';\n\n// Wire types — mirrors of types/analytics.ts on the server.\n\nexport interface AnalyticsWindow {\n from: string;\n to: string;\n}\n\nexport type AggregateMeasure =\n | { kind: 'membership'; asOf?: string }\n | { kind: 'dwell'; window: AnalyticsWindow };\n\nexport interface AnalyticsFilter {\n role?: string;\n roles?: string[];\n /** Entity facet key — resolves server-side to every role declaring it (the entity's system). */\n entity?: string;\n facets?: Record<string, unknown>;\n /** Case-insensitive facet-value prefix match, keyed by facet. */\n prefix?: Record<string, string>;\n /**\n * Exact facet-value match via the text projection (metadata->>key = value),\n * keyed by facet. Compares as text, so a categorical value the aggregate\n * returned (bool/enum/number, all surfaced as text) round-trips as a filter.\n */\n equals?: Record<string, string>;\n block?: Record<string, unknown>[];\n /** Row carries ANY of these facet sets (max 200) — the positive mirror of block. */\n anyOf?: Record<string, unknown>[];\n range?: { facet: string; op: '<' | '<=' | '>' | '>=' | '='; value: number }[];\n exists?: string[];\n}\n\nexport interface AggregateByFacetsInput {\n query: AnalyticsFilter;\n groupBy: { columns?: ('role' | 'subtype' | 'status')[]; facets?: string[]; state?: boolean };\n measure: AggregateMeasure;\n distinctBy?: string;\n orderBy?: { field: string; direction?: 'asc' | 'desc' }[];\n limit?: number;\n offset?: number;\n}\n\nexport interface AggregateRow {\n role?: string;\n subtype?: string | null;\n status?: string;\n facets: Record<string, string | null>;\n state?: string;\n count?: number;\n dwellSeconds?: number;\n sampleCount: number;\n}\n\nexport interface AggregateByFacetsResult {\n groups: AggregateRow[];\n overflow: boolean;\n}\n\nexport interface TimelineByFacetInput {\n facet: { key: string; value: string };\n query?: AnalyticsFilter;\n window?: AnalyticsWindow;\n select?: { columns?: ('role' | 'subtype' | 'status')[]; facets?: string[] };\n /** Interval order by startedAt (default asc). */\n order?: 'asc' | 'desc';\n /** Strict startedAt upper bound — the \"load earlier\" cursor. */\n before?: string;\n limit?: number;\n}\n\nexport interface TimelineInterval {\n role: string;\n subtype?: string | null;\n status?: string;\n facets: Record<string, string | null>;\n startedAt: string;\n endedAt: string | null;\n durationSeconds: number;\n}\n\nexport interface TimelineByFacetResult {\n intervals: TimelineInterval[];\n overflow: boolean;\n}\n\n// ── Key + window helpers (exported for tests) ────────────────────────────────\n\n/** Key-order-independent stringify so `{a,b}` and `{b,a}` share one query key. */\nexport function canonicalStringify(value: unknown): string {\n return JSON.stringify(value, (_key, v) =>\n v && typeof v === 'object' && !Array.isArray(v)\n ? Object.fromEntries(Object.entries(v).sort(([a], [b]) => (a < b ? -1 : 1)))\n : v,\n );\n}\n\n/** The trailing window for a period: `to` = next minute boundary, `from` = to − hours. */\nexport function analyticsWindow(periodHours: number, now = Date.now()): AnalyticsWindow {\n const to = Math.ceil(now / 60_000) * 60_000;\n return {\n from: new Date(to - periodHours * 3_600_000).toISOString(),\n to: new Date(to).toISOString(),\n };\n}\n\n/**\n * A live trailing window that rolls forward on the minute. Without the tick a\n * quiet tab's `to` falls into the past and the server reclassifies the query\n * fully-past (10-minute cache) — a \"live\" board frozen for 10 minutes.\n */\nexport function useAnalyticsWindow(periodHours: number): AnalyticsWindow {\n const [window, setWindow] = useState(() => analyticsWindow(periodHours));\n useEffect(() => {\n setWindow(analyticsWindow(periodHours));\n let timer: ReturnType<typeof setTimeout>;\n const schedule = () => {\n // Fire just past the minute boundary so ceil() lands on the NEXT one.\n timer = setTimeout(() => {\n setWindow(analyticsWindow(periodHours));\n schedule();\n }, 60_000 - (Date.now() % 60_000) + 250);\n };\n schedule();\n return () => clearTimeout(timer);\n }, [periodHours]);\n return window;\n}\n\n/** 403 is a scope answer, not a transient fault — never retry it. */\nfunction retryUnlessForbidden(failureCount: number, error: unknown): boolean {\n if (error instanceof ApiError && error.status === 403) return false;\n return failureCount < 2;\n}\n\n// ── Hooks ─────────────────────────────────────────────────────────────────────\n\nexport function useAggregateByFacets(\n input: AggregateByFacetsInput | null,\n opts?: { enabled?: boolean },\n) {\n return useQuery<AggregateByFacetsResult>({\n queryKey: ['escAggregate', input ? canonicalStringify(input) : 'off'],\n queryFn: () =>\n apiFetch('/escalations/aggregate-by-facets', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n staleTime: 15_000,\n enabled: (opts?.enabled ?? true) && !!input,\n retry: retryUnlessForbidden,\n });\n}\n\n/** One-shot timeline fetch — cursor pages (\"load earlier\") outside the query cache. */\nexport function fetchTimelineByFacet(input: TimelineByFacetInput): Promise<TimelineByFacetResult> {\n return apiFetch('/escalations/timeline-by-facet', {\n method: 'POST',\n body: JSON.stringify(input),\n });\n}\n\nexport function useTimelineByFacet(\n input: TimelineByFacetInput | null,\n opts?: { enabled?: boolean },\n) {\n return useQuery<TimelineByFacetResult>({\n queryKey: ['escTimeline', input ? canonicalStringify(input) : 'off'],\n queryFn: () => fetchTimelineByFacet(input!),\n staleTime: 15_000,\n enabled: (opts?.enabled ?? true) && !!input,\n retry: retryUnlessForbidden,\n });\n}\n\n/** True when the query failed the analytics read gate (render the scope notice). */\nexport function isForbidden(error: unknown): boolean {\n return error instanceof ApiError && error.status === 403;\n}\n","// ---------------------------------------------------------------------------\n// State-mix color assignment — a small ordered palette of the -graphic status\n// tokens (chart-grade contrast) assigned to subtypes by dwell rank. The null\n// subtype is a REAL group (rows created without one): it gets a key, a color,\n// and a label — dropping it would misstate the total tracked time.\n// ---------------------------------------------------------------------------\n\nexport const MIX_PALETTE = [\n 'rgb(var(--lt-status-queued-graphic))', // sky\n 'rgb(var(--lt-status-claimed-graphic))', // orange\n 'rgb(var(--lt-status-success-graphic))', // green\n 'rgb(var(--lt-status-pending-graphic))', // amber\n 'rgb(var(--lt-status-error))', // red\n 'rgb(var(--lt-accent))',\n] as const;\n\nexport const NO_SUBTYPE_KEY = '∅';\nexport const NO_SUBTYPE_LABEL = 'no subtype';\n\n/** Map key for a subtype group (null/undefined collapse to the ∅ group). */\nexport function subtypeKey(subtype: string | null | undefined): string {\n return subtype ?? NO_SUBTYPE_KEY;\n}\n\nexport function subtypeLabel(subtype: string | null | undefined): string {\n return subtype ?? NO_SUBTYPE_LABEL;\n}\n\n/**\n * Stable ordered assignment over arbitrary labels: sorted by total weight\n * descending (alphabetical tiebreak so equal ranks never swap), palette\n * wrapping beyond its length. Deterministic for a given entry set.\n */\nexport function assignLabelColors(\n entries: Array<{ label: string; weight: number }>,\n): Map<string, string> {\n const totals = new Map<string, number>();\n for (const e of entries) totals.set(e.label, (totals.get(e.label) ?? 0) + e.weight);\n const ranked = [...totals.entries()].sort(\n ([ak, av], [bk, bv]) => bv - av || (ak < bk ? -1 : 1),\n );\n const colors = new Map<string, string>();\n ranked.forEach(([key], i) => colors.set(key, MIX_PALETTE[i % MIX_PALETTE.length]));\n return colors;\n}\n\n/** The subtype-keyed form used by the station MIX surfaces. */\nexport function assignMixColors(\n groups: { subtype?: string | null; dwellSeconds?: number; count?: number }[],\n): Map<string, string> {\n return assignLabelColors(\n groups.map((g) => ({ label: subtypeKey(g.subtype), weight: g.dwellSeconds ?? g.count ?? 0 })),\n );\n}\n","import { useCallback, useMemo } from 'react';\nimport {\n useAggregateByFacets,\n useAnalyticsWindow,\n type TimelineInterval,\n} from '../../api/escalation-analytics';\nimport { useRoleDetails } from '../../api/roles';\nimport { assignLabelColors } from './mix-colors';\n\n/**\n * A category-color resolver for an entity system's timeline intervals — the\n * same palette the entity-lens band uses, so a timeline opened anywhere (the\n * lens, the station detail panel, an escalation cell popover) colors its dots\n * by state identically. Each interval's state is derived exactly as the server\n * does (subtype-sourced roles → COALESCE(subtype, role), everyone else → role),\n * then mapped through colors assigned over the system's state dwell.\n *\n * A stable reference window (not the user's selected period) keeps the color\n * assignment consistent across contexts. Pass `enabled: false` when the opener\n * already supplies its own resolver, so this does no redundant fetching.\n */\nexport function useEntityStateColors(\n scope: { entity?: string; role?: string },\n { enabled = true, periodHours = 720 }: { enabled?: boolean; periodHours?: number } = {},\n): (interval: TimelineInterval) => string | undefined {\n const window = useAnalyticsWindow(periodHours);\n const query = scope.entity\n ? { entity: scope.entity }\n : scope.role\n ? { roles: [scope.role] }\n : null;\n const active = enabled && !!query;\n\n const dwell = useAggregateByFacets(\n active\n ? {\n query: query!,\n groupBy: { state: true },\n measure: { kind: 'dwell', window },\n orderBy: [{ field: 'dwellSeconds', direction: 'desc' }],\n }\n : null,\n );\n const now = useAggregateByFacets(\n active ? { query: query!, groupBy: { state: true }, measure: { kind: 'membership' } } : null,\n );\n const { data: roleData } = useRoleDetails({ enabled: active });\n\n const subtypeSourced = useMemo(\n () =>\n new Set(\n (roleData?.roles ?? [])\n .filter((r) => r.entity_state_source === 'subtype')\n .map((r) => r.role),\n ),\n [roleData],\n );\n const colors = useMemo(\n () =>\n assignLabelColors(\n [\n ...(dwell.data?.groups ?? []).filter((g) => (g.dwellSeconds ?? 0) > 0),\n ...(now.data?.groups ?? []),\n ].map((g) => ({ label: g.state ?? '—', weight: g.dwellSeconds ?? g.count ?? 0 })),\n ),\n [dwell.data, now.data],\n );\n\n return useCallback(\n (interval: TimelineInterval) => {\n const state = subtypeSourced.has(interval.role)\n ? (interval.subtype ?? interval.role)\n : interval.role;\n return colors.get(state);\n },\n [colors, subtypeSourced],\n );\n}\n","import { Fragment, useEffect, useRef, useState } from 'react';\nimport { X, Link as LinkIcon } from 'lucide-react';\nimport {\n useTimelineByFacet,\n fetchTimelineByFacet,\n isForbidden,\n type AnalyticsFilter,\n type TimelineInterval,\n} from '../../api/escalation-analytics';\nimport { useEscalationAnalyticsEvents } from '../../hooks/useEventHooks';\nimport { useShellPanel } from '../../hooks/useShellPanel';\nimport { formatDateTime, formatDurationCompact } from '../../lib/format';\nimport { assignLabelColors } from '../../pages/operations/mix-colors';\nimport { useEntityStateColors } from '../../pages/operations/useEntityStateColors';\n\n/** The category a row belongs to — its state within the process (subtype),\n * falling back to the role. This is the axis the timeline graphic colors by,\n * NOT the escalation lifecycle (resolved/expired) which would be near-uniform\n * across a mostly-completed history. */\nconst categoryOf = (iv: TimelineInterval): string => iv.subtype ?? iv.role;\n\n// Newest page size — the head query and every \"load earlier\" page.\nconst TIMELINE_PAGE_SIZE = 100;\n\n/**\n * One entity's escalation-interval timeline — every station the facet value\n * has moved through, as [started, ended) spans rendered chronologically. Gaps\n * between consecutive intervals are untracked time and render as explicit\n * separators: their size is the digital/physical settle latency, a health\n * signal, never hidden.\n *\n * The head query fetches the NEWEST page (order desc) so push-driven\n * invalidation keeps the recent end fresh; older pages accumulate locally via\n * the \"Load earlier\" cursor (`before` = oldest loaded startedAt) and reset\n * whenever the head page changes.\n *\n * Rendered in the global shell right panel (key 'entity-timeline'). Passing\n * `role` keeps the query inside the pond gate for read_all members; without\n * it the query is cross-role and needs a global principal — a 403 degrades to\n * a quiet scope notice.\n */\nexport function EntityTimelinePanel({\n facetKey,\n value,\n role,\n entity,\n intervalColor,\n}: {\n facetKey: string;\n value: string;\n role?: string;\n /** Scope to the derived entity system (every role declaring this entity facet). */\n entity?: string;\n /**\n * Optional color resolver from the opener (the entity lens): maps an interval\n * to the EXACT color the timeline graphic uses for its category, so the list\n * and the band agree. Absent (standalone opens), the panel colors from its\n * own intervals — consistent, but not cross-component identical.\n */\n intervalColor?: (interval: TimelineInterval) => string | undefined;\n}) {\n useEscalationAnalyticsEvents();\n const { closePanel } = useShellPanel();\n const scope: { query?: AnalyticsFilter } = entity\n ? { query: { entity } }\n : role\n ? { query: { roles: [role] } }\n : {};\n const { data, error, isLoading } = useTimelineByFacet({\n facet: { key: facetKey, value },\n ...scope,\n order: 'desc',\n limit: TIMELINE_PAGE_SIZE,\n });\n\n // Color resolution: the opener's resolver (the lens, period-matched to its\n // band) wins; otherwise derive the entity system's colors here so station\n // detail and cell popovers color by the same scheme. When a resolver is\n // supplied, the fallback does no fetching.\n const systemColor = useEntityStateColors({ entity, role }, { enabled: !intervalColor });\n const resolveColor = intervalColor ?? systemColor;\n\n // Head page, chronological. Older pages prepend before it.\n const headIntervals = [...(data?.intervals ?? [])].reverse();\n const [older, setOlder] = useState<TimelineInterval[]>([]);\n const [hasEarlier, setHasEarlier] = useState(false);\n const [loadingEarlier, setLoadingEarlier] = useState(false);\n const [earlierError, setEarlierError] = useState<string | null>(null);\n\n // Reset accumulated pages when the newest interval set changes — a new facet\n // value, or a push-driven head refetch that shifted the recent end.\n const headSignature = data\n ? `${value}|${data.intervals.length}|${data.intervals[0]?.startedAt ?? ''}|${data.intervals[data.intervals.length - 1]?.startedAt ?? ''}`\n : null;\n const appliedSignature = useRef<string | null>(null);\n useEffect(() => {\n if (headSignature === appliedSignature.current) return;\n appliedSignature.current = headSignature;\n setOlder([]);\n setHasEarlier(data?.overflow ?? false);\n setEarlierError(null);\n }, [headSignature, data]);\n\n const intervals = [...older, ...headIntervals];\n\n // Category colors — the same palette generator the timeline graphic uses,\n // keyed by each row's category and weighted by dwell so the dominant states\n // take the lead palette slots. The dot reads as \"what this was,\" matching the\n // band segments on the left.\n const categoryColors = assignLabelColors(\n intervals.map((iv) => ({ label: categoryOf(iv), weight: iv.durationSeconds })),\n );\n\n const loadEarlier = async () => {\n const oldest = intervals[0]?.startedAt;\n if (!oldest || loadingEarlier) return;\n setLoadingEarlier(true);\n setEarlierError(null);\n try {\n const page = await fetchTimelineByFacet({\n facet: { key: facetKey, value },\n ...scope,\n order: 'desc',\n before: oldest,\n limit: TIMELINE_PAGE_SIZE,\n });\n setOlder((prev) => [...[...page.intervals].reverse(), ...prev]);\n setHasEarlier(page.overflow);\n } catch (err) {\n setEarlierError((err as Error).message);\n } finally {\n setLoadingEarlier(false);\n }\n };\n\n return (\n <div className=\"h-full flex flex-col\">\n <div className=\"flex items-start justify-between px-5 pt-5 pb-3 border-b border-surface-border/40\">\n <div className=\"min-w-0\">\n <p className=\"text-2xs font-semibold uppercase tracking-widest text-text-tertiary\">\n Timeline · <span className=\"normal-case font-mono\">{facetKey}</span>\n </p>\n <p className=\"text-sm font-mono text-text-primary truncate mt-0.5\" title={value}>\n {value}\n </p>\n {intervals.length > 0 && (\n <p className=\"text-2xs text-text-quaternary mt-0.5\">\n {intervals.length} interval{intervals.length === 1 ? '' : 's'}\n </p>\n )}\n </div>\n <span className=\"flex items-center gap-1 mt-0.5 shrink-0 ml-2\">\n {entity && <CopyLinkButton entity={entity} value={value} />}\n <button onClick={() => closePanel('entity-timeline')} className=\"icon-link\">\n <X className=\"w-4 h-4\" />\n </button>\n </span>\n </div>\n\n <div className=\"flex-1 overflow-y-auto px-5 py-4\">\n {isLoading ? (\n <p className=\"text-2xs text-text-tertiary italic\">Loading timeline…</p>\n ) : isForbidden(error) ? (\n <p className=\"text-2xs text-text-tertiary\">\n Timeline requires full read access to this station's queue.\n </p>\n ) : error ? (\n <p className=\"text-2xs text-status-error\">{(error as Error).message}</p>\n ) : intervals.length === 0 ? (\n <p className=\"text-2xs text-text-quaternary\">\n No escalation has carried this value.\n </p>\n ) : (\n <div className=\"relative\">\n {(hasEarlier || earlierError) && (\n <div className=\"pb-2 pl-5\">\n {hasEarlier && (\n <button\n onClick={loadEarlier}\n disabled={loadingEarlier}\n className=\"text-2xs text-text-tertiary hover:text-accent transition-colors disabled:opacity-40\"\n >\n {loadingEarlier ? 'Loading earlier…' : 'Load earlier'}\n </button>\n )}\n {earlierError && <p className=\"text-2xs text-status-error mt-1\">{earlierError}</p>}\n </div>\n )}\n {/* Left rail behind the dots */}\n <div className=\"absolute left-[4px] top-2 bottom-2 w-px bg-surface-border\" />\n <div className=\"space-y-0\">\n {intervals.map((interval, i) => (\n <Fragment key={`${interval.startedAt}-${i}`}>\n {i > 0 && <GapRow prev={intervals[i - 1]} next={interval} />}\n <IntervalRow\n interval={interval}\n color={resolveColor(interval) ?? categoryColors.get(categoryOf(interval))}\n />\n </Fragment>\n ))}\n </div>\n </div>\n )}\n </div>\n </div>\n );\n}\n\n/** Copies the entity-lens deep link (?lens= + ?entity=) with a transient note. */\nfunction CopyLinkButton({ entity, value }: { entity: string; value: string }) {\n const [copied, setCopied] = useState(false);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n useEffect(() => () => clearTimeout(timer.current), []);\n\n const copy = async () => {\n const url = `${window.location.origin}/operations?lens=${encodeURIComponent(entity)}&entity=${encodeURIComponent(value)}`;\n await navigator.clipboard.writeText(url);\n setCopied(true);\n clearTimeout(timer.current);\n timer.current = setTimeout(() => setCopied(false), 1500);\n };\n\n return (\n <span className=\"flex items-center gap-1\">\n {copied && <span className=\"text-2xs text-text-quaternary\">copied</span>}\n <button onClick={copy} className=\"icon-link\" title=\"Copy link to this timeline\">\n <LinkIcon className=\"w-3.5 h-3.5\" />\n </button>\n </span>\n );\n}\n\nfunction IntervalRow({ interval, color }: { interval: TimelineInterval; color?: string }) {\n return (\n <div className=\"relative flex gap-3 py-2\">\n {/* Filled dot in the row's CATEGORY color — matches the graphic's segments,\n so the list reads by state the same way the band does. */}\n <span\n className=\"w-[9px] h-[9px] rounded-full shrink-0 mt-1 relative z-10\"\n style={{ backgroundColor: color ?? 'rgb(var(--lt-surface-border))' }}\n title={categoryOf(interval)}\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-baseline gap-2\">\n <span className=\"text-xs font-mono text-text-primary truncate\">\n {interval.role}\n {interval.subtype ? <span className=\"text-text-tertiary\"> · {interval.subtype}</span> : null}\n </span>\n <span className=\"text-2xs font-mono tabular-nums text-text-secondary ml-auto shrink-0\">\n {formatDurationCompact(interval.durationSeconds * 1000)}\n </span>\n </div>\n <p className=\"text-2xs font-mono text-text-tertiary mt-0.5\">\n {formatDateTime(interval.startedAt)} → {interval.endedAt ? formatDateTime(interval.endedAt) : 'now'}\n </p>\n </div>\n </div>\n );\n}\n\n/** Untracked time between two intervals — the settle latency between queues, surfaced. */\nfunction GapRow({ prev, next }: { prev: TimelineInterval; next: TimelineInterval }) {\n if (!prev.endedAt) return null;\n const gapMs = Date.parse(next.startedAt) - Date.parse(prev.endedAt);\n if (gapMs <= 1000) return null; // contiguous handoff\n return (\n <div className=\"relative flex items-center gap-3 py-1\">\n <span className=\"w-[9px] shrink-0\" />\n <div className=\"flex-1 border-t border-dashed border-surface-border/60\" />\n <span className=\"text-2xs text-text-quaternary shrink-0\">\n untracked · {formatDurationCompact(gapMs)}\n </span>\n <div className=\"flex-1 border-t border-dashed border-surface-border/60\" />\n </div>\n );\n}\n"],"names":["canonicalStringify","value","_key","v","a","b","analyticsWindow","periodHours","now","to","useAnalyticsWindow","window","setWindow","useState","useEffect","timer","schedule","retryUnlessForbidden","failureCount","error","ApiError","useAggregateByFacets","input","opts","useQuery","apiFetch","fetchTimelineByFacet","useTimelineByFacet","isForbidden","MIX_PALETTE","NO_SUBTYPE_KEY","NO_SUBTYPE_LABEL","subtypeKey","subtype","subtypeLabel","assignLabelColors","entries","totals","e","ranked","ak","av","bk","bv","colors","key","i","assignMixColors","groups","g","useEntityStateColors","scope","enabled","query","active","dwell","roleData","useRoleDetails","subtypeSourced","useMemo","r","_a","_b","useCallback","interval","state","categoryOf","iv","TIMELINE_PAGE_SIZE","EntityTimelinePanel","facetKey","role","entity","intervalColor","useEscalationAnalyticsEvents","closePanel","useShellPanel","data","isLoading","systemColor","resolveColor","headIntervals","older","setOlder","hasEarlier","setHasEarlier","loadingEarlier","setLoadingEarlier","earlierError","setEarlierError","headSignature","appliedSignature","useRef","intervals","categoryColors","loadEarlier","oldest","page","prev","err","jsxs","jsx","CopyLinkButton","X","Fragment","GapRow","IntervalRow","copied","setCopied","copy","url","LinkIcon","color","formatDateTime","next","gapMs","formatDurationCompact"],"mappings":"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"}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{a as h,j as e}from"./vendor-query-RUZdMvN6.js";import{Q as te,V as tt,K as we,o as kt,ax as st,H as $t,aa as St,x as qt}from"./index-CcjdA7jA.js";import{j as Mt,i as Ct}from"./useEventHooks-BbXfrFbq.js";import{s as Le,a as he,u as B,b as Ue,E as Te,c as nt,i as Ee,d as at}from"./EntityTimelinePanel-CABCW2dS.js";import{ap as _t,aX as Rt,as as rt,C as Pt,s as ze,ax as Lt,b as Et,X as Ot,aw as At,aS as Bt,aY as Ft,E as It,a0 as Tt,an as ot}from"./vendor-icons-Aw7bzBxa.js";import{P as Wt}from"./PageHeader-B7YJxa4o.js";import{f as lt,L as le,u as Dt}from"./vendor-react-CdqEC2zv.js";function Ut({groups:t,colors:s}){const r=h.useMemo(()=>{const a=(t??[]).filter(n=>(n.dwellSeconds??0)>0),c=a.reduce((n,o)=>n+(o.dwellSeconds??0),0);return c?a.map(n=>({key:he(n.subtype),label:Le(n.subtype),seconds:n.dwellSeconds??0,pct:(n.dwellSeconds??0)/c})).sort((n,o)=>o.seconds-n.seconds):null},[t]);if(!r)return e.jsx("span",{className:"text-2xs text-text-quaternary",children:"—"});const i=r.map(a=>`${a.label} ${te(a.seconds*1e3)} · ${Math.round(a.pct*100)}%`).join(`
|
|
2
|
-
`);return e.jsxs("div",{className:"flex items-center gap-1.5",title:i,children:[e.jsx("div",{className:"w-16 h-1.5 bg-surface-sunken rounded-full overflow-hidden flex shrink-0",children:r.map(a=>e.jsx("div",{style:{width:`${a.pct*100}%`,backgroundColor:s.get(a.key)}},a.key))}),e.jsxs("span",{className:"text-2xs font-mono text-text-quaternary tabular-nums",children:[Math.round(r[0].pct*100),"%"]})]})}function Oe(t){return t.reduce((s,r)=>s+(r.dwellSeconds??0),0)||1}function it(t,s){const r=[];for(const i of t){const a=i.facets[s];a==null||(i.dwellSeconds??0)<=0||r.push(a)}return r}function ct(t,s,r,i){const a=new Map;for(const o of s){const d=o.facets[i];if(d==null||(o.dwellSeconds??0)<=0)continue;const x=a.get(d)??[];x.push(o),a.set(d,x)}const c=new Map;for(const o of r){const d=o.facets[i];d==null||(o.count??0)<=0||o.state==null||c.has(d)||c.set(d,o.state)}const n=[];for(const o of t){const d=o.facets[i];if(d==null||(o.dwellSeconds??0)<=0)continue;const x=[...a.get(d)??[]].sort((p,w)=>(w.dwellSeconds??0)-(p.dwellSeconds??0));n.push({value:d,groups:x,total:o.dwellSeconds??0,nowState:c.get(d)??null})}return n}function zt(t,s,r=12){const i=new Map;for(const a of t){if((a.dwellSeconds??0)<=0)continue;const c=a.facets[s]??"no value",n=i.get(c)??[];n.push(a),i.set(c,n)}return[...i.entries()].map(([a,c])=>({value:a,groups:[...c].sort((n,o)=>(o.dwellSeconds??0)-(n.dwellSeconds??0)),total:Oe(c)})).sort((a,c)=>c.total-a.total).slice(0,r)}function Ae({groups:t,colors:s,height:r,className:i=""}){const a=Oe(t),c=new Map([...s.keys()].map((o,d)=>[o,d])),n=[...t].sort((o,d)=>(c.get(o.state??"—")??1/0)-(c.get(d.state??"—")??1/0));return e.jsx("div",{className:`${r} flex rounded-full overflow-hidden bg-surface-sunken ${i}`,children:n.map(o=>e.jsx("div",{title:`${o.state??"—"} · ${te((o.dwellSeconds??0)*1e3)}`,style:{width:`${(o.dwellSeconds??0)/a*100}%`,backgroundColor:s.get(o.state??"—")}},o.state??"—"))})}function dt({text:t,tail:s=6,className:r=""}){if(t.length<=s+1)return e.jsx("span",{className:`truncate ${r}`,title:t,children:t});const i=t.slice(0,t.length-s),a=t.slice(t.length-s);return e.jsxs("span",{className:`flex items-baseline min-w-0 ${r}`,title:t,children:[e.jsx("span",{className:"truncate min-w-0",children:i}),e.jsx("span",{className:"shrink-0",children:a})]})}const Ve=15,xt="grid grid-cols-[0.6rem_7rem_minmax(2rem,1fr)_1rem] items-center gap-2.5",Ht=[25,50,100],Gt=50;function Vt({row:t,colors:s,stateLabel:r,onOpen:i}){return e.jsxs("div",{role:"button",tabIndex:0,onClick:()=>i(t.value),onKeyDown:a=>{a.key==="Enter"&&i(t.value)},className:`${xt} text-2xs cursor-pointer group py-0.5`,children:[e.jsx("span",{className:"w-2 h-2 rounded-full dot-ring justify-self-center",style:{backgroundColor:t.nowState?s.get(t.nowState):"transparent"},title:t.nowState?r(t.nowState):"no current state"}),e.jsx(dt,{text:t.value,className:"font-mono text-text-secondary group-hover:text-accent transition-colors"}),e.jsx(Ae,{groups:t.groups,colors:s,height:"h-1.5",className:"min-w-[2rem]"}),e.jsx("button",{className:"icon-link justify-self-center",title:`${te(t.total*1e3)} tracked · open timeline`,onClick:a=>{a.stopPropagation(),i(t.value)},children:e.jsx(rt,{className:"w-3 h-3"})})]})}function ut({sliced:t,header:s,rows:r,colors:i,stateLabel:a,onOpen:c,onTarget:n,hasMore:o,emptyText:d}){return e.jsxs("div",{className:t?"w-72 shrink-0":"flex-1 max-w-3xl",children:[s&&e.jsxs("button",{type:"button",onClick:()=>n==null?void 0:n(s.value),className:`${xt} w-full text-left mb-2 group`,children:[e.jsx("span",{"aria-hidden":!0}),e.jsx(dt,{text:s.value,className:"font-mono text-xs font-medium text-text-primary group-hover:text-accent transition-colors"}),e.jsx(Ae,{groups:s.groups,colors:i,height:"h-2.5",className:"min-w-[2rem]"}),e.jsx("span",{className:"icon-link justify-self-center",title:`${te(s.total*1e3)} total in ${s.value} — the band shows the state split`,children:e.jsx(_t,{className:"w-3 h-3"})})]}),r.length===0?e.jsx("p",{className:"text-2xs text-text-quaternary",children:d??"No entities on this page."}):e.jsx("div",{className:"space-y-0.5",children:r.map(x=>e.jsx(Vt,{row:x,colors:i,stateLabel:a,onOpen:c},x.value))}),o&&s&&n&&e.jsxs("button",{type:"button",onClick:()=>n(s.value),className:"mt-2 inline-flex items-center gap-1 text-2xs text-accent hover:text-accent-hover transition-colors",children:["More ",e.jsx(Rt,{className:"w-3 h-3"})]})]})}function Yt({entityKey:t,sliceKey:s,value:r,headerGroups:i,headerTotal:a,window:c,find:n,colors:o,stateLabel:d,onOpen:x,onTarget:p}){var M;const w={entity:t,equals:{[s]:r}},j=B({query:{...w,...n?{prefix:{[t]:n}}:{}},groupBy:{facets:[t]},measure:{kind:"dwell",window:c},orderBy:[{field:"dwellSeconds",direction:"desc"}],limit:Ve}),f=h.useMemo(()=>{var b;return it(((b=j.data)==null?void 0:b.groups)??[],t)},[j.data,t]),q=f.map(b=>({[t]:b})),k=B(f.length?{query:{entity:t,anyOf:q},groupBy:{state:!0,facets:[t]},measure:{kind:"dwell",window:c},limit:Ve*4}:null),R=B(f.length?{query:{entity:t,anyOf:q},groupBy:{state:!0,facets:[t]},measure:{kind:"membership"}}:null),$=h.useMemo(()=>{var b,F,P;return ct(((b=j.data)==null?void 0:b.groups)??[],((F=k.data)==null?void 0:F.groups)??[],((P=R.data)==null?void 0:P.groups)??[],t)},[j.data,k.data,R.data,t]);return e.jsx(ut,{sliced:!0,header:{value:r,groups:i,total:a},rows:$,colors:o,stateLabel:d,onOpen:x,onTarget:p,hasMore:((M=j.data)==null?void 0:M.overflow)??!1})}function Qt({rows:t,colors:s,stateLabel:r,onOpen:i,emptyText:a}){return e.jsx(ut,{sliced:!1,rows:t,colors:s,stateLabel:r,onOpen:i,emptyText:a})}const qe="entity-timeline",Xt=300,Fe=12;function Zt({entityKey:t,periodHours:s,roles:r,find:i,onFindChange:a,entityValue:c,onEntityChange:n,sliceKey:o=null,onSliceKeyChange:d,sliceValue:x=null,onSliceValueChange:p}){var pe,$e,Se,K,Ge;const w=Ue(s),j=tt(),f=o??"",q=!!f,k=q&&!!x,R=q&&!x,[$,M]=h.useState(0),[b,F]=h.useState(Gt);h.useEffect(()=>{M(0)},[i,w.from,w.to,t,f,x,b]);const[P,v]=h.useState(i??""),L=h.useRef(void 0);h.useEffect(()=>()=>clearTimeout(L.current),[]),h.useEffect(()=>{v(i??"")},[i]);const V=m=>{v(m),clearTimeout(L.current),L.current=setTimeout(()=>{const E=m.trim();a(E||null)},Xt)},g=h.useMemo(()=>{const m=new Map;for(const E of r)m.set(E.role,we(E));return m},[r]),C=m=>m==null?"—":g.get(m)??m,z=B({query:{entity:t},groupBy:{state:!0},measure:{kind:"dwell",window:w},orderBy:[{field:"dwellSeconds",direction:"desc"}]}),H=B({query:{entity:t},groupBy:{state:!0},measure:{kind:"membership"}}),fe=B({query:{entity:t},groupBy:{},measure:{kind:"membership"},distinctBy:t}),T=B(q?{query:{entity:t},groupBy:{state:!0,facets:[f]},measure:{kind:"dwell",window:w},limit:200}:null),_=B(!R?{query:{entity:t,...k?{equals:{[f]:x}}:{},...i?{prefix:{[t]:i}}:{}},groupBy:{facets:[t]},measure:{kind:"dwell",window:w},orderBy:[{field:"dwellSeconds",direction:"desc"}],limit:b,offset:$*b}:null),se=h.useMemo(()=>{var m;return it(((m=_==null?void 0:_.data)==null?void 0:m.groups)??[],t)},[_==null?void 0:_.data,t]),X=se.length?{entity:t,anyOf:se.map(m=>({[t]:m}))}:null,xe=B(X?{query:X,groupBy:{state:!0,facets:[t]},measure:{kind:"dwell",window:w},limit:b*10}:null),ne=B(X?{query:X,groupBy:{state:!0,facets:[t]},measure:{kind:"membership"}}:null),ue=h.useMemo(()=>{var m,E,re;return ct(((m=_==null?void 0:_.data)==null?void 0:m.groups)??[],((E=xe.data)==null?void 0:E.groups)??[],((re=ne.data)==null?void 0:re.groups)??[],t)},[_==null?void 0:_.data,xe.data,ne.data,t]),Y=h.useRef(()=>{}),l=h.useRef(m=>Y.current(m)).current,S=h.useRef(null),O=h.useRef(!1);h.useEffect(()=>{j&&c!==S.current&&(S.current=c,c?j.setPanel(e.jsx(Te,{facetKey:t,value:c,entity:t,intervalColor:l}),{key:qe,width:420}):(O.current=!1,j.closePanel(qe)))},[c,t,j]),h.useEffect(()=>{if(!(!j||!c)){if(j.open&&j.ownerKey===qe){O.current=!0;return}O.current&&(O.current=!1,n(null))}},[j,c,n]);const U=h.useRef(j);U.current=j,h.useEffect(()=>()=>{var m;S.current&&((m=U.current)==null||m.closePanel(qe))},[]);const{data:A}=kt(),Z=h.useMemo(()=>((A==null?void 0:A.keys)??[]).filter(m=>m!==t),[A,t]),W=(((pe=z.data)==null?void 0:pe.groups)??[]).filter(m=>(m.dwellSeconds??0)>0),D=h.useMemo(()=>{var m;return nt([...W,...((m=H.data)==null?void 0:m.groups)??[]].map(E=>({label:E.state??"—",weight:E.dwellSeconds??E.count??0})))},[W,H.data]),J=new Map(((($e=H.data)==null?void 0:$e.groups)??[]).map(m=>[m.state??"—",m.count??0])),me=((K=(Se=fe.data)==null?void 0:Se.groups[0])==null?void 0:K.count)??null,ye=h.useMemo(()=>new Set(r.filter(m=>m.entity_state_source==="subtype").map(m=>m.role)),[r]);Y.current=m=>{const E=ye.has(m.role)?m.subtype??m.role:m.role;return D.get(E)};const ae=h.useMemo(()=>{var m;return q?zt(((m=T.data)==null?void 0:m.groups)??[],f,Fe):[]},[q,T.data,f]),Q=h.useMemo(()=>{var E;const m=new Set;for(const re of((E=T.data)==null?void 0:E.groups)??[])(re.dwellSeconds??0)>0&&re.facets[f]!=null&&m.add(re.facets[f]);return m.size},[T.data,f]),ke=h.useMemo(()=>{var E;if(!k)return{groups:[],total:0};const m=(((E=T.data)==null?void 0:E.groups)??[]).filter(re=>re.facets[f]===x);return{groups:m,total:Oe(m)}},[k,T.data,f,x]),u=((Ge=_==null?void 0:_.data)==null?void 0:Ge.overflow)??!1,N=Ee(_==null?void 0:_.error),y=q&&Ee(T.error);return e.jsxs("div",{className:"flex-1 min-h-0 flex flex-col overflow-hidden",children:[e.jsxs("div",{className:"shrink-0 px-2 pt-4 pb-3 flex items-start gap-6 border-b border-surface-border/40",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-baseline justify-between gap-4 mb-2.5",children:[e.jsxs("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary",children:["Where the time went · ",e.jsx("span",{className:"normal-case font-mono",children:t})," system"]}),me!=null&&e.jsxs("p",{className:"text-2xs text-text-quaternary whitespace-nowrap",children:[e.jsx("span",{className:"text-xs font-mono font-semibold text-text-primary tabular-nums",children:me})," ",e.jsx("span",{className:"font-mono",children:t})," in queue now"]})]}),W.length>0?e.jsxs(e.Fragment,{children:[e.jsx(Ae,{groups:W,colors:D,height:"h-3"}),e.jsx("div",{className:"flex flex-wrap gap-x-6 gap-y-1 mt-2.5",children:W.map(m=>e.jsxs("span",{className:"flex items-center gap-1.5 text-2xs",children:[e.jsx("span",{className:"w-2 h-2 rounded-full shrink-0",style:{backgroundColor:D.get(m.state??"—")}}),e.jsx("span",{className:"font-mono text-text-secondary",children:C(m.state)}),e.jsx("span",{className:"font-mono tabular-nums text-text-tertiary",children:te((m.dwellSeconds??0)*1e3)}),e.jsxs("span",{className:"font-mono tabular-nums text-text-quaternary",children:[Math.round((m.dwellSeconds??0)/Oe(W)*100),"%"]}),(J.get(m.state??"—")??0)>0&&e.jsxs("span",{className:"text-text-quaternary",children:["· ",J.get(m.state??"—")," now"]})]},m.state))})]}):e.jsx("p",{className:"text-2xs text-text-quaternary",children:"No tracked time in this window."})]}),e.jsxs("div",{className:"shrink-0 w-56 space-y-2.5",children:[e.jsxs("label",{className:"block",children:[e.jsx("span",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Slice by"}),e.jsxs("select",{value:f,onChange:m=>d==null?void 0:d(m.target.value||null),className:"select text-xs font-mono w-full",children:[e.jsx("option",{value:"",children:"— none —"}),Z.map(m=>e.jsx("option",{value:m,children:m},m))]})]}),e.jsx("input",{type:"text",value:P,onChange:m=>V(m.target.value),placeholder:`Find by ${t}…`,"aria-label":`Find by ${t}`,className:"w-full bg-transparent border-b border-surface-border/60 focus:border-accent focus:outline-none text-xs font-mono text-text-primary placeholder:text-text-quaternary pb-0.5 transition-colors"})]})]}),k&&e.jsxs("div",{className:"shrink-0 px-2 pt-3 flex items-center gap-3",children:[e.jsxs("button",{type:"button",onClick:()=>p==null?void 0:p(null),className:"inline-flex items-center gap-1 text-2xs text-accent hover:text-accent-hover transition-colors shrink-0",children:[e.jsx(Pt,{className:"w-3 h-3"})," all ",f]}),e.jsx("span",{className:"font-mono text-xs text-text-primary shrink-0",children:x}),e.jsx(Ae,{groups:ke.groups,colors:D,height:"h-2",className:"flex-1 max-w-md"}),e.jsx("span",{className:"font-mono tabular-nums text-2xs text-text-tertiary shrink-0",children:te(ke.total*1e3)})]}),e.jsx("div",{className:"flex-1 min-h-0 overflow-auto px-2 py-4",children:R?y?e.jsx("p",{className:"text-2xs text-text-quaternary",children:"Slicing requires full read access to the system's queues."}):ae.length===0?e.jsx("p",{className:"text-2xs text-text-quaternary",children:"No tracked time for this slice in the window."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"flex gap-6 min-w-max",children:ae.map(m=>e.jsx(Yt,{entityKey:t,sliceKey:f,value:m.value,headerGroups:m.groups,headerTotal:m.total,window:w,find:i,colors:D,stateLabel:C,onOpen:n,onTarget:E=>p==null?void 0:p(E)},m.value))}),Q>Fe&&e.jsxs("p",{className:"text-2xs text-text-quaternary pt-4",children:["Showing the top ",Fe," of ",Q," ",e.jsx("span",{className:"font-mono",children:f})," values — a facet this wide isn't a good slice dimension."]})]}):N?e.jsx("p",{className:"text-2xs text-text-quaternary",children:"The per-entity view requires full read access to the system's queues."}):e.jsx(Qt,{rows:ue,colors:D,stateLabel:C,onOpen:n,emptyText:i?`No ${t} starts with “${i}” in this window.`:"No entities tracked in this window."})}),!R&&e.jsxs("div",{className:"shrink-0 border-t border-surface-border bg-surface/95 px-2 pt-2 pb-3 flex items-center gap-3 text-2xs",children:[e.jsx("button",{disabled:$===0,onClick:()=>M($-1),className:"text-text-tertiary hover:text-accent transition-colors disabled:opacity-40 disabled:hover:text-text-tertiary",children:"Prev"}),e.jsxs("span",{className:"font-mono tabular-nums text-text-quaternary",children:["page ",$+1]}),e.jsx("button",{disabled:!u,onClick:()=>M($+1),className:"text-text-tertiary hover:text-accent transition-colors disabled:opacity-40 disabled:hover:text-text-tertiary",children:"Next"}),e.jsxs("span",{className:"ml-auto flex items-center gap-1.5 text-text-quaternary",children:[e.jsx("span",{children:"per page"}),e.jsx("select",{value:b,onChange:m=>F(Number(m.target.value)),"aria-label":"Results per page",className:"select text-2xs font-mono py-0.5",children:Ht.map(m=>e.jsx("option",{value:m,children:m},m))})]})]})]})}function Jt({lenses:t,activeLens:s,stationCount:r,onSelect:i}){const[a,c]=h.useState(!1),n=h.useRef(null);h.useEffect(()=>{if(!a)return;const d=p=>{n.current&&!n.current.contains(p.target)&&c(!1)},x=p=>{p.key==="Escape"&&c(!1)};return document.addEventListener("mousedown",d),document.addEventListener("keydown",x),()=>{document.removeEventListener("mousedown",d),document.removeEventListener("keydown",x)}},[a]);const o=d=>{i(d),c(!1)};return e.jsxs("div",{ref:n,className:"relative",title:"View: the board station-first, or an entity system (roles sharing an entity facet) entity-first",children:[e.jsxs("button",{type:"button",onClick:()=>c(d=>!d),className:"group flex items-baseline gap-1.5","aria-expanded":a,"aria-haspopup":"listbox","aria-label":"Board view",children:[e.jsx("span",{className:"text-2xs uppercase tracking-widest text-text-quaternary",children:"View"}),e.jsx("span",{className:"text-xs font-medium text-text-primary group-hover:text-accent transition-colors",children:s?e.jsxs(e.Fragment,{children:["by ",e.jsx("span",{className:"font-mono",children:s})]}):"Stations"}),e.jsx(ze,{className:`w-3 h-3 self-center shrink-0 text-text-tertiary group-hover:text-accent transition-transform ${a?"rotate-180":""}`,strokeWidth:1.5})]}),a&&e.jsxs("div",{role:"listbox",className:"absolute z-[100] top-full right-0 mt-1.5 min-w-[16rem] max-h-80 overflow-y-auto bg-surface-raised border border-surface-border rounded-md shadow-lg py-1",children:[e.jsx(mt,{label:"Stations",note:`${r} station${r===1?"":"s"}`,active:s===null,onClick:()=>o(null)}),t.map(d=>e.jsx(Kt,{lens:d,active:s===d,fetchCount:a,onClick:()=>o(d)},d))]})]})}function mt({label:t,note:s,active:r,onClick:i,mono:a}){return e.jsxs("button",{type:"button",role:"option","aria-selected":r,onClick:i,className:`w-full text-left px-3 py-1.5 flex items-baseline gap-2.5 transition-colors ${r?"text-accent bg-accent/5":"text-text-primary hover:bg-surface-hover"}`,children:[e.jsx("span",{className:`text-xs font-medium truncate ${a?"font-mono":""}`,children:t}),s&&e.jsx("span",{className:"ml-auto text-2xs font-mono text-text-quaternary tabular-nums shrink-0",children:s})]})}function Kt({lens:t,active:s,fetchCount:r,onClick:i}){var n,o;const c=(o=(n=B({query:{entity:t},groupBy:{},measure:{kind:"membership"},distinctBy:t},{enabled:r}).data)==null?void 0:n.groups[0])==null?void 0:o.count;return e.jsx(mt,{label:`by ${t}`,mono:!0,note:c!=null?`${c} in queue`:null,active:s,onClick:i})}const pt=800,ht=270,ie=28,es=60,Be=24,ts=72,Pe=pt-ie-es,We=ht-Be-ts,G=Be+We,Ie=ie+Pe,I="0.5s cubic-bezier(0.4, 0, 0.2, 1)",Ye=9;function ss(t){return`M ${(t.x-Ye).toFixed(1)} ${t.y.toFixed(1)} L ${(t.x+Ye).toFixed(1)} ${t.y.toFixed(1)}`}function ge(t){if(t.length===0)return"";if(t.length===1)return ss(t[0]);const s=[];for(let r=0;r<t.length-1;r++){const i=t[Math.max(0,r-1)],a=t[r],c=t[r+1],n=t[Math.min(t.length-1,r+2)],o=(a.x+(c.x-i.x)/6).toFixed(1),d=(a.y+(c.y-i.y)/6).toFixed(1),x=(c.x-(n.x-a.x)/6).toFixed(1),p=(c.y-(n.y-a.y)/6).toFixed(1);r===0&&s.push(`M ${a.x.toFixed(1)} ${a.y.toFixed(1)}`),s.push(`C ${o} ${d}, ${x} ${p}, ${c.x.toFixed(1)} ${c.y.toFixed(1)}`)}return s.join(" ")}function ns(t,s){if(t.length<2||s.length<2)return"";const r=ge(t),i=[...s].reverse(),a=ge(i),c=a.slice(a.indexOf("C"));return`${r} L ${i[0].x.toFixed(1)} ${i[0].y.toFixed(1)} ${c} Z`}function Qe(t){return t>=1e4?`${Math.round(t/1e3)}k`:t>=1e3?`${(t/1e3).toFixed(1)}k`:String(t)}function Me(t){return t.length>0?t[t.length-1]:void 0}function as(t){return[1,2,5,10,20,50,100,200,500,1e3,2e3,5e3,1e4,2e4,5e4].filter(r=>r>0&&r<t*.98)}function rs(t){return[.25,.5,.75].map(r=>Math.round(r*t)).filter(r=>r>0)}const ce="rgb(var(--lt-status-claimed-graphic))",je="rgb(var(--lt-status-queued-graphic))",ee="rgb(var(--lt-status-success-graphic))",de="rgb(var(--lt-text-quaternary))",be="rgb(var(--lt-status-error))";function Ne(t,s){return t.replace(/\)$/,` / ${s})`)}const os=13;function ls(t,s){const r=[...t].sort((n,o)=>n.y-o.y);let i=-1/0;const a=r.map(n=>{const o=Math.max(n.y+3,i+os);return i=o,{...n,labelY:o}}),c=a.length>0?a[a.length-1].labelY-s:0;if(c>0)for(const n of a)n.labelY-=c;return a}function is({stations:t,selectedRole:s,onSelect:r,onUpstreamSelect:i,onCmdClick:a,periodHours:c,logScale:n=!1,fill:o=!1}){const[d,x]=h.useState(null),p=t.length;if(p===0)return null;const w=l=>p===1?ie+Pe/2:ie+l/(p-1)*Pe,j=new Map(t.map((l,S)=>[l.role,w(S)])),f=t.map((l,S)=>{var A,Z,W,D;const O=l.target_per_hour??null,U=O!=null?O*c:null;return{idx:S,x:w(S),expected:U,actual:((A=l.metric)==null?void 0:A.resolved)??0,active:((Z=l.metric)==null?void 0:Z.claimed)??0,pending:((W=l.metric)==null?void 0:W.pending)??0,priorityCount:((D=l.metric)==null?void 0:D.priority_count)??0}}),q=f.some(l=>l.expected!=null),R=Math.max(1,...f.map(l=>l.expected??0),...f.map(l=>l.actual),...f.map(l=>l.expected!=null?l.pending:0))*1.15,$=n?l=>{const S=Math.log(1+R);return Be+We*(1-Math.log(1+Math.max(0,l))/S)}:l=>Be+We*(1-Math.max(0,Math.min(l,R))/R),M=n?as(R):rs(R),b=f.filter(l=>l.expected!=null),F=b.map(l=>({...l,y:$(l.expected)})),P=b.map(l=>({...l,y:$(l.actual)})),v=b.map(l=>({...l,y:$(l.active)})),L=b.map(l=>({...l,y:$(l.pending)})),V=ge(F),g=ge(P),C=ge(v),z=ge(L),H=Me(P),fe=Me(F),T=Me(v),ve=Me(L),_=P.length>=2&&H?`${g} L ${H.x.toFixed(1)} ${G} L ${P[0].x.toFixed(1)} ${G} Z`:"",se=b.some(l=>l.pending>0||l.active>0),X=se&&v.length>=2&&T?`${C} L ${T.x.toFixed(1)} ${G} L ${v[0].x.toFixed(1)} ${G} Z`:"",xe=se?ns(L,v):"",ne=b.some(l=>l.active>0),ue=b.some(l=>l.pending>l.active),Y=ls([fe?{key:"target",text:"Target",color:de,y:fe.y}:null,H?{key:"actual",text:"Resolved",color:ee,y:H.y}:null,ne&&T?{key:"active",text:"Claimed",color:ce,y:T.y}:null,ue&&ve?{key:"queued",text:"Pending",color:je,y:ve.y}:null].filter(Boolean),G+4);return e.jsxs("svg",{viewBox:`0 0 ${pt} ${ht}`,className:o?"w-full h-full":"w-full",preserveAspectRatio:"xMidYMid meet",style:{display:"block",...o?{}:{height:"auto"}},children:[M.map(l=>{const S=$(l);return e.jsxs("g",{children:[e.jsx("line",{x1:ie,y1:S,x2:Ie,y2:S,className:"stroke-surface-border",strokeWidth:.5,opacity:n?.45:.3,strokeDasharray:n?"2 5":void 0,style:{transition:`y1 ${I}, y2 ${I}`}}),e.jsx("text",{x:ie-4,y:S+2.5,textAnchor:"end",fontSize:6,fontFamily:"ui-monospace, monospace",opacity:.35,className:"fill-text-quaternary",children:Qe(l)})]},`grid-${l}`)}),t.map(l=>{if(!l.parent_role)return null;const S=j.get(l.parent_role);if(S==null)return null;const O=w(t.findIndex(U=>U.role===l.role));return e.jsx("line",{x1:S,y1:G,x2:O,y2:G,className:"stroke-surface-border",strokeWidth:.75},`dep-${l.role}`)}),_&&e.jsx("path",{d:_,opacity:.05,style:{fill:ee,transition:`d ${I}`}}),X&&e.jsx("path",{d:X,opacity:.12,style:{fill:ce,transition:`d ${I}`}}),xe&&e.jsx("path",{d:xe,opacity:.12,style:{fill:je,transition:`d ${I}`}}),V&&e.jsx("path",{d:V,fill:"none",strokeWidth:.75,strokeDasharray:"2 3",strokeLinecap:"round",opacity:.7,style:{stroke:de,transition:`d ${I}`}}),F.map(l=>e.jsxs("g",{transform:`translate(${l.x} ${l.y})`,style:{transition:`transform ${I}`},children:[e.jsx("circle",{r:2,opacity:.8,style:{fill:de}}),e.jsx("text",{y:-5,textAnchor:"middle",fontSize:6.5,fontFamily:"ui-monospace, monospace",fontWeight:"500",opacity:.7,style:{fill:de},children:Math.round(l.expected)})]},`tval-${l.idx}`)),se&&z&&e.jsx("path",{d:z,fill:"none",strokeWidth:.75,strokeDasharray:"2 3",strokeLinecap:"round",opacity:.55,style:{stroke:je,transition:`d ${I}`}}),C&&e.jsx("path",{d:C,fill:"none",strokeWidth:.75,strokeDasharray:"2 3",strokeLinecap:"round",opacity:.5,style:{stroke:ce,transition:`d ${I}`}}),g&&e.jsx("path",{d:g,fill:"none",strokeWidth:.6,strokeLinejoin:"round",strokeLinecap:"round",opacity:.65,style:{stroke:ee,transition:`d ${I}`}}),v.map((l,S)=>{if(l.pending<=0&&l.active<=0)return null;const O=Math.max(2.5,Math.min(5,2.5+l.active/10)),U=l.pending>l.active,A=Math.min(L[S].y-4,l.y-O-4);return e.jsxs("g",{children:[l.pending>0&&e.jsx("text",{x:l.x,y:A,textAnchor:"middle",fontSize:7.5,fontFamily:"ui-monospace, monospace",fontWeight:"600",style:{fill:U?je:"rgb(var(--lt-text-tertiary))",transition:`y ${I}`},children:l.pending}),e.jsxs("g",{transform:`translate(${l.x} ${l.y})`,style:{transition:`transform ${I}`},children:[e.jsx("circle",{r:O,opacity:.85,style:{fill:ce}}),l.active>0&&e.jsx("text",{y:O+9,textAnchor:"middle",fontSize:7.5,fontFamily:"ui-monospace, monospace",fontWeight:"600",style:{fill:ce},children:l.active})]})]},`active-${l.idx}`)}),f.map(l=>{var ae;const S=t[l.idx],O=l.x,U=l.expected!=null?$(l.actual):G,A=Math.max(2.25,Math.min(4,2.25+l.actual/160)),Z=S.role===s,W=d===l.idx,D=l.expected==null?"idle · set a target rate to plot pace":`${l.actual} resolved · target ${Math.round(l.expected)}`+(l.pending>l.active?` · ${l.pending-l.active} pending`:"")+(l.active>0?` · ${l.active} claimed`:"")+(l.priorityCount>0?` · ${l.priorityCount} in jeopardy`:""),J=D.length*5.5+20,me=Math.max(ie+J/2+4,Math.min(Ie-J/2-4,O)),ye=U-A-10;return e.jsxs("g",{onClick:Q=>{Q.metaKey||Q.ctrlKey?(Q.stopPropagation(),a==null||a(S.role)):r(S.role)},onMouseEnter:()=>x(l.idx),onMouseLeave:()=>x(null),style:{cursor:"pointer"},children:[e.jsxs("g",{transform:`translate(${O} ${U})`,style:{transition:`transform ${I}`},children:[e.jsx("circle",{r:22,fill:"transparent"}),e.jsx("circle",{r:A,opacity:.9,style:{fill:ee,transition:`r ${I}`}}),l.expected!=null&&e.jsx("text",{y:-A-5,textAnchor:"middle",fontSize:9.5,fontFamily:"ui-monospace, monospace",fontWeight:"500",style:{fill:ee},children:Qe(l.actual)}),W&&!Z&&e.jsx("circle",{r:A+3,fill:"none",strokeWidth:1,opacity:.4,style:{stroke:ee}}),Z&&e.jsx("circle",{r:A+4,fill:"none",className:"stroke-accent",strokeWidth:2})]}),(((ae=S.upstream_roles)==null?void 0:ae.length)??0)>0&&e.jsxs("g",{transform:`translate(${O-20} ${G})`,onClick:Q=>{Q.stopPropagation(),i==null||i(S.upstream_roles[0])},style:{cursor:"pointer"},children:[e.jsx("title",{children:`Fed by ${S.upstream_roles.join(", ")} — click to view that sequence`}),e.jsx("circle",{r:9,cy:-6,fill:"transparent"}),e.jsx("path",{d:"M -7 -14 C -3 -14 -1 -9 0 -2",fill:"none",className:"stroke-text-quaternary",strokeWidth:1,strokeDasharray:"2 2",strokeLinecap:"round"}),e.jsx("path",{d:"M 0 -2 L 8 -2",className:"stroke-text-quaternary",strokeWidth:1,strokeLinecap:"round"}),e.jsx("path",{d:"M 8 -2 l -3.5 -2 v 4 z",className:"fill-text-quaternary"})]}),e.jsx("text",{x:O,y:G+(l.idx%2===0?14:27),textAnchor:"middle",fontSize:9.5,className:"fill-text-tertiary",fontFamily:"ui-sans-serif, sans-serif",fontWeight:"500",children:we(S)}),W&&e.jsxs("g",{children:[e.jsx("rect",{x:me-J/2,y:ye-16,width:J,height:19,rx:3,className:"fill-text-primary",opacity:.88}),e.jsx("text",{x:me,y:ye-3,textAnchor:"middle",fontSize:8.5,className:"fill-surface",fontFamily:"ui-monospace, monospace",children:D})]})]},S.role)}),!q&&e.jsx("text",{x:ie+Pe/2,y:G+48,textAnchor:"middle",fontSize:8.5,className:"fill-text-quaternary",fontFamily:"ui-sans-serif, sans-serif",children:"Set target_per_hour on each role in Admin → Roles to enable the pace chart"}),Y.map(l=>e.jsx("text",{x:Ie+6,y:l.labelY,fontSize:8,fontFamily:"ui-sans-serif, sans-serif",fontWeight:l.key==="actual"?700:500,opacity:l.key==="active"?.85:1,style:{fill:l.color,transition:`y ${I}`},children:l.text},l.key))]})}function ft(t){const s=t.priority_facet?`metadata.${t.priority_facet}`:"created_at",r=JSON.stringify([{field:s,direction:"asc"}]);return`/escalations/available?role=${encodeURIComponent(t.role)}&jeopardy=1&view=table&orderBy=${encodeURIComponent(r)}`}function cs({role:t,periodHours:s,onOpenEntity:r}){var M,b,F,P,v,L,V;const i=Ue(s),a=t.entity_facet,[c,n]=h.useState(!1),[,o]=lt(),d=()=>{a&&o(g=>{const C=new URLSearchParams(g);return C.set("lens",a),C})},x=B({query:{roles:[t.role]},groupBy:{columns:["subtype"]},measure:{kind:"dwell",window:i},orderBy:[{field:"dwellSeconds",direction:"desc"}]}),p=B({query:{roles:[t.role]},groupBy:{columns:["subtype"]},measure:{kind:"membership"},orderBy:[{field:"count",direction:"desc"}]}),w=B(a?{query:{roles:[t.role]},groupBy:{},measure:{kind:"membership"},distinctBy:a}:null),j=B(a&&c?{query:{roles:[t.role],exists:[a]},groupBy:{facets:[a]},measure:{kind:"dwell",window:i},orderBy:[{field:"dwellSeconds",direction:"desc"}],limit:8}:null),f=h.useMemo(()=>{var g,C;return at([...((g=x.data)==null?void 0:g.groups)??[],...((C=p.data)==null?void 0:C.groups)??[]])},[x.data,p.data]);if(Ee(x.error))return e.jsx("div",{className:"border-t border-surface-border/40 pt-4 mt-5",children:e.jsx("p",{className:"text-2xs text-text-quaternary",children:"Analytics require full read access to this station's queue."})});const q=(((M=x.data)==null?void 0:M.groups)??[]).filter(g=>(g.dwellSeconds??0)>0),k=q.reduce((g,C)=>g+(C.dwellSeconds??0),0),R=(((b=p.data)==null?void 0:b.groups)??[]).filter(g=>(g.count??0)>0),$=((P=(F=w.data)==null?void 0:F.groups[0])==null?void 0:P.count)??null;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"border-t border-surface-border/40 pt-4 mt-5",children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-2.5",children:"Where the time went"}),k>0?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-2 flex rounded-full overflow-hidden bg-surface-sunken mb-2.5",children:q.map(g=>e.jsx("div",{style:{width:`${(g.dwellSeconds??0)/k*100}%`,backgroundColor:f.get(he(g.subtype))}},he(g.subtype)))}),e.jsx("div",{className:"space-y-1",children:q.map(g=>e.jsxs("div",{className:"flex items-center gap-2 text-2xs",children:[e.jsx("span",{className:"w-2 h-2 rounded-full shrink-0",style:{backgroundColor:f.get(he(g.subtype))}}),e.jsx("span",{className:`font-mono truncate flex-1 ${g.subtype?"text-text-secondary":"text-text-tertiary"}`,children:Le(g.subtype)}),e.jsx("span",{className:"font-mono tabular-nums text-text-secondary shrink-0",children:te((g.dwellSeconds??0)*1e3)}),e.jsxs("span",{className:"font-mono tabular-nums text-text-quaternary w-8 text-right shrink-0",children:[Math.round((g.dwellSeconds??0)/k*100),"%"]})]},he(g.subtype)))}),((v=x.data)==null?void 0:v.overflow)&&e.jsx("p",{className:"text-2xs text-text-quaternary mt-1.5",children:"more groups exist — narrow the window"})]}):e.jsx("p",{className:"text-2xs text-text-quaternary",children:"No tracked time in this window."})]}),e.jsxs("div",{className:"border-t border-surface-border/40 pt-4 mt-5",children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-2.5",children:"In queue now"}),a&&$!=null&&e.jsxs("button",{onClick:d,className:"group flex items-center gap-1 text-2xs mb-2 text-left",title:`Open the ${a} lens — the whole system, entity-first`,children:[e.jsx("span",{className:"text-xs font-mono font-semibold text-text-primary tabular-nums",children:$})," ",e.jsx("span",{className:"font-mono text-text-tertiary group-hover:text-accent transition-colors",children:a}),e.jsx("span",{className:"text-text-quaternary",children:" in queue"}),e.jsx(Lt,{className:"w-3 h-3 text-text-quaternary group-hover:text-accent transition-colors"})]}),R.length>0?e.jsx("div",{className:"space-y-1",children:R.map(g=>e.jsxs("div",{className:"flex items-center gap-2 text-2xs",children:[e.jsx("span",{className:"w-2 h-2 rounded-full shrink-0",style:{backgroundColor:f.get(he(g.subtype))}}),e.jsx("span",{className:`font-mono truncate flex-1 ${g.subtype?"text-text-secondary":"text-text-tertiary"}`,children:Le(g.subtype)}),e.jsx("span",{className:"font-mono tabular-nums text-text-primary shrink-0",children:g.count})]},he(g.subtype)))}):e.jsx("p",{className:"text-2xs text-text-quaternary",children:"Queue clear."}),a&&e.jsxs("div",{className:"mt-3",children:[e.jsxs("button",{onClick:()=>n(g=>!g),className:"flex items-center gap-1 text-2xs text-text-tertiary hover:text-accent transition-colors",children:[c?e.jsx(ze,{className:"w-3 h-3"}):e.jsx(Et,{className:"w-3 h-3"}),"By entity"]}),c&&(Ee(j.error)?e.jsx("p",{className:"text-2xs text-text-quaternary mt-1.5",children:"Requires full read access to this station's queue."}):e.jsxs("div",{className:"space-y-1 mt-1.5",children:[(((L=j.data)==null?void 0:L.groups)??[]).map(g=>{const C=g.facets[a];return C==null?null:e.jsxs("div",{className:"flex items-center gap-2 text-2xs",children:[e.jsx("span",{className:"font-mono truncate flex-1 text-text-secondary",title:C,children:C}),e.jsx("span",{className:"font-mono tabular-nums text-text-secondary shrink-0",children:te((g.dwellSeconds??0)*1e3)}),e.jsx("button",{className:"icon-link shrink-0",title:"Open timeline",onClick:()=>r(a,C),children:e.jsx(rt,{className:"w-3 h-3"})})]},C)}),j.data&&j.data.groups.length===0&&e.jsx("p",{className:"text-2xs text-text-quaternary",children:"No entities in this window."}),((V=j.data)==null?void 0:V.overflow)&&e.jsx("p",{className:"text-2xs text-text-quaternary",children:"top 8 by dwell"})]}))]})]})]})}const yt=["15m","1h","24h","7d","30d"],ds=t=>yt.includes(t),xs={"15m":.25,"1h":1,"24h":24,"7d":168,"30d":720};function Ce(t){if(t==null)return"—";if(t<1){const s=Math.round(t*60);return s<=0?"< 1s":`${s}s`}return t<60?`${t.toFixed(0)}m`:`${(t/60).toFixed(1)}h`}function _e({label:t,value:s}){return e.jsxs("div",{className:"flex items-center justify-between py-1.5",children:[e.jsx("span",{className:"text-2xs text-text-tertiary uppercase tracking-wider",children:t}),e.jsx("span",{className:"text-xs font-mono font-medium text-text-primary tabular-nums",children:s})]})}function us({period:t,onChange:s}){return e.jsx("div",{className:"flex items-center gap-1 mb-4",children:yt.map(r=>e.jsx("button",{onClick:()=>s(r),className:`px-2 py-0.5 text-2xs font-mono rounded transition-colors ${t===r?"bg-accent/10 text-accent font-semibold":"icon-link"}`,children:r},r))})}function ms({role:t,globalPeriod:s,onClose:r}){const[i,a]=h.useState(ds(s)?s:"24h"),{data:c}=st(i),n=c==null?void 0:c.stations.find(j=>j.role===t.role),o=t.sla_minutes??void 0,d=t.target_per_hour??void 0,x=t.worker_count??void 0,p=tt(),w=h.useCallback((j,f)=>{p==null||p.setPanel(t.entity_facet?e.jsx(Te,{facetKey:j,value:f,entity:t.entity_facet}):e.jsx(Te,{facetKey:j,value:f,role:t.role}),{key:"entity-timeline",width:420})},[p,t.role,t.entity_facet]);return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-start justify-between mb-4",children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex items-baseline gap-1.5 flex-wrap",children:[e.jsx("span",{className:"text-sm font-bold text-text-primary",children:we(t)}),e.jsx("span",{className:"text-2xs font-mono text-text-secondary",children:t.role})]}),t.description&&e.jsx("p",{className:"text-2xs text-text-tertiary mt-1 line-clamp-2 leading-relaxed",children:t.description})]}),e.jsx("button",{onClick:r,className:"icon-link mt-0.5 shrink-0 ml-2",children:e.jsx(Ot,{className:"w-4 h-4"})})]}),n&&n.priority_count>0&&e.jsxs(le,{to:ft(t),className:"flex items-center justify-between group mb-4",children:[e.jsxs("span",{className:"text-2xs",style:{color:be},children:[n.priority_count," in jeopardy — pull oldest first"]}),e.jsx(At,{className:"w-3 h-3 transition-colors",style:{color:be}})]}),e.jsx(us,{period:i,onChange:a}),(d||o||x)&&e.jsxs("div",{className:"flex items-center gap-6 mb-6 text-2xs border-b border-surface-border/30 pb-5",children:[d&&e.jsxs("div",{children:[e.jsxs("div",{className:"font-mono font-semibold text-text-primary text-sm",children:[d,"/h"]}),e.jsx("div",{className:"text-text-quaternary uppercase tracking-wider text-[8.5px] mt-0.5",children:"target"})]}),o&&e.jsxs("div",{children:[e.jsxs("div",{className:"font-mono font-semibold text-text-primary text-sm",children:[o,"m"]}),e.jsx("div",{className:"text-text-quaternary uppercase tracking-wider text-[8.5px] mt-0.5",children:"SLA"})]}),x&&e.jsxs("div",{children:[e.jsx("div",{className:"font-mono font-semibold text-text-primary text-sm",children:x}),e.jsx("div",{className:"text-text-quaternary uppercase tracking-wider text-[8.5px] mt-0.5",children:"workers"})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-x-4 mb-2",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-2xs text-text-quaternary uppercase tracking-wider mb-2",children:"Wait (queue)"}),e.jsx(_e,{label:"P99",value:Ce((n==null?void 0:n.wait.p99)??null)}),e.jsx(_e,{label:"avg",value:Ce((n==null?void 0:n.wait.avg)??null)})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-2xs text-text-quaternary uppercase tracking-wider mb-2",children:"Work (proc.)"}),e.jsx(_e,{label:"P99",value:Ce((n==null?void 0:n.work.p99)??null)}),e.jsx(_e,{label:"avg",value:Ce((n==null?void 0:n.work.avg)??null)})]})]}),o&&e.jsx("div",{className:"border-t border-surface-border/40 pt-4 mt-5",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-2xs text-text-tertiary",children:"SLA target"}),e.jsxs("span",{className:"text-xs font-mono text-text-secondary",children:[o,"m"]})]})}),e.jsx(cs,{role:t,periodHours:xs[i],onOpenEntity:w})]})}function ps({allMetrics:t,orderedRoles:s,period:r}){const i=t.reduce((x,p)=>x+p.pending,0),a=t.reduce((x,p)=>x+p.resolved,0),c=t.reduce((x,p)=>x+p.priority_count,0),n=new Map(t.map(x=>[x.role,x])),o=t.filter(x=>x.priority_count>0).length,d=t.filter(x=>x.pending>0).length;return e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"text-2xs text-text-quaternary uppercase tracking-wider mb-3",children:["Pipeline · ",r]}),e.jsx("div",{className:"mb-4",children:o>0?e.jsxs("p",{className:"text-2xs",style:{color:be},children:[o," station",o>1?"s":""," with items in jeopardy"]}):d>0?e.jsxs("p",{className:"text-2xs text-status-warning",children:[d," station",d>1?"s":""," with backlog"]}):a>0?e.jsx("p",{className:"text-2xs text-status-success",children:"Flowing — queue clear"}):e.jsx("p",{className:"text-2xs text-text-quaternary",children:"Quiet — awaiting work"})}),e.jsxs("div",{className:"space-y-1.5 mb-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-2xs text-text-quaternary uppercase tracking-wider",children:"Pending"}),e.jsx("span",{className:`text-xs font-mono tabular-nums ${i>0?"text-text-primary font-semibold":"text-text-quaternary"}`,children:i})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-2xs text-text-quaternary uppercase tracking-wider",children:["Resolved · ",r]}),e.jsx("span",{className:"text-xs font-mono tabular-nums text-text-secondary",children:a})]}),c>0&&e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-2xs text-text-quaternary uppercase tracking-wider",children:"Priority"}),e.jsx("span",{className:"text-xs font-mono tabular-nums font-semibold",style:{color:be},children:c})]})]}),e.jsx("div",{className:"border-t border-surface-border/40 pt-2 mb-1",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-2xs text-text-quaternary uppercase tracking-wider flex-1",children:"Station"}),e.jsx("span",{className:"text-2xs text-text-quaternary uppercase tracking-wider w-8 text-right shrink-0",children:"pend"}),e.jsx("span",{className:"text-2xs text-text-quaternary uppercase tracking-wider w-8 text-right shrink-0",children:"clmd"}),e.jsx("span",{className:"text-2xs text-text-quaternary uppercase tracking-wider w-8 text-right shrink-0",children:"res"})]})}),e.jsx("div",{className:"space-y-0.5",children:s.map(x=>{const p=n.get(x.role),w=(p==null?void 0:p.pending)??0,j=(p==null?void 0:p.claimed)??0,f=(p==null?void 0:p.resolved)??0,q=(p==null?void 0:p.priority_count)??0,k=x.title||x.role,R=q>0,$=w>0;return e.jsxs("div",{className:"flex items-center gap-2 py-0.5",children:[e.jsx("span",{className:`text-2xs font-mono flex-1 truncate ${$?"text-text-primary":"text-text-quaternary"}`,title:k,children:k}),e.jsx("span",{className:"text-[0.625rem] leading-none font-semibold tabular-nums w-4 text-right shrink-0",style:{color:be},title:R?`${q} priority — pull oldest first`:void 0,children:R?q:""}),e.jsx("span",{className:`text-2xs font-mono tabular-nums w-8 text-right shrink-0 ${$?"text-text-primary font-semibold":"text-text-quaternary"}`,children:w>0?w:"—"}),e.jsx("span",{className:`text-2xs font-mono tabular-nums w-8 text-right shrink-0 ${j>0?"text-accent font-semibold":"text-text-quaternary"}`,children:j>0?j:"—"}),e.jsx("span",{className:`text-2xs font-mono tabular-nums w-8 text-right shrink-0 ${f>0?"text-text-secondary":"text-text-quaternary"}`,children:f>0?f:"—"})]},x.role)})}),e.jsx("p",{className:"text-2xs text-text-quaternary mt-5",children:"Select a station for queue detail."})]})}function hs({role:t,allMetrics:s,orderedRoles:r,globalPeriod:i,mixGroups:a,onClose:c}){return e.jsx("div",{className:"w-[280px] shrink-0 px-7 py-10 flex flex-col overflow-y-auto min-h-0",children:t?e.jsx(ms,{role:t,globalPeriod:i,onClose:c}):e.jsxs(e.Fragment,{children:[e.jsx(ps,{allMetrics:s,orderedRoles:r,period:i}),e.jsx(fs,{mixGroups:a,orderedRoles:r})]})})}function fs({mixGroups:t,orderedRoles:s}){const r=new Set(s.map(o=>o.role)),i=(t??[]).filter(o=>o.role&&r.has(o.role)&&(o.dwellSeconds??0)>0);if(i.length===0)return null;const a=new Map(s.map(o=>[o.role,o.title||o.role])),c=Xe(i,o=>o.role),n=Xe(i,o=>Le(o.subtype));return e.jsxs(e.Fragment,{children:[e.jsx(Ze,{label:"Time by station",entries:c,display:o=>a.get(o)??o}),e.jsx(Ze,{label:"Time by subtype",entries:n,display:o=>o})]})}function Xe(t,s){const r=new Map;for(const i of t){const a=s(i);r.set(a,(r.get(a)??0)+(i.dwellSeconds??0))}return[...r.entries()].sort(([,i],[,a])=>a-i)}function Ze({label:t,entries:s,display:r}){const i=nt(s.map(([c,n])=>({label:c,weight:n}))),a=s.reduce((c,[,n])=>c+n,0)||1;return e.jsxs("div",{className:"border-t border-surface-border/40 pt-4 mt-5",children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-2.5",children:t}),e.jsx("div",{className:"h-2 flex rounded-full overflow-hidden bg-surface-sunken mb-2",children:s.map(([c,n])=>e.jsx("div",{style:{width:`${n/a*100}%`,backgroundColor:i.get(c)}},c))}),e.jsxs("div",{className:"space-y-0.5",children:[s.slice(0,6).map(([c,n])=>e.jsxs("div",{className:"flex items-center gap-2 text-2xs",children:[e.jsx("span",{className:"w-2 h-2 rounded-full shrink-0",style:{backgroundColor:i.get(c)}}),e.jsx("span",{className:"font-mono text-text-secondary truncate flex-1",children:r(c)}),e.jsx("span",{className:"font-mono tabular-nums text-text-tertiary shrink-0",children:te(n*1e3)}),e.jsxs("span",{className:"font-mono tabular-nums text-text-quaternary w-8 text-right shrink-0",children:[Math.round(n/a*100),"%"]})]},c)),s.length>6&&e.jsxs("p",{className:"text-2xs text-text-quaternary",children:["+",s.length-6," more"]})]})]})}const ys=de,He="rgb(var(--lt-accent))",gt=Ne(de,.09),jt=Ne(de,.09),bt=Ne(He,.07),wt=Ne(je,.08),Nt=Ne(ce,.08),vt=Ne(ee,.08),gs=["15m","1h","24h","7d","30d"],Re={"15m":.25,"1h":1,"24h":24,"7d":168,"30d":720};function De(t){const s=t.filter(n=>n.ops_visible),r=new Map(s.map(n=>[n.role,n])),i=new Set,c=s.filter(n=>!n.parent_role||!r.has(n.parent_role)).map(n=>{const o=[],d=[{role:n,depth:0}];for(;d.length>0;){const x=d.shift();i.has(x.role.role)||(i.add(x.role.role),o.push(x),s.filter(p=>p.parent_role===x.role.role&&!i.has(p.role)).forEach(p=>d.push({role:p,depth:x.depth+1})))}return{origin:n,stations:o}});return s.filter(n=>!i.has(n.role)).forEach(n=>c.push({origin:n,stations:[{role:n,depth:0}]})),c.sort((n,o)=>o.stations.length-n.stations.length||n.origin.role.localeCompare(o.origin.role))}function Je(t){if(t==null)return"—";if(t<1){const s=Math.round(t*60);return s<=0?"< 1s":`${s}s`}return t<60?`${t.toFixed(0)}m`:`${(t/60).toFixed(1)}h`}function js(t,s){if(!s||t===0)return{pct:null,color:"bg-surface-border"};const r=t/s,i=Math.round(r*100),a=r>1?"bg-status-warning":r<.2?"bg-status-draft":"bg-status-success";return{pct:i,color:a}}function Ke({value:t,onSave:s}){const[r,i]=h.useState(t!=null?String(t):""),a=h.useRef(void 0),c=n=>{const o=parseInt(n,10);s(!n.trim()||isNaN(o)||o<0?null:o)};return e.jsx("input",{type:"number",min:0,step:1,value:r,onChange:n=>{const o=n.target.value;i(o),clearTimeout(a.current),a.current=setTimeout(()=>c(o),400)},onBlur:n=>{clearTimeout(a.current),c(n.target.value)},onClick:n=>n.stopPropagation(),onKeyDown:n=>n.stopPropagation(),className:"w-full bg-transparent text-xs font-mono tabular-nums text-right focus:outline-none"})}function bs({role:t,metric:s,mixGroups:r,mixColors:i,selected:a,periodHours:c,onClick:n}){var P;const o=St(),{isBuilder:d,isOps:x}=qt(),p=(s==null?void 0:s.pending)??0,w=(s==null?void 0:s.claimed)??0,j=(s==null?void 0:s.resolved)??0,f=(s==null?void 0:s.priority_count)??0,q=t.target_per_hour??null,{pct:k,color:R}=js(p,q),$=k!=null?Math.min(100,k):0,M=vs(t.target_per_hour??null,t.sla_minutes??null,p,c),b=v=>o.mutate({role:t.role,target_per_hour:v}),F=v=>o.mutate({role:t.role,sla_minutes:v});return e.jsxs("tr",{tabIndex:0,onClick:n,onKeyDown:v=>{v.key==="Enter"&&n()},className:`cursor-pointer border-b border-surface-border/30 last:border-b-0 transition-colors ${a?"border-l-2 !border-l-accent":""}`,children:[e.jsx("td",{className:"pl-3 pr-2 py-1.5 overflow-hidden",children:e.jsxs("div",{className:"flex items-center gap-1.5 min-w-0",children:[e.jsx("span",{className:"font-bold text-text-primary truncate text-xs",children:we(t)}),(((P=t.upstream_roles)==null?void 0:P.length)??0)>0&&e.jsx("span",{title:`Fed by ${t.upstream_roles.join(", ")}`,className:"shrink-0 leading-none",children:e.jsx(Ft,{className:"w-3 h-3 text-text-quaternary"})})]})}),e.jsx("td",{className:"hidden xl:table-cell pr-2 py-1.5 overflow-hidden",children:e.jsx("span",{className:"block font-mono text-2xs text-text-tertiary truncate",children:t.role})}),e.jsx("td",{className:"px-2 py-1.5",style:{backgroundColor:gt},children:e.jsx(Ke,{value:t.target_per_hour??null,onSave:b})}),e.jsx("td",{className:"px-2 py-1.5",style:{backgroundColor:jt},children:e.jsx(Ke,{value:t.sla_minutes??null,onSave:F})}),e.jsx("td",{className:"px-2 py-1.5 text-right",style:{backgroundColor:bt},title:M!=null?`~${M} concurrent worker${M===1?"":"s"} to sustain ${t.target_per_hour}/h within ${t.sla_minutes}m SLA`:void 0,children:e.jsx("span",{className:`text-xs font-mono tabular-nums ${M!=null?"":"text-text-quaternary"}`,style:M!=null?{color:He}:void 0,children:M??"—"})}),e.jsx("td",{className:"px-2 py-1.5 text-right",style:{backgroundColor:wt},children:e.jsx(le,{to:`/escalations/available?role=${encodeURIComponent(t.role)}&status=available`,className:`text-xs font-mono tabular-nums hover:underline ${p>0?"text-text-primary font-semibold":"text-text-quaternary"}`,onClick:v=>v.stopPropagation(),children:p})}),e.jsx("td",{className:"px-2 py-1.5 text-right",style:{backgroundColor:Nt},children:e.jsx(le,{to:`/escalations/available?role=${encodeURIComponent(t.role)}&status=claimed`,className:`text-xs font-mono tabular-nums hover:underline ${w>0?"font-semibold":"text-text-quaternary"}`,style:w>0?{color:ce}:void 0,onClick:v=>v.stopPropagation(),children:w})}),e.jsx("td",{className:"px-2 py-1.5 text-right",style:{backgroundColor:vt},children:e.jsx(le,{to:`/escalations/available?role=${encodeURIComponent(t.role)}&status=resolved`,className:`text-xs font-mono tabular-nums hover:underline ${j>0?"text-text-secondary":"text-text-quaternary"}`,style:j>0?{color:ee}:void 0,onClick:v=>v.stopPropagation(),children:j})}),e.jsx("td",{className:"hidden xl:table-cell px-2 py-1.5 text-right",children:e.jsx("span",{className:"text-xs font-mono tabular-nums text-text-secondary",children:Je((s==null?void 0:s.wait.p99)??null)})}),e.jsx("td",{className:"hidden xl:table-cell px-2 py-1.5 text-right",children:e.jsx("span",{className:"text-xs font-mono tabular-nums text-text-secondary",children:Je((s==null?void 0:s.work.p99)??null)})}),e.jsx("td",{className:"hidden lg:table-cell px-2 py-1.5",children:e.jsx(Ut,{groups:r,colors:i})}),e.jsx("td",{className:"hidden lg:table-cell px-2 py-1.5",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-12 h-1.5 bg-surface-sunken rounded-full overflow-hidden shrink-0",children:e.jsx("div",{className:`h-full rounded-full ${R}`,style:{width:`${$}%`}})}),e.jsx("span",{className:`text-2xs font-mono tabular-nums ${k!=null&&k>100?"text-status-warning font-semibold":"text-text-quaternary"}`,children:k!=null?`${k}%`:"—"})]})}),e.jsx("td",{className:"py-1.5",children:e.jsxs("div",{className:"flex items-center justify-center gap-1.5",children:[e.jsx(le,{to:`/escalations/available?role=${encodeURIComponent(t.role)}&status=all`,className:"icon-link",title:"View all items in queue",onClick:v=>v.stopPropagation(),children:e.jsx(It,{className:"w-3.5 h-3.5"})}),e.jsx("span",{className:"w-3.5 flex items-center justify-center",children:(d||x)&&e.jsx(le,{to:`/admin/roles/${encodeURIComponent(t.role)}?section=pace-board`,className:"icon-link",title:"Configure this station",onClick:v=>v.stopPropagation(),children:e.jsx(Tt,{className:"w-3.5 h-3.5"})})}),e.jsx("span",{className:"w-3.5 flex items-center justify-center",children:f>0&&e.jsx(le,{to:ft(t),className:"text-status-error hover:opacity-70 transition-opacity",title:`${f} item${f===1?"":"s"} in jeopardy — pull oldest first`,onClick:v=>v.stopPropagation(),children:e.jsx(ot,{className:"w-3.5 h-3.5",strokeWidth:2})})})]})})]})}function et({n:t}){return t<=0?null:e.jsxs("span",{className:"inline-flex items-center gap-0.5 font-semibold tabular-nums",style:{color:be},title:`${t} in jeopardy`,children:[e.jsx(ot,{className:"w-3 h-3",strokeWidth:2.25}),t>9?"9+":t]})}function ws({fragments:t,aggregates:s,activeOrigin:r,onSelect:i}){const[a,c]=h.useState(!1),n=h.useRef(null);h.useEffect(()=>{if(!a)return;const x=w=>{n.current&&!n.current.contains(w.target)&&c(!1)},p=w=>{w.key==="Escape"&&c(!1)};return document.addEventListener("mousedown",x),document.addEventListener("keydown",p),()=>{document.removeEventListener("mousedown",x),document.removeEventListener("keydown",p)}},[a]);const o=t.find(x=>x.origin.role===r)??t[0];if(!o)return null;const d=s.get(o.origin.role);return e.jsxs("div",{ref:n,className:"relative px-4 pt-2",children:[e.jsxs("button",{type:"button",onClick:()=>c(x=>!x),className:"group flex items-baseline gap-2.5","aria-expanded":a,"aria-haspopup":"listbox",children:[e.jsx("span",{className:"text-sm font-medium text-text-primary group-hover:text-accent transition-colors",children:we(o.origin)}),e.jsxs("span",{className:"text-2xs font-mono text-text-quaternary tabular-nums",children:[(d==null?void 0:d.stations)??o.stations.length," station",((d==null?void 0:d.stations)??o.stations.length)===1?"":"s"," · ",(d==null?void 0:d.pending)??0," pending"]}),e.jsx(et,{n:(d==null?void 0:d.jeopardy)??0}),e.jsx(ze,{className:`w-3.5 h-3.5 self-center shrink-0 text-text-tertiary group-hover:text-accent transition-transform ${a?"rotate-180":""}`,strokeWidth:1.5})]}),a&&e.jsx("div",{role:"listbox",className:"absolute z-[100] top-full left-4 mt-1.5 min-w-[20rem] max-h-80 overflow-y-auto bg-surface-raised border border-surface-border rounded-md shadow-lg py-1",children:t.map(x=>{const p=s.get(x.origin.role),w=x.origin.role===o.origin.role;return e.jsxs("button",{type:"button",role:"option","aria-selected":w,onClick:()=>{i(x.origin.role),c(!1)},className:`w-full text-left px-3 py-1.5 flex items-baseline gap-2.5 transition-colors ${w?"text-accent bg-accent/5":"text-text-primary hover:bg-surface-hover"}`,children:[e.jsx("span",{className:"text-xs font-medium truncate",children:we(x.origin)}),e.jsxs("span",{className:"ml-auto text-2xs font-mono text-text-quaternary tabular-nums shrink-0",children:[(p==null?void 0:p.stations)??x.stations.length," st · ",(p==null?void 0:p.pending)??0," pending"]}),e.jsx("span",{className:"w-12 shrink-0 text-left text-2xs",children:e.jsx(et,{n:(p==null?void 0:p.jeopardy)??0})})]},x.origin.role)})})]})}const Ns=[{label:"TARGET/H",band:gt,hue:de,w:"w-[8%]"},{label:"SLA/M",band:jt,hue:ys,w:"w-[7%]"},{label:"WORKERS",band:bt,hue:He,w:"w-[8%]"},{label:"PENDING",band:wt,hue:je,w:"w-[8%]"},{label:"CLAIMED",band:Nt,hue:ce,w:"w-[8%]"},{label:"RESOLVED",band:vt,hue:ee,w:"w-[8%]"}];function vs(t,s,r,i){if(!t||!s)return null;const a=t*s/60,c=r>0?r*s/(60*i):0;return Math.ceil(a+c)}const oe="sticky top-0 z-10 bg-surface border-b border-surface-border py-1.5 text-2xs font-semibold uppercase tracking-wider whitespace-nowrap";function ks(){return e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{className:`${oe} pl-3 pr-2 text-left text-text-quaternary`,children:"NAME"}),e.jsx("th",{className:`${oe} hidden xl:table-cell w-[12%] pr-2 text-left text-text-quaternary`,children:"ROLE"}),Ns.map(t=>e.jsx("th",{className:`${oe} ${t.w} px-2 text-right`,style:{color:t.hue,backgroundImage:`linear-gradient(${t.band}, ${t.band})`},children:t.label},t.label)),e.jsx("th",{className:`${oe} hidden xl:table-cell w-[8%] px-2 text-right text-text-quaternary`,children:"P99 WAIT"}),e.jsx("th",{className:`${oe} hidden xl:table-cell w-[8%] px-2 text-right text-text-quaternary`,children:"P99 WORK"}),e.jsx("th",{className:`${oe} hidden lg:table-cell w-[10%] px-2 text-left text-text-quaternary`,children:"MIX"}),e.jsx("th",{className:`${oe} hidden lg:table-cell w-[11%] px-2 text-left text-text-quaternary`,children:"TREND"}),e.jsx("th",{className:`${oe} w-20 px-1 text-center text-text-quaternary`,children:"ACTIONS"})]})})}function $s(){var ke;const[t,s]=h.useState("1h"),[r,i]=h.useState(null),[a,c]=h.useState(!1),[n,o]=h.useState(!0);Mt(),Ct();const{data:d,isLoading:x,refetch:p}=$t(),{data:w,isLoading:j,refetch:f}=st(t),q=(d==null?void 0:d.roles)??[],k=(w==null?void 0:w.stations)??[],R=h.useMemo(()=>{const u=new Map(k.map(y=>[y.role,y])),N=new Map;for(const y of De((d==null?void 0:d.roles)??[])){let pe=0,$e=0;for(const Se of y.stations){const K=u.get(Se.role.role);pe+=(K==null?void 0:K.pending)??0,$e+=(K==null?void 0:K.priority_count)??0}N.set(y.origin.role,{stations:y.stations.length,pending:pe,jeopardy:$e})}return N},[k,d]),$=h.useMemo(()=>De(q),[q]),[M,b]=lt(),F=M.get("fragment"),P=$.find(u=>u.origin.role===F)??$[0]??null,v=h.useCallback(u=>{i(null),b(N=>{const y=new URLSearchParams(N);return y.set("fragment",u),y})},[b]),L=(P==null?void 0:P.stations)??[],V=h.useMemo(()=>new Set(L.map(({role:u})=>u.role)),[L]),g=Ue(Re[t]),C=h.useMemo(()=>L.map(({role:u})=>u.role),[L]),{data:z}=B(C.length?{query:{roles:C},groupBy:{columns:["role","subtype"]},measure:{kind:"dwell",window:g}}:null),H=h.useMemo(()=>{const u=new Map;for(const N of(z==null?void 0:z.groups)??[]){if(!N.role)continue;const y=u.get(N.role)??[];y.push(N),u.set(N.role,y)}return u},[z]),fe=h.useMemo(()=>{const u=new Map;for(const[N,y]of H)u.set(N,at(y));return u},[H]),T=h.useMemo(()=>new Map,[]),ve=h.useMemo(()=>k.filter(u=>V.has(u.role)),[k,V]),_=h.useMemo(()=>L.map(({role:u})=>({role:u.role,title:u.title,parent_role:u.parent_role,target_per_hour:u.target_per_hour??null,upstream_roles:u.upstream_roles??[],metric:k.find(N=>N.role===u.role)})),[L,k]),se=h.useCallback(u=>{const N=$.find(y=>y.stations.some(({role:pe})=>pe.role===u));N&&v(N.origin.role)},[$,v]),X=Dt(),xe=((ke=L.find(({role:u})=>u.role===r))==null?void 0:ke.role)??null,ne=h.useMemo(()=>{const u=new Set;for(const N of q)N.ops_visible&&N.entity_facet&&u.add(N.entity_facet);return[...u].sort()},[q]),ue=M.get("lens"),Y=ue&&ne.includes(ue)?ue:null,l=h.useCallback(u=>{i(null),b(N=>{const y=new URLSearchParams(N);return u?y.set("lens",u):y.delete("lens"),y.delete("entity"),y.delete("find"),y.delete("slice"),y.delete("sliceValue"),y})},[b]),S=M.get("entity"),O=M.get("find"),U=h.useCallback(u=>{b(N=>{const y=new URLSearchParams(N);return u?y.set("entity",u):y.delete("entity"),y})},[b]),A=h.useCallback(u=>{b(N=>{const y=new URLSearchParams(N);return u?y.set("find",u):y.delete("find"),y},{replace:!0})},[b]),Z=M.get("slice"),W=M.get("sliceValue"),D=h.useCallback(u=>{b(N=>{const y=new URLSearchParams(N);return u?y.set("slice",u):y.delete("slice"),y.delete("sliceValue"),y})},[b]),J=h.useCallback(u=>{b(N=>{const y=new URLSearchParams(N);return u?y.set("sliceValue",u):y.delete("sliceValue"),y})},[b]),me=x||j,ye=async()=>{c(!0),await Promise.all([p(),f()]),c(!1)},ae=u=>i(N=>N===u?null:u),Q=e.jsx("div",{className:"flex items-center gap-0.5",children:gs.map(u=>e.jsx("button",{onClick:()=>s(u),className:`px-2.5 py-1 text-2xs font-mono rounded transition-colors ${t===u?"bg-accent/10 text-accent font-semibold":"icon-link"}`,children:u},u))});return e.jsxs("div",{className:"flex flex-col flex-1 min-h-0",children:[e.jsx(Wt,{title:"Pace Board",docsHash:"#docs:dashboard.md:pace-board",center:Q,actions:e.jsx("button",{onClick:ye,disabled:a,className:"icon-link disabled:opacity-40",children:e.jsx(Bt,{className:`w-3.5 h-3.5 ${a?"animate-spin":""}`})})}),me?e.jsxs("div",{className:"animate-pulse space-y-6 mt-4",children:[e.jsx("div",{className:"h-8 bg-surface-sunken rounded w-64"}),e.jsx("div",{className:"h-64 bg-surface-sunken rounded w-full"}),e.jsx("div",{className:"space-y-3",children:[1,2,3].map(u=>e.jsx("div",{className:"h-8 bg-surface-sunken rounded w-full"},u))})]}):$.length===0?e.jsxs("div",{className:"mt-8",children:[e.jsx("p",{className:"text-sm text-text-secondary mb-2",children:"Stations appear here once roles are marked visible in Operations."}),e.jsxs("p",{className:"text-xs text-text-tertiary",children:["Go to"," ",e.jsx(le,{to:"/admin/roles",className:"text-accent hover:underline",children:"Roles"})," ","and enable ",e.jsx("strong",{children:"Visible in Operations"})," on roles that represent pipeline stations."]})]}):e.jsxs("div",{className:"flex flex-col flex-1 min-h-0",children:[e.jsxs("div",{className:"flex items-end justify-between",children:[e.jsx("div",{className:"flex-1",children:!Y&&$.length>1&&e.jsx(ws,{fragments:$,aggregates:R,activeOrigin:(P==null?void 0:P.origin.role)??null,onSelect:v})}),ne.length>0&&e.jsx("div",{className:"px-4 pt-2 pb-0.5",children:e.jsx(Jt,{lenses:ne,activeLens:Y,stationCount:L.length,onSelect:l})})]}),Y?e.jsx(Zt,{entityKey:Y,periodHours:Re[t],roles:q,find:O,onFindChange:A,entityValue:S,onEntityChange:U,sliceKey:Z,onSliceKeyChange:D,sliceValue:W,onSliceValueChange:J},Y):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex-1 min-h-[40vh] flex items-stretch overflow-hidden",children:[e.jsxs("div",{className:"flex-1 min-w-0 min-h-0 flex flex-col overflow-hidden px-2 py-4",children:[e.jsx("div",{className:"flex items-center justify-center gap-0.5 pb-2 shrink-0",children:["lin","log"].map(u=>e.jsx("button",{onClick:()=>o(u==="log"),className:`px-2 py-0.5 text-2xs font-mono rounded transition-colors ${(n?"log":"lin")===u?"text-accent font-semibold":"icon-link"}`,title:u==="lin"?"Linear Y axis":"Logarithmic Y axis — reveals shape across wide value ranges",children:u},u))}),e.jsx("div",{className:"flex-1 min-h-0 flex flex-col justify-center overflow-hidden",children:e.jsx(is,{stations:_,selectedRole:r,onSelect:ae,onUpstreamSelect:se,onCmdClick:u=>X(`/escalations/available?role=${encodeURIComponent(u)}`),periodHours:Re[t],logScale:n})})]}),e.jsx("div",{className:"w-px bg-surface-border shrink-0 self-stretch"}),e.jsx(hs,{role:xe,allMetrics:ve,orderedRoles:L.map(u=>u.role),globalPeriod:t,mixGroups:z==null?void 0:z.groups,onClose:()=>i(null)})]}),e.jsx("div",{className:"max-h-[30vh] flex-none overflow-y-auto border-t border-surface-border",children:e.jsxs("table",{className:"w-full table-fixed",children:[e.jsx(ks,{}),e.jsx("tbody",{children:L.map(({role:u})=>e.jsx(bs,{role:u,metric:k.find(N=>N.role===u.role),mixGroups:H.get(u.role),mixColors:fe.get(u.role)??T,selected:r===u.role,periodHours:Re[t],onClick:()=>ae(u.role)},u.role))})]})})]})]})]})}const Ls=Object.freeze(Object.defineProperty({__proto__:null,OperationsPage:$s,buildFragments:De},Symbol.toStringTag,{value:"Module"}));export{Ls as O,is as P,De as b,ft as j};
|
|
3
|
-
//# sourceMappingURL=OperationsPage-Bsrt4XTL.js.map
|