@hotmeshio/long-tail 0.30.4 → 0.30.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/api/escalations/index.d.ts +1 -0
- package/build/api/escalations/index.js +5 -2
- package/build/api/escalations/roster-action.d.ts +11 -0
- package/build/api/escalations/roster-action.js +47 -30
- package/build/api/escalations/roster-scan.d.ts +26 -0
- package/build/api/escalations/roster-scan.js +114 -0
- package/build/api/scan-codes/context.d.ts +9 -1
- package/build/api/scan-codes/context.js +16 -1
- package/build/api/scan-codes/execute.js +6 -1
- package/build/api/scan-codes/fill-labels.d.ts +8 -0
- package/build/api/scan-codes/fill-labels.js +23 -2
- package/build/api/scan-codes/hold.js +2 -0
- package/build/api/scan-codes/located.d.ts +10 -0
- package/build/api/scan-codes/located.js +74 -0
- package/build/api/scan-codes/open.d.ts +9 -0
- package/build/api/scan-codes/open.js +99 -0
- package/build/api/scan-codes/present.js +1 -0
- package/build/api/scan-codes/verb-fill.js +1 -1
- package/build/routes/escalations/resolve.js +18 -0
- package/build/services/role/index.d.ts +2 -0
- package/build/services/role/index.js +7 -0
- package/build/services/role/scan-done.js +4 -1
- package/build/services/role/sql.d.ts +1 -0
- package/build/services/role/sql.js +3 -1
- package/build/services/role/types.d.ts +2 -0
- package/build/services/scan-code/index.d.ts +1 -1
- package/build/services/scan-code/index.js +2 -1
- package/build/services/scan-code/parse.d.ts +5 -1
- package/build/services/scan-code/parse.js +8 -2
- package/build/services/scan-code/validate-station.d.ts +13 -0
- package/build/services/scan-code/validate-station.js +81 -0
- package/build/services/scan-code/validate-subject.js +33 -6
- package/build/services/scan-code/validate.js +12 -18
- package/build/system/mcp-servers/admin/schemas.d.ts +471 -4
- package/build/system/mcp-servers/admin/schemas.js +32 -4
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/index.d.ts +1 -1
- package/build/types/scan-choice.d.ts +2 -4
- package/build/types/scan-code/constants.d.ts +1 -0
- package/build/types/scan-code/constants.js +1 -0
- package/build/types/scan-code/response.d.ts +22 -4
- package/build/types/scan-code/rule.d.ts +61 -3
- package/dashboard/dist/assets/{AdminDashboard-VQ1fhhJP.js → AdminDashboard-D12QiMM5.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-VQ1fhhJP.js.map → AdminDashboard-D12QiMM5.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-BOe_W2Ij.js → AgentConfigPage-BKQd9b8m.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-BOe_W2Ij.js.map → AgentConfigPage-BKQd9b8m.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-5ov5D9V2.js → AgentDetailPage-ie-DxsIj.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-5ov5D9V2.js.map → AgentDetailPage-ie-DxsIj.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-DDFMKHhI.js → AgentsPage-Nqm2DxCP.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-DDFMKHhI.js.map → AgentsPage-Nqm2DxCP.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-GFn8Sgg1.js → AvailableEscalationsPage-BRKyG5qZ.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-GFn8Sgg1.js.map → AvailableEscalationsPage-BRKyG5qZ.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-Dqpo36dM.js → BotPicker-BizdmeJp.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-Dqpo36dM.js.map → BotPicker-BizdmeJp.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-CmLVxkz-.js → BulkAssignModal-BWfzPrRk.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-CmLVxkz-.js.map → BulkAssignModal-BWfzPrRk.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-Dfkip6_b.js → CapabilitiesPage-DT8q7Zlh.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-Dfkip6_b.js.map → CapabilitiesPage-DT8q7Zlh.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-CYNYMYSa.js → CollapsibleSection-al5mqR4O.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-CYNYMYSa.js.map → CollapsibleSection-al5mqR4O.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-CpJNP-8w.js → ConfirmDeleteModal-BrlVktv2.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-CpJNP-8w.js.map → ConfirmDeleteModal-BrlVktv2.js.map} +1 -1
- package/dashboard/dist/assets/{ConnectedAppsPage-DXIp2Dpl.js → ConnectedAppsPage-CLAsJ2yQ.js} +2 -2
- package/dashboard/dist/assets/{ConnectedAppsPage-DXIp2Dpl.js.map → ConnectedAppsPage-CLAsJ2yQ.js.map} +1 -1
- package/dashboard/dist/assets/{CountdownTimer-CuPY7zkb.js → CountdownTimer-D2D68exl.js} +2 -2
- package/dashboard/dist/assets/{CountdownTimer-CuPY7zkb.js.map → CountdownTimer-D2D68exl.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-CtrnkHcj.js → CredentialsPage-DWrZbEI0.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-CtrnkHcj.js.map → CredentialsPage-DWrZbEI0.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-DVjTw5Ri.js → CronLabel-DuXR8iWq.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-DVjTw5Ri.js.map → CronLabel-DuXR8iWq.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-gY_mGMTF.js → ElapsedCell-ronqG5-E.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-gY_mGMTF.js.map → ElapsedCell-ronqG5-E.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-DJN_ZEQa.js → EntityTimelinePanel-CKsktd84.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-DJN_ZEQa.js.map → EntityTimelinePanel-CKsktd84.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-A4KpTdJA.js → EscalationListSchemaPage-C954ngy3.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-A4KpTdJA.js.map → EscalationListSchemaPage-C954ngy3.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-nfCn42hT.js → EscalationSchemaPage-Dij9K0ON.js} +2 -2
- package/dashboard/dist/assets/{EscalationSchemaPage-nfCn42hT.js.map → EscalationSchemaPage-Dij9K0ON.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTimeline-CLvSr1SD.js → EscalationTimeline-DT2Owdl0.js} +2 -2
- package/dashboard/dist/assets/{EscalationTimeline-CLvSr1SD.js.map → EscalationTimeline-DT2Owdl0.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTitleSelect-CT7mYHkb.js → EscalationTitleSelect-BdbfMA98.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-CT7mYHkb.js.map → EscalationTitleSelect-BdbfMA98.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-CKaGRh-E.js → EscalationsOverview-niahs84P.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-CKaGRh-E.js.map → EscalationsOverview-niahs84P.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-2ywJsOLy.js → EventTable-DuLMBrSx.js} +2 -2
- package/dashboard/dist/assets/{EventTable-2ywJsOLy.js.map → EventTable-DuLMBrSx.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-Dy0b7wwf.js → FilterBar-jtY6KNpL.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-Dy0b7wwf.js.map → FilterBar-jtY6KNpL.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-yOVpraAy.js → GraphInvokePage-DSRAI0Zt.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-yOVpraAy.js.map → GraphInvokePage-DSRAI0Zt.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-67xXjKjN.js → HomePage-BUlSnCg8.js} +2 -2
- package/dashboard/dist/assets/{HomePage-67xXjKjN.js.map → HomePage-BUlSnCg8.js.map} +1 -1
- package/dashboard/dist/assets/{LinePage-CMsYtukW.js → LinePage-BJKhVM9Y.js} +3 -3
- package/dashboard/dist/assets/{LinePage-CMsYtukW.js.map → LinePage-BJKhVM9Y.js.map} +1 -1
- package/dashboard/dist/assets/{LinesPage-pwL46mOS.js → LinesPage-CrpJua3_.js} +3 -3
- package/dashboard/dist/assets/{LinesPage-pwL46mOS.js.map → LinesPage-CrpJua3_.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-CJmvGy2B.js → ListToolbar-BN0UPt0L.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-CJmvGy2B.js.map → ListToolbar-BN0UPt0L.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-DA9LLvNG.js → McpOverview-BgbJXYPh.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-DA9LLvNG.js.map → McpOverview-BgbJXYPh.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-N7qLmfE8.js → McpQueryDetailPage-BNjm2nrc.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-N7qLmfE8.js.map → McpQueryDetailPage-BNjm2nrc.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-CpsP3w7x.js → McpQueryPage-DplR8wP9.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-CpsP3w7x.js.map → McpQueryPage-DplR8wP9.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-qHRQ1pEY.js → McpRunDetailPage-BHVEcKV5.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-qHRQ1pEY.js.map → McpRunDetailPage-BHVEcKV5.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-BRDDYpTM.js → McpRunsPage-CtlLagcs.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-BRDDYpTM.js.map → McpRunsPage-CtlLagcs.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-zUaab-CL.js → OperationsPage-DH67bcW9.js} +3 -3
- package/dashboard/dist/assets/{OperationsPage-zUaab-CL.js.map → OperationsPage-DH67bcW9.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-el5BquXN.js → OperatorDashboard-CMkgMewd.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-el5BquXN.js.map → OperatorDashboard-CMkgMewd.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-B_tb8gfl.js → PersonaDetailPage-Cs1FFdNq.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-B_tb8gfl.js.map → PersonaDetailPage-Cs1FFdNq.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-BPI7mqM8.js → PersonasPage-CHTRdneF.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-BPI7mqM8.js.map → PersonasPage-CHTRdneF.js.map} +1 -1
- package/dashboard/dist/assets/{PortalPage-e_rBb1do.js → PortalPage-ChB5pBTZ.js} +2 -2
- package/dashboard/dist/assets/{PortalPage-e_rBb1do.js.map → PortalPage-ChB5pBTZ.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-D35RX1bB.js → ProcessDetailPage-CzyqSfal.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-D35RX1bB.js.map → ProcessDetailPage-CzyqSfal.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-CT81miI5.js → ProcessesListPage-rOwNkaU9.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-CT81miI5.js.map → ProcessesListPage-rOwNkaU9.js.map} +1 -1
- package/dashboard/dist/assets/{ResolverForm-BxJkoKAO.js → ResolverForm-DibnlZ-A.js} +2 -2
- package/dashboard/dist/assets/{ResolverForm-BxJkoKAO.js.map → ResolverForm-DibnlZ-A.js.map} +1 -1
- package/dashboard/dist/assets/{RoleDetailPage-DtU7vsJm.js → RoleDetailPage-Bv9R7iQC.js} +3 -3
- package/dashboard/dist/assets/{RoleDetailPage-DtU7vsJm.js.map → RoleDetailPage-Bv9R7iQC.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-BE7RWt9q.js → RolesPage-CUP7EH5U.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-BE7RWt9q.js.map → RolesPage-CUP7EH5U.js.map} +1 -1
- package/dashboard/dist/assets/{RosterWidget-BJMx0a8Z.js → RosterWidget-DZtmQcjU.js} +2 -2
- package/dashboard/dist/assets/RosterWidget-DZtmQcjU.js.map +1 -0
- package/dashboard/dist/assets/{RunAsSelector-Co6s9bqA.js → RunAsSelector-B9-1vgZr.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-Co6s9bqA.js.map → RunAsSelector-B9-1vgZr.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-C2TETaj5.js → ScanCodesPage-KN_e2rJl.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-C2TETaj5.js.map → ScanCodesPage-KN_e2rJl.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-C2UgU8l-.js → ScanSchemeDetailPage-CqItQ67Y.js} +4 -4
- package/dashboard/dist/assets/{ScanSchemeDetailPage-C2UgU8l-.js.map → ScanSchemeDetailPage-CqItQ67Y.js.map} +1 -1
- package/dashboard/dist/assets/ScanStationPage-B0qbUOwc.js +2 -0
- package/dashboard/dist/assets/ScanStationPage-B0qbUOwc.js.map +1 -0
- package/dashboard/dist/assets/{SchemeMatchFields-9H7SmbED.js → SchemeMatchFields-CL7TKnw3.js} +2 -2
- package/dashboard/dist/assets/{SchemeMatchFields-9H7SmbED.js.map → SchemeMatchFields-CL7TKnw3.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-miUdVAKw.js → StickyPagination-CUwxfBQH.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-miUdVAKw.js.map → StickyPagination-CUwxfBQH.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-D5Rk7pn7.js → StreamMessageDetail-DOjcO7d2.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-D5Rk7pn7.js.map → StreamMessageDetail-DOjcO7d2.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-B1QY1ZzH.js → SwimlaneTimeline-SPMpoLHP.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-B1QY1ZzH.js.map → SwimlaneTimeline-SPMpoLHP.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-DKUM37o8.js → TaskDetailPage-DvfzR2IQ.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-DKUM37o8.js.map → TaskDetailPage-DvfzR2IQ.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-CUulwvm-.js → TasksListPage-Jp6wmL7t.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-CUulwvm-.js.map → TasksListPage-Jp6wmL7t.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-CHTelacB.js → TimeAgo-BCQA0Gb_.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-CHTelacB.js.map → TimeAgo-BCQA0Gb_.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-NanLWLKo.js → TimestampCell-xhdMHDQt.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-NanLWLKo.js.map → TimestampCell-xhdMHDQt.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-CF1CHzgz.js → ToolTestPanel-D8M3ITrJ.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-CF1CHzgz.js.map → ToolTestPanel-D8M3ITrJ.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-CGO8XV_a.js → TopicDetailPage-DdBJQp31.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-CGO8XV_a.js.map → TopicDetailPage-DdBJQp31.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-Bt8gOKYr.js → TopicsPage-vpvsynD9.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-Bt8gOKYr.js.map → TopicsPage-vpvsynD9.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-DKXnK7DD.js → UserName-BK6Lzsdw.js} +2 -2
- package/dashboard/dist/assets/{UserName-DKXnK7DD.js.map → UserName-BK6Lzsdw.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-Crf7AIFc.js → WorkflowExecutionPage-DkM1TS4I.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-Crf7AIFc.js.map → WorkflowExecutionPage-DkM1TS4I.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard--isjt06C.js → WorkflowsDashboard-g_N4y3QS.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard--isjt06C.js.map → WorkflowsDashboard-g_N4y3QS.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-D7Oqf4-V.js → WorkflowsOverview-Drjo-Lu-.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-D7Oqf4-V.js.map → WorkflowsOverview-Drjo-Lu-.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-B0wxgrGP.js → YamlWorkflowDetailPage-CLltNHjZ.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-B0wxgrGP.js.map → YamlWorkflowDetailPage-CLltNHjZ.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-BVdLnm6K.js → YamlWorkflowsPage-CxQCB-Zi.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-BVdLnm6K.js.map → YamlWorkflowsPage-CxQCB-Zi.js.map} +1 -1
- package/dashboard/dist/assets/{agents-CHjbjHXA.js → agents-Dk25jjhj.js} +2 -2
- package/dashboard/dist/assets/{agents-CHjbjHXA.js.map → agents-Dk25jjhj.js.map} +1 -1
- package/dashboard/dist/assets/{bots-WrUhEPWs.js → bots-bRkCqhlq.js} +2 -2
- package/dashboard/dist/assets/{bots-WrUhEPWs.js.map → bots-bRkCqhlq.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-CunMmkj8.js → capabilities-DARawLry.js} +2 -2
- package/dashboard/dist/assets/{capabilities-CunMmkj8.js.map → capabilities-DARawLry.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-D6IZIZoh.js → controlplane-DKccxxs6.js} +2 -2
- package/dashboard/dist/assets/{controlplane-D6IZIZoh.js.map → controlplane-DKccxxs6.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-Bvo6JI4Z.js → escalation-columns-BaYuzMYf.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-Bvo6JI4Z.js.map → escalation-columns-BaYuzMYf.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-items-DFGRwo49.js → escalation-items-CwbNFnsH.js} +2 -2
- package/dashboard/dist/assets/{escalation-items-DFGRwo49.js.map → escalation-items-CwbNFnsH.js.map} +1 -1
- package/dashboard/dist/assets/{index-B8qrHwp9.js → index-BZgtzkkG.js} +2 -2
- package/dashboard/dist/assets/{index-B8qrHwp9.js.map → index-BZgtzkkG.js.map} +1 -1
- package/dashboard/dist/assets/{index-DRw0FXdX.js → index-Bx9HVzuT.js} +2 -2
- package/dashboard/dist/assets/{index-DRw0FXdX.js.map → index-Bx9HVzuT.js.map} +1 -1
- package/dashboard/dist/assets/{index-ygxyAKcc.js → index-CU2UW2y6.js} +14 -14
- package/dashboard/dist/assets/index-CU2UW2y6.js.map +1 -0
- package/dashboard/dist/assets/{index-OuKQ_0eB.js → index-Cf6qCgTf.js} +2 -2
- package/dashboard/dist/assets/{index-OuKQ_0eB.js.map → index-Cf6qCgTf.js.map} +1 -1
- package/dashboard/dist/assets/{index-DRK7M1_9.js → index-CtrSYqmL.js} +2 -2
- package/dashboard/dist/assets/{index-DRK7M1_9.js.map → index-CtrSYqmL.js.map} +1 -1
- package/dashboard/dist/assets/{index-Bo8QU31k.js → index-D1uliPqS.js} +2 -2
- package/dashboard/dist/assets/{index-Bo8QU31k.js.map → index-D1uliPqS.js.map} +1 -1
- package/dashboard/dist/assets/{index-B95LbYhW.js → index-DU-1gMks.js} +2 -2
- package/dashboard/dist/assets/{index-B95LbYhW.js.map → index-DU-1gMks.js.map} +1 -1
- package/dashboard/dist/assets/{index-CpCchhQv.js → index-DU2QCbgH.js} +2 -2
- package/dashboard/dist/assets/{index-CpCchhQv.js.map → index-DU2QCbgH.js.map} +1 -1
- package/dashboard/dist/assets/{index-BZFSXEkr.js → index-DgpL_Lgc.js} +2 -2
- package/dashboard/dist/assets/{index-BZFSXEkr.js.map → index-DgpL_Lgc.js.map} +1 -1
- package/dashboard/dist/assets/{index-boT612Jo.js → index-E_hJ7vtX.js} +2 -2
- package/dashboard/dist/assets/{index-boT612Jo.js.map → index-E_hJ7vtX.js.map} +1 -1
- package/dashboard/dist/assets/{index-DCJ483vt.js → index-dShcvdg3.js} +2 -2
- package/dashboard/dist/assets/{index-DCJ483vt.js.map → index-dShcvdg3.js.map} +1 -1
- package/dashboard/dist/assets/{index-C7EIu1mG.js → index-hKOlahpE.js} +2 -2
- package/dashboard/dist/assets/{index-C7EIu1mG.js.map → index-hKOlahpE.js.map} +1 -1
- package/dashboard/dist/assets/index-kzifJWbM.js +3 -0
- package/dashboard/dist/assets/index-kzifJWbM.js.map +1 -0
- package/dashboard/dist/assets/{knowledge-BubJBTwg.js → knowledge-DOe5ks-E.js} +2 -2
- package/dashboard/dist/assets/{knowledge-BubJBTwg.js.map → knowledge-DOe5ks-E.js.map} +1 -1
- package/dashboard/dist/assets/{machines-DSm5NFgs.js → machines-Zq_00v7k.js} +2 -2
- package/dashboard/dist/assets/{machines-DSm5NFgs.js.map → machines-Zq_00v7k.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-D6MckqOV.js → mcp-BL8kD0oh.js} +2 -2
- package/dashboard/dist/assets/{mcp-D6MckqOV.js.map → mcp-BL8kD0oh.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-VyCdOag6.js → mcp-query-BpokmJWi.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-VyCdOag6.js.map → mcp-query-BpokmJWi.js.map} +1 -1
- package/dashboard/dist/assets/{personas-CyJc10xe.js → personas-BubCnQZ8.js} +2 -2
- package/dashboard/dist/assets/{personas-CyJc10xe.js.map → personas-BubCnQZ8.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-B2inDtx3.js → pipelines--DUoMx7K.js} +2 -2
- package/dashboard/dist/assets/{pipelines-B2inDtx3.js.map → pipelines--DUoMx7K.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-DOP4d3M6.js → tasks-CJXN4OB4.js} +2 -2
- package/dashboard/dist/assets/{tasks-DOP4d3M6.js.map → tasks-CJXN4OB4.js.map} +1 -1
- package/dashboard/dist/assets/{topics-CNOjSWpX.js → topics-CAG08Ruo.js} +2 -2
- package/dashboard/dist/assets/{topics-CNOjSWpX.js.map → topics-CAG08Ruo.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-CgO0TGMd.js → useDebouncedValue-DQ2D8cm2.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-CgO0TGMd.js.map → useDebouncedValue-DQ2D8cm2.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-BWHvUKtK.js → useNamespace-DjEVAlJQ.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-BWHvUKtK.js.map → useNamespace-DjEVAlJQ.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-BZQ__ZGD.js → useYamlActivityEvents-etcpfIwo.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-BZQ__ZGD.js.map → useYamlActivityEvents-etcpfIwo.js.map} +1 -1
- package/dashboard/dist/assets/{validate-CAin6WM_.js → validate-YJK_6a7m.js} +2 -2
- package/dashboard/dist/assets/{validate-CAin6WM_.js.map → validate-YJK_6a7m.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-Dyln3od-.js → yaml-workflows-D97Bz6li.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-Dyln3od-.js.map → yaml-workflows-D97Bz6li.js.map} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/docs/api/http/escalations.md +15 -0
- package/docs/dashboard.md +2 -2
- package/docs/hitl/x-lt-roster.md +2 -0
- package/docs/hitl/x-lt-scan.md +12 -0
- package/docs/scan-codes.md +81 -3
- package/package.json +1 -1
- package/dashboard/dist/assets/RosterWidget-BJMx0a8Z.js.map +0 -1
- package/dashboard/dist/assets/ScanStationPage-nWYz-OD3.js +0 -2
- package/dashboard/dist/assets/ScanStationPage-nWYz-OD3.js.map +0 -1
- package/dashboard/dist/assets/index-P-DlgAWj.js +0 -3
- package/dashboard/dist/assets/index-P-DlgAWj.js.map +0 -1
- package/dashboard/dist/assets/index-ygxyAKcc.js.map +0 -1
package/docs/scan-codes.md
CHANGED
|
@@ -273,6 +273,10 @@ receives the raw value and renders it with the list's formatter, so an ISO
|
|
|
273
273
|
instant in metadata reads the same on the station as in a list column (and
|
|
274
274
|
in the deployment's display time zone, when one is set).
|
|
275
275
|
|
|
276
|
+
`show` names a [roster](hitl/x-lt-roster.md) field of the row's form, rendered
|
|
277
|
+
above the choices as a hold renders it: an arrival screen lists what came in
|
|
278
|
+
the container before the person taps Arrive.
|
|
279
|
+
|
|
276
280
|
Without `facts`, the station lists the row's metadata, leaving out the
|
|
277
281
|
bookkeeping a bench never acts on: scan provenance (`scannedAt`,
|
|
278
282
|
`scanScheme`, `scanCategory`, `scanStation`, `scanActionName`),
|
|
@@ -358,7 +362,10 @@ set one ("Take the new label from the printer and stick it on C-12").
|
|
|
358
362
|
Any step that writes may carry `done: { markdown }`: the copy the station shows,
|
|
359
363
|
large, once the write lands and until the next scan ("Place it in
|
|
360
364
|
**{container.containerCode}**. All good."). It reads the same bags its refusal copy
|
|
361
|
-
reads.
|
|
365
|
+
reads. `done.afterSeconds` (0-60) sets how long this act's copy stays up before
|
|
366
|
+
the station returns, over the role's `scan_done.after_seconds`, and
|
|
367
|
+
`done.nextPrompt` replaces the "Scan the next item" line under it when the next
|
|
368
|
+
act is not a scan ("Set the bag in tub **{container.tubCode}**"). A fill or an into-subject add that leaves slots open shows its done
|
|
362
369
|
copy under the hold; without done copy the station shows the count ("2 of 5
|
|
363
370
|
checked off" for a fill, "2 of 5 added" for an add).
|
|
364
371
|
|
|
@@ -375,6 +382,22 @@ unchanged.
|
|
|
375
382
|
"show": "shoes" } }
|
|
376
383
|
```
|
|
377
384
|
|
|
385
|
+
**Ending the hold.** The hold card's button lets go of the item. By default it
|
|
386
|
+
reads "Put it down" and the station stays where it is. `hold.release` names it
|
|
387
|
+
for the bench: `label`, `tone: "accent"` to draw it as the screen's primary act,
|
|
388
|
+
and `return` (`home` or a dashboard route) for where the station goes once
|
|
389
|
+
released. Releasing writes nothing: items not yet scanned simply wait for the
|
|
390
|
+
next trip. With `hold.show`, `hold.whenAllIn` ends the hold on its own once
|
|
391
|
+
every entry on the roster is in. The station shows its done copy
|
|
392
|
+
(`markdown`, `afterSeconds`, `nextPrompt`, rendered against the held row), then
|
|
393
|
+
returns as after a completed act.
|
|
394
|
+
|
|
395
|
+
```jsonc
|
|
396
|
+
"params": { "hold": { "label": "{item.tubCode}", "show": "bags",
|
|
397
|
+
"release": { "label": "I'm done", "tone": "accent", "return": "home" },
|
|
398
|
+
"whenAllIn": { "markdown": "Every bag is in **{item.tubCode}**.", "afterSeconds": 5 } } }
|
|
399
|
+
```
|
|
400
|
+
|
|
378
401
|
The server trusts nothing about the subject. Each request re-parses its
|
|
379
402
|
code, re-reads the row under the station's read scope, requires the row to
|
|
380
403
|
still carry the code's target and to be pending. A subject that fails is
|
|
@@ -418,6 +441,19 @@ printed code. With them, `{fill.pending}` lists the open entries by label,
|
|
|
418
441
|
refusal's `expected` reads the labels. An entry the map does not name reads as
|
|
419
442
|
its code; without `fill.labels`, both tokens read codes.
|
|
420
443
|
|
|
444
|
+
**Which key a fill takes.** A scan fills the first open key for its code, in
|
|
445
|
+
the row's order. When the same code is expected under several keys that each
|
|
446
|
+
belong to something the station can hold (two boxes of one item arriving in
|
|
447
|
+
two parcels), `fill.prefer` names a per-key map on the batch row naming the
|
|
448
|
+
value each key belongs to. Open keys whose value equals the held subject's
|
|
449
|
+
target (or, for a list value, contains it) fill first; the rest follow as
|
|
450
|
+
before. Held by parcel `P2`, scanning the item fills the key mapped to `P2`.
|
|
451
|
+
|
|
452
|
+
```jsonc
|
|
453
|
+
"params": { "fill": { "into": "subject", "prefer": "envelope.key_parcels" } }
|
|
454
|
+
// the row's envelope: { "key_parcels": { "<code>#1": "P1", "<code>#2": "P2" } }
|
|
455
|
+
```
|
|
456
|
+
|
|
421
457
|
```jsonc
|
|
422
458
|
"refuse": { "markdown": "Not one of this order's shoes. Still to match: {fill.pending}." },
|
|
423
459
|
"done": { "markdown": "Matched. Next: {fill.next}" },
|
|
@@ -443,6 +479,14 @@ declares `refuse.conflict` also clears the subject so the next item scan
|
|
|
443
479
|
reads fresh state. Exactly one of two racing acts wins whenever both name
|
|
444
480
|
the same row: the reciprocal statement writes both rows or neither.
|
|
445
481
|
|
|
482
|
+
**Where the scanned item is now.** Refusal and done copy may read
|
|
483
|
+
`{located.<facet>}`: the scanned code's own pending row, the newest one in any
|
|
484
|
+
role the reader may read (the held row excepted). Besides the row's facets it
|
|
485
|
+
carries `id`, `role` and `roleTitle` (the role's title, else its name), so a
|
|
486
|
+
refusal can say where the item belongs: "This bag is at
|
|
487
|
+
**{located.roleTitle}**." The row is read only for a step whose copy or Open
|
|
488
|
+
names it; with no such row the token renders empty.
|
|
489
|
+
|
|
446
490
|
**The item's own row on an into-subject add.** A held container that collects
|
|
447
491
|
item codes (a box being packed from a bin) often has items that each wait on
|
|
448
492
|
their own row. `accumulate.item` locates that row and writes it as the
|
|
@@ -633,6 +677,30 @@ Pair kiosk with `x-lt-transition-done` on the role's form schema
|
|
|
633
677
|
resolve lands back on the list rather than walking browser history — see
|
|
634
678
|
[x-lt-transition](./hitl/x-lt-transition.md).
|
|
635
679
|
|
|
680
|
+
### Open: from a scan result into its row
|
|
681
|
+
|
|
682
|
+
The station's answer stays light (right container or wrong one), but the moment
|
|
683
|
+
something is off the person needs the full form. A step's `open` puts an
|
|
684
|
+
**Open** button on the hold card, the done screen or the refusal it answers with:
|
|
685
|
+
|
|
686
|
+
```jsonc
|
|
687
|
+
"open": { "target": "subject", "claim": true }
|
|
688
|
+
"open": { "target": "row", "label": "Open the bin", "list": { "facets": ["binCode"], "role": "binning" } }
|
|
689
|
+
"open": { "target": "located", "label": "Where it is" }
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
`target` is the row the step acted on or located (`row`), the held row
|
|
693
|
+
(`subject`, on a hold the row just held), or the scanned code's own pending row
|
|
694
|
+
(`located`). Open lands on that row's detail page, in the app. With `list`, it
|
|
695
|
+
lands on the faceted list of rows sharing those facets with the target, the
|
|
696
|
+
values read from the target row on the server. With `claim`, the row is claimed
|
|
697
|
+
first as the person acting (the badge rides the claim) and opens claimed in
|
|
698
|
+
their name; a claim the server refuses (no badge, a scope that does not cover
|
|
699
|
+
it, someone else's claim) still opens the row, read-only, where the detail page
|
|
700
|
+
offers its own Claim. Opening from a hold lets go of the item. A target with no
|
|
701
|
+
row, or a list facet the row does not carry, offers no button. Every decision
|
|
702
|
+
(reject, missing, done) stays on the detail form.
|
|
703
|
+
|
|
636
704
|
### After a scan completes: the return
|
|
637
705
|
|
|
638
706
|
A station works in one rhythm: badge, item, destination, done, back to the
|
|
@@ -644,7 +712,9 @@ list. A role names the last step in `properties.scan_done`:
|
|
|
644
712
|
|
|
645
713
|
`return` is `home` (the role's kiosk home: its first portal, else its list) or
|
|
646
714
|
a dashboard-relative route; `after_seconds` (0-60, default 2) is how long the
|
|
647
|
-
done copy stays up first
|
|
715
|
+
done copy stays up first, and a step's `done.afterSeconds` sets it for one act.
|
|
716
|
+
The done screen counts the seconds down. `button` (e.g. `"Done"`) adds a button
|
|
717
|
+
that returns at once. The station returns once a scan act completes its
|
|
648
718
|
row: the last fill of a batch, an executed choice with done copy, any write
|
|
649
719
|
that clears the subject. A fill that leaves entries pending stays on the hold
|
|
650
720
|
card, a refusal never returns, and a `follow` runs first. A station holding
|
|
@@ -687,6 +757,11 @@ submit for ten minutes. A grant bound to a scanned subject (`grant_scope:
|
|
|
687
757
|
locally, so the identity gate sits at the one place a record actually
|
|
688
758
|
changes, once per change.
|
|
689
759
|
|
|
760
|
+
Claiming at a station works the same way. On a read-only station login, the
|
|
761
|
+
detail page's Claim asks for a badge and claims as whoever badges in; the badge
|
|
762
|
+
then stays primed for the work on the row, bounded by its grant's own uses and
|
|
763
|
+
lifetime. A claim the server refuses says why on the claim bar.
|
|
764
|
+
|
|
690
765
|
Mutations attribute to the badged person (`assigned_to`, `resolved_by`)
|
|
691
766
|
with the device recorded beside them (`scanStation` in the scan
|
|
692
767
|
provenance) — every action individually owned and geographically placed.
|
|
@@ -708,7 +783,10 @@ A field can take a scan while the form is open: with
|
|
|
708
783
|
[`x-lt-scan`](hitl/x-lt-scan.md), scanning a container into a claimed form
|
|
709
784
|
fills its container field (checked against what the record expects), and
|
|
710
785
|
`x-lt-scan-submit` submits once the scan fields are filled, which raises the
|
|
711
|
-
badge prompt. A
|
|
786
|
+
badge prompt. A batch [roster](hitl/x-lt-roster.md) that declares `x-lt-scan`
|
|
787
|
+
checks its entries off the same way: a scan of an accepted scheme, with nothing
|
|
788
|
+
focused, fills the row's first open entry for that code on the server, as the
|
|
789
|
+
person acting. A scan no field accepts runs globally as usual.
|
|
712
790
|
|
|
713
791
|
Badge tokens are printed credentials: seed them as long random strings,
|
|
714
792
|
bind them server-side (`lt_users.metadata`), and treat badge possession
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"RosterWidget-BJMx0a8Z.js","sources":["../../../shared/form-validation/ctx-path.ts","../../../shared/form-validation/x-lt-show-if.ts","../../src/components/escalation/resolver-form/FieldChrome.tsx","../../src/components/escalation/widgets/OpenDetailButton.tsx","../../src/components/escalation/widgets/InlineConfirm.tsx","../../src/components/escalation/widgets/embed-write.ts","../../src/components/escalation/widgets/InlineCodeEntry.tsx","../../../shared/form-validation/x-lt-roster.ts","../../src/components/escalation/widgets/RosterEntryRow.tsx","../../src/hooks/useRosters.ts","../../../shared/form-validation/x-lt-actions.ts","../../src/components/escalation/widgets/RosterWidget.tsx"],"sourcesContent":["/**\n * Context-path resolution shared by every token that names a `\"domain.path\"`.\n *\n * A path may embed `{{domain.path}}` interpolation segments — the same\n * grammar as x-lt-help tokens — resolved against the live context before the\n * walk. This is what makes cascading selects work: a field can declare\n *\n * x-lt-options: \"lookup.geo.regions.{{resolver.country}}\"\n *\n * and its option list follows the submitter's country answer, re-resolved\n * locally on every edit. An unresolved segment means \"no concrete path yet\",\n * never a literal placeholder.\n */\nimport { getDeep } from './x-lt-bind';\n\nexport const INTERPOLATION_PATTERN = /\\{\\{\\s*([^{}]+?)\\s*\\}\\}/g;\n\n/** Whether a token embeds `{{domain.path}}` interpolation segments. */\nexport function hasInterpolation(token: unknown): token is string {\n return typeof token === 'string' && /\\{\\{[^{}]+\\}\\}/.test(token);\n}\n\n/** Resolve a concrete `\"domain.path\"` (x-lt-bind syntax, `a.b[0].c`) against the context. */\nexport function resolveCtxPath(\n path: string,\n ctx: Record<string, unknown> | undefined,\n): unknown {\n if (!ctx) return undefined;\n const dot = path.indexOf('.');\n const root = ctx[dot === -1 ? path : path.slice(0, dot)];\n if (dot === -1) return root;\n if (root === null || typeof root !== 'object') return undefined;\n return getDeep(root, path.slice(dot + 1));\n}\n\n/**\n * Interpolate every `{{domain.path}}` segment against the context. Returns\n * the concrete path, or null when any segment resolves to nothing (missing,\n * null, empty string) or to a non-scalar — an unanswered cascade parent\n * yields no path, so the dependent field offers nothing.\n */\nexport function interpolatePath(\n template: string,\n ctx: Record<string, unknown> | undefined,\n): string | null {\n let unresolved = false;\n const concrete = template.replace(INTERPOLATION_PATTERN, (_match, rawPath: string) => {\n const value = resolveCtxPath(rawPath, ctx);\n if (typeof value === 'string' && value.trim().length > 0) return value;\n if (typeof value === 'number' && Number.isFinite(value)) return String(value);\n unresolved = true;\n return '';\n });\n return unresolved ? null : concrete;\n}\n","/**\n * x-lt-showIf — conditional field visibility. A form_schema property may\n * declare `x-lt-showIf: \"domain.path\"` to show the field only when the value\n * at that path is present and truthy. Prefix `!` to invert: show when absent\n * or falsy.\n *\n * Equality forms compare the resolved value's string form:\n * \"domain.path=VALUE\" — show when String(value) equals VALUE\n * \"domain.path!=VALUE\" — show when it does not\n * An absent value compares as the empty string, so `=X` is false and `!=X` is\n * true when the path is missing. VALUE is the raw remainder after the operator\n * (trimmed; no quoting). The truthy/! forms are unchanged.\n *\n * Domains follow the same `domain.path` convention as x-lt-help tokens:\n * metadata — the escalation row's metadata dict\n * payload — the escalation context payload (escalation_payload)\n * envelope — the workflow-sent input envelope\n * escalation — top-level escalation row fields\n * resolver — the submitted resolver payload\n * roster (each roster field's counts: `roster.orders.outstanding=0`)\n *\n * A missing or non-string condition always shows the field (opt-in, safe default).\n */\nimport { getDeep } from './x-lt-bind';\nimport { HELP_DOMAINS, type HelpTokenContext } from './x-lt-help';\n\nexport type ShowIfContext = HelpTokenContext;\n\nfunction isTruthy(value: unknown): boolean {\n return value !== null && value !== undefined && value !== '' && value !== false && value !== 0;\n}\n\n/** The value's comparable string form; absent compares as the empty string. */\nfunction asComparable(value: unknown): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'object') return JSON.stringify(value);\n return String(value);\n}\n\nfunction resolvePath(expr: string, ctx: ShowIfContext): { known: boolean; value: unknown } {\n const dot = expr.indexOf('.');\n const domain = (dot === -1 ? expr : expr.slice(0, dot)) as (typeof HELP_DOMAINS)[number];\n if (!(HELP_DOMAINS as readonly string[]).includes(domain)) return { known: false, value: undefined };\n const root = ctx[domain];\n if (dot === -1) return { known: true, value: root };\n try {\n return { known: true, value: getDeep(root, expr.slice(dot + 1)) };\n } catch {\n return { known: true, value: undefined };\n }\n}\n\n/**\n * Evaluates an x-lt-showIf condition. Returns true when the field should be\n * shown. Returns true when condition is absent, non-string, or context is null.\n * An array of conditions shows the field only when every one holds.\n */\nexport function evaluateShowIf(condition: unknown, ctx: ShowIfContext | null | undefined): boolean {\n if (Array.isArray(condition)) return condition.every((c) => evaluateShowIf(c, ctx));\n if (typeof condition !== 'string' || condition.length === 0) return true;\n if (!ctx) return true;\n const negate = condition.startsWith('!');\n const expr = negate ? condition.slice(1) : condition;\n\n // Equality forms — `!=` first so it never parses as `=` with a `!` in the path.\n const neqAt = expr.indexOf('!=');\n const eqAt = expr.indexOf('=');\n if (neqAt !== -1 || (eqAt !== -1 && eqAt !== neqAt + 1)) {\n const isNeq = neqAt !== -1 && (eqAt === -1 || neqAt < eqAt);\n const opAt = isNeq ? neqAt : eqAt;\n const path = expr.slice(0, opAt).trim();\n const expected = expr.slice(opAt + (isNeq ? 2 : 1)).trim();\n const { known, value } = resolvePath(path, ctx);\n if (!known) return true; // unknown domain — safe default, same as truthy form\n const matches = asComparable(value) === expected;\n const result = isNeq ? !matches : matches;\n return negate ? !result : result;\n }\n\n const { known, value } = resolvePath(expr, ctx);\n if (!known) return true;\n return negate ? !isTruthy(value) : isTruthy(value);\n}\n\n/**\n * `x-lt-hide-if-empty`: the field is suppressed while its value is empty\n * (null, undefined, '', false, or 0). Render and validation share this test.\n */\nexport function isHiddenIfEmpty(fieldSchema: Record<string, unknown> | undefined, value: unknown): boolean {\n if (fieldSchema?.['x-lt-hide-if-empty'] !== true) return false;\n return value === null || value === undefined || value === '' || value === false || value === 0;\n}\n\n/**\n * `x-lt-hidden: true`: the field never renders. A value set by the caller\n * (a workflow default, an API submitter) passes through to the payload and\n * is checked against the field's type and enum; the field is never required,\n * since no one on the form can answer it.\n */\nexport const X_LT_HIDDEN = 'x-lt-hidden';\n\nexport function isHiddenField(fieldSchema: Record<string, unknown> | undefined): boolean {\n return fieldSchema?.[X_LT_HIDDEN] === true;\n}\n","/**\n * Shared field chrome for the resolver form: label, helper, error, and the\n * input class recipes. One place styles every generated field.\n */\n\nexport function FieldLabel({ children, isRequired, htmlFor }: {\n children: React.ReactNode;\n isRequired?: boolean;\n htmlFor?: string;\n}) {\n // `block` is load-bearing: a <label> is inline by default, and the\n // label→instruction→control anatomy would then hold only by accident —\n // a full-width control wraps below, but a narrow control (number,\n // max-w-48) with no instruction line sits flush BESIDE the label. The\n // anatomy is a column; the label declares it.\n return (\n <label htmlFor={htmlFor} className=\"block text-2xs font-semibold uppercase tracking-wider text-text-secondary\">\n {children}\n {isRequired && <span className=\"text-status-error ml-0.5\">*</span>}\n </label>\n );\n}\n\nexport function FieldHelper({ id, children }: { id?: string; children: React.ReactNode }) {\n return (\n <p id={id} className=\"text-2xs text-text-tertiary mt-0.5 leading-snug\">\n {children}\n </p>\n );\n}\n\nexport function FieldError({ error, id }: { error?: string; id?: string }) {\n if (!error) return null;\n return (\n <p id={id} role=\"alert\" className=\"text-2xs text-status-error mt-1 animate-[field-error-in_0.3s_ease-out]\">\n {error}\n </p>\n );\n}\n\nexport function inputClass(hasError?: boolean): string {\n return hasError\n ? 'input text-sm w-full mt-1 border-status-error/50 focus:border-status-error animate-[field-shake_0.4s_ease-in-out]'\n : 'input text-sm w-full mt-1';\n}\n\n// Select shares the field recipe but adds the unified chevron (via .select).\n// Width follows the content, floored for presence and capped by the cell —\n// a one-word choice never stretches across the measure. The floor is\n// min(16rem, 100%): CSS lets min-width beat max-width, so a bare min-w-64\n// would overflow a cell narrower than 16rem — the cell always wins.\nexport function selectClass(hasError?: boolean): string {\n return hasError\n ? 'select text-sm mt-1 min-w-[min(16rem,100%)] max-w-full border-status-error/50 focus:border-status-error animate-[field-shake_0.4s_ease-in-out]'\n : 'select text-sm mt-1 min-w-[min(16rem,100%)] max-w-full';\n}\n","import { Link } from 'react-router-dom';\nimport { ArrowUpRight } from 'lucide-react';\n\n/**\n * The one affordance for opening an embedded row's detail page — a clear\n * icon-in-a-button, not a bare glyph, so the gesture reads as \"open this\". The\n * tooltip stays generic (\"View details\") rather than naming the record kind, so\n * the same control fits any embed. Non-focusable: the row/card click and the\n * canned actions carry the keyboard path; this is a pointer shortcut.\n */\nexport function OpenDetailButton({ to, className = '' }: { to: string; className?: string }) {\n return (\n <Link\n to={to}\n title=\"View details\"\n tabIndex={-1}\n className={`inline-flex items-center justify-center w-6 h-6 shrink-0 rounded border border-surface-border text-accent/70 hover:text-accent hover:border-accent/60 hover:bg-accent/5 transition-colors ${className}`}\n >\n <ArrowUpRight className=\"w-3.5 h-3.5\" strokeWidth={2} />\n <span className=\"sr-only\">View details</span>\n </Link>\n );\n}\n","/**\n * A confirmation asked in place, beside the control that asked it. Used by\n * embedded row actions instead of a browser dialog, which blocks a shared\n * station and every other tab.\n */\nexport function InlineConfirm({ message, onConfirm, onCancel, testId }: {\n message: string;\n onConfirm: () => void;\n onCancel: () => void;\n testId?: string;\n}) {\n return (\n <span className=\"inline-flex flex-wrap items-center gap-2\" role=\"group\" aria-label=\"Confirm action\" data-testid={testId}>\n <span className=\"text-xs text-text-primary whitespace-normal\">{message}</span>\n <button\n type=\"button\"\n onClick={onConfirm}\n className=\"px-2 py-0.5 text-2xs font-medium text-text-inverse bg-accent rounded hover:bg-accent/90 transition-colors\"\n data-testid={testId ? `${testId}-yes` : undefined}\n autoFocus\n >\n Confirm\n </button>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-2 py-0.5 text-2xs font-medium text-text-secondary border border-surface-border rounded hover:bg-surface-hover transition-colors\"\n data-testid={testId ? `${testId}-no` : undefined}\n >\n Cancel\n </button>\n </span>\n );\n}\n","import { createContext, useContext } from 'react';\n\nexport interface EmbedWriteOptions {\n /**\n * The action needs a badge (a role the person acting lacks): hold it for\n * the next badge, saying this. A page that takes no badges drops it.\n */\n badge?: string;\n}\n\n/** Runs an embedded row action, or holds it until the page can run it (a badge at a shared station). */\nexport type EmbedWriteGuard = (verb: string, run: () => Promise<void>, options?: EmbedWriteOptions) => void;\n\nconst runNow: EmbedWriteGuard = (_verb, run, options) => {\n if (!options?.badge) void run();\n};\n\n/**\n * The host page's gate for writes an embedded widget makes on other rows\n * (roster and list actions). Absent a provider, actions run directly.\n */\nexport const EmbedWriteContext = createContext<EmbedWriteGuard>(runNow);\n\nexport function useEmbedWrite(): EmbedWriteGuard {\n return useContext(EmbedWriteContext);\n}\n","import { useState } from 'react';\nimport { SCAN_CAPTURE_ATTR, SCAN_CAPTURE_OFF } from '../../../lib/scan-sources/types';\n\n/**\n * A code typed in place, beside the control that asked for it: a key-in for\n * an item whose barcode will not scan. The server checks the code against\n * the entry; Enter confirms. The field keeps its keys, so a code typed or\n * scanned into it is never also run as a scan.\n */\nexport function InlineCodeEntry({ label, onConfirm, onCancel, testId }: {\n label: string;\n onConfirm: (code: string) => void;\n onCancel: () => void;\n testId?: string;\n}) {\n const [code, setCode] = useState('');\n const submit = () => { if (code.trim()) onConfirm(code.trim()); };\n return (\n <span\n className=\"inline-flex flex-wrap items-center gap-2\"\n role=\"group\"\n aria-label={label}\n data-testid={testId}\n {...{ [SCAN_CAPTURE_ATTR]: SCAN_CAPTURE_OFF }}\n >\n <input\n type=\"text\"\n inputMode=\"numeric\"\n value={code}\n onChange={(e) => setCode(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') submit();\n if (e.key === 'Escape') onCancel();\n }}\n placeholder=\"Code on the label\"\n aria-label=\"Code on the label\"\n className=\"input text-xs py-0.5 w-40 font-mono\"\n data-testid={testId ? `${testId}-input` : undefined}\n autoFocus\n />\n <button\n type=\"button\"\n onClick={submit}\n disabled={!code.trim()}\n className=\"px-2 py-0.5 text-2xs font-medium text-text-inverse bg-accent rounded hover:bg-accent/90 disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n data-testid={testId ? `${testId}-yes` : undefined}\n >\n {label}\n </button>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-2 py-0.5 text-2xs font-medium text-text-secondary border border-surface-border rounded hover:bg-surface-hover transition-colors\"\n data-testid={testId ? `${testId}-no` : undefined}\n >\n Cancel\n </button>\n </span>\n );\n}\n","/**\n * x-lt-roster: every member a container row expects, each with its state.\n * A form field declares `x-lt-widget: \"roster\"` and an `x-lt-roster` block:\n *\n * \"x-lt-roster\": {\n * \"expected\": { \"query\": { \"roles\": [\"packing\"], \"facets\": { \"box\": \"{{escalation.id}}\" } } },\n * \"key\": \"{{metadata.orderId}}\",\n * \"in\": [\"items\", \"resolver.bags\"],\n * \"flagged\": [{ \"when\": \"resolver.outcome=missing\", \"label\": \"Missing\" }]\n * }\n *\n * The expected set is one of:\n * - `query`: member rows matched by role(s) and facets, any status unless\n * `status` narrows it. `key` names each row's entry (default its id).\n * - `list`: a `domain.path` naming an array of keys on the host row.\n * - `batch`: the host row's batch keys; `labels` names a per-key map.\n *\n * An entry is `in` when its key is held by the host row (`items`: the\n * accumulated keys, or a batch's filled keys) or appears in a named context\n * value (`resolver.<field>`, a string or an array). It is `flagged` when its\n * member row matches a `flagged` rule (or, on a batch set, when its key\n * carries a flag in `envelope.batch_flags`), and `waiting` otherwise. In wins over\n * flagged, so a member flagged on its own row and then added reads in.\n *\n * `countedBy` names the separator of counted keys (`<code>#1`, `<code>#2`):\n * the nth occurrence of a code in a named context value ticks `<code>#n`,\n * so two scans of one code tick both of its keys.\n *\n * Isomorphic: the dashboard renders the widget and the form's `roster.*`\n * context from it, and the API layer computes the same counts to evaluate\n * showIf and the roster submit guard at resolve.\n */\nimport { getDeep } from './x-lt-bind';\nimport { resolveCtxPath } from './ctx-path';\nimport { interpolateHelp, type HelpTokenContext } from './x-lt-help';\nimport { evaluateShowIf } from './x-lt-show-if';\n\nexport const X_LT_ROSTER = 'x-lt-roster';\nexport const ROSTER_WIDGET = 'roster';\n/** The context domain the counts are read from: `roster.<field>.outstanding`. */\nexport const ROSTER_DOMAIN = 'roster';\n/** The most member rows a query set reads. */\nexport const ROSTER_QUERY_LIMIT = 200;\n/** The `in` source naming the host row's held keys. */\nexport const ROSTER_ITEMS_SOURCE = 'items';\n/** `query.status` value that reads every status (the default). */\nexport const ROSTER_ANY_STATUS = 'any';\n\nexport const ROSTER_STATES = { WAITING: 'waiting', IN: 'in', FLAGGED: 'flagged' } as const;\nexport type RosterState = (typeof ROSTER_STATES)[keyof typeof ROSTER_STATES];\n\nexport interface RosterQuery {\n role?: string;\n roles?: string[];\n facets?: Record<string, string>;\n /** A status to narrow to; omitted or `any` reads every status. */\n status?: string;\n}\n\nexport type RosterExpected =\n | { query: RosterQuery }\n | { list: string }\n | { batch: true; labels?: string };\n\nexport interface RosterFlagRule {\n /** An x-lt-showIf condition over the member row's own context. */\n when: string | string[];\n label: string;\n}\n\nexport interface RosterDef {\n expected: RosterExpected;\n key?: string;\n in?: string[];\n flagged?: RosterFlagRule[];\n /** The separator of counted keys: the nth occurrence of a code ticks `<code><sep>n`. */\n countedBy?: string;\n}\n\n/** One member row's token context (the row's own domains). */\nexport type RosterRow = HelpTokenContext & { escalation: Record<string, unknown> };\n\nexport interface RosterEntry {\n key: string;\n state: RosterState;\n /** The matching flag rule's label, when flagged. */\n flag?: string;\n /** The member row, for a query set. */\n row?: RosterRow;\n /** The per-key label value from a batch's `labels` map. */\n label?: unknown;\n}\n\nexport interface RosterCounts {\n expected: number;\n in: number;\n flagged: number;\n waiting: number;\n /** Entries neither in nor flagged: the count a roster guard waits on. */\n outstanding: number;\n}\n\nexport interface RosterResult {\n entries: RosterEntry[];\n counts: RosterCounts;\n}\n\nconst DEFAULT_KEY = '{{escalation.id}}';\nconst MISSING = '—';\nconst BATCH_KEYS = 'batch_keys';\nconst BATCH_PENDING = 'batch_pending';\nconst BATCH_FLAGS = 'batch_flags';\nconst ACCUMULATE_KEYS = 'accumulate_keys';\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return !!v && typeof v === 'object' && !Array.isArray(v);\n}\n\nfunction strings(v: unknown): string[] {\n if (typeof v === 'string') return v ? [v] : [];\n if (!Array.isArray(v)) return [];\n return v.filter((s): s is string => typeof s === 'string' && s.length > 0);\n}\n\n/** The field's roster declaration, or undefined when it declares none or an unusable one. */\nexport function readRosterDef(fieldSchema: Record<string, unknown> | null | undefined): RosterDef | undefined {\n const raw = fieldSchema?.[X_LT_ROSTER];\n if (!isRecord(raw) || !isRecord(raw.expected)) return undefined;\n const e = raw.expected;\n const hasSource = isRecord(e.query) || typeof e.list === 'string' || e.batch === true;\n return hasSource ? (raw as unknown as RosterDef) : undefined;\n}\n\n/** Every roster field of a form schema, by field name. */\nexport function readRosterDefs(schema: Record<string, unknown> | null | undefined): Record<string, RosterDef> {\n const properties = isRecord(schema?.properties) ? (schema!.properties as Record<string, unknown>) : {};\n const defs: Record<string, RosterDef> = {};\n for (const [field, def] of Object.entries(properties)) {\n const roster = isRecord(def) ? readRosterDef(def) : undefined;\n if (roster) defs[field] = roster;\n }\n return defs;\n}\n\n/** The roster's member-row query, or null when its set is not a query. */\nexport function rosterQueryOf(def: RosterDef): RosterQuery | null {\n return 'query' in def.expected && isRecord(def.expected.query) ? def.expected.query : null;\n}\n\n/** The query's concrete params: facets interpolated, `any` status dropped. Null when the scope is empty. */\nexport function resolveRosterQuery(\n query: RosterQuery,\n ctx: HelpTokenContext,\n): { roles?: string[]; facets: Record<string, string>; status?: string; limit: number } | null {\n const facets: Record<string, string> = {};\n for (const [k, v] of Object.entries(query.facets ?? {})) {\n if (typeof v !== 'string') continue;\n const resolved = interpolateHelp(v, ctx);\n if (!resolved || resolved === MISSING) return null;\n facets[k] = resolved;\n }\n const roles = [...(query.role ? [query.role] : []), ...strings(query.roles)];\n if (!roles.length && !Object.keys(facets).length) return null;\n const status = query.status && query.status !== ROSTER_ANY_STATUS ? query.status : undefined;\n return { ...(roles.length ? { roles } : {}), facets, ...(status ? { status } : {}), limit: ROSTER_QUERY_LIMIT };\n}\n\nfunction parseJson(v: unknown): Record<string, unknown> | null {\n if (isRecord(v)) return v;\n if (typeof v !== 'string' || !v) return null;\n try {\n const parsed = JSON.parse(v);\n return isRecord(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\n/** A member row's token context, from a row whose JSON columns are strings or objects. */\nexport function rosterRowContext(row: Record<string, unknown>): RosterRow {\n return {\n escalation: row,\n metadata: isRecord(row.metadata) ? row.metadata : parseJson(row.metadata),\n envelope: parseJson(row.envelope),\n payload: parseJson(row.escalation_payload),\n resolver: parseJson(row.resolver_payload),\n };\n}\n\n/** The keys the host row holds: its accumulated keys, or a batch's filled keys. */\nfunction heldKeys(ctx: HelpTokenContext): Set<string> {\n const metadata = ctx.metadata ?? {};\n const accumulated = metadata[ACCUMULATE_KEYS];\n if (Array.isArray(accumulated)) return new Set(strings(accumulated));\n const envelopeItems = getDeep(ctx.envelope, 'accumulate_items');\n if (isRecord(envelopeItems)) return new Set(Object.keys(envelopeItems));\n if (Array.isArray(metadata[BATCH_PENDING])) {\n const pending = new Set(strings(metadata[BATCH_PENDING]));\n return new Set(strings(metadata[BATCH_KEYS]).filter((k) => !pending.has(k)));\n }\n return new Set();\n}\n\n/** Each value as given, and with `countedBy` its nth occurrence also as `<value><sep>n`. */\nfunction countedKeys(values: string[], separator: string | undefined): string[] {\n if (!separator) return values;\n const seen = new Map<string, number>();\n return values.flatMap((v) => {\n const n = (seen.get(v) ?? 0) + 1;\n seen.set(v, n);\n return [v, `${v}${separator}${n}`];\n });\n}\n\nfunction arrivedKeys(def: RosterDef, ctx: HelpTokenContext): Set<string> {\n const arrived = new Set<string>();\n const separator = typeof def.countedBy === 'string' && def.countedBy ? def.countedBy : undefined;\n for (const source of def.in ?? [ROSTER_ITEMS_SOURCE]) {\n const keys = source === ROSTER_ITEMS_SOURCE\n ? [...heldKeys(ctx)]\n : countedKeys(strings(resolveCtxPath(source, ctx as Record<string, unknown>)), separator);\n keys.forEach((k) => arrived.add(k));\n }\n return arrived;\n}\n\n/** A batch key's flag label, from `envelope.batch_flags[key].label`. */\nfunction batchFlagLabel(ctx: HelpTokenContext, key: string): string | undefined {\n const flags = getDeep(ctx.envelope, BATCH_FLAGS);\n const flag = isRecord(flags) ? flags[key] : undefined;\n return isRecord(flag) && typeof flag.label === 'string' && flag.label ? flag.label : undefined;\n}\n\nfunction flagFor(def: RosterDef, row: RosterRow | undefined): string | undefined {\n if (!row) return undefined;\n for (const rule of def.flagged ?? []) {\n const conditions = strings(rule.when);\n if (!conditions.length || typeof rule.label !== 'string') continue;\n if (evaluateShowIf(conditions, row)) return rule.label;\n }\n return undefined;\n}\n\n/** A row's creation instant in ms; 0 when absent or unreadable. */\nfunction createdAt(row: RosterRow): number {\n const raw = row.escalation.created_at;\n const ms = raw instanceof Date ? raw.getTime() : typeof raw === 'string' ? Date.parse(raw) : NaN;\n return Number.isNaN(ms) ? 0 : ms;\n}\n\n/**\n * The expected keys in order, each with its member row (query) or label\n * (batch). Several rows sharing a key (a member that parked again) read as\n * one entry on the newest row, so its state and actions follow the live row.\n */\nfunction expectedEntries(\n def: RosterDef,\n ctx: HelpTokenContext,\n rows: RosterRow[],\n): Array<{ key: string; row?: RosterRow; label?: unknown }> {\n const seen = new Set<string>();\n const out: Array<{ key: string; row?: RosterRow; label?: unknown }> = [];\n const push = (key: string, extra: { row?: RosterRow; label?: unknown } = {}) => {\n if (!key || key === MISSING || seen.has(key)) return;\n seen.add(key);\n out.push({ key, ...extra });\n };\n const e = def.expected;\n if ('query' in e) {\n const template = def.key ?? DEFAULT_KEY;\n const newest = new Map<string, RosterRow>();\n for (const row of rows) {\n const key = interpolateHelp(template, row);\n const held = newest.get(key);\n if (!held || createdAt(row) > createdAt(held)) newest.set(key, row);\n }\n for (const row of rows) {\n const key = interpolateHelp(template, row);\n push(key, { row: newest.get(key) });\n }\n } else if ('list' in e) {\n strings(resolveCtxPath(e.list, ctx as Record<string, unknown>)).forEach((k) => push(k));\n } else {\n const labels = e.labels ? resolveCtxPath(e.labels, ctx as Record<string, unknown>) : undefined;\n for (const key of strings(ctx.metadata?.[BATCH_KEYS])) {\n push(key, isRecord(labels) && key in labels ? { label: labels[key] } : {});\n }\n }\n return out;\n}\n\n/**\n * Every expected entry with its state, and the counts. `rows` are the\n * member rows a query set read (ignored for list and batch sets). `ctx` is\n * the host row's context with the live form values under `resolver`.\n */\nexport function computeRoster(def: RosterDef, ctx: HelpTokenContext, rows: RosterRow[] = []): RosterResult {\n const arrived = arrivedKeys(def, ctx);\n const batch = 'batch' in def.expected;\n const entries: RosterEntry[] = expectedEntries(def, ctx, rows).map((e) => {\n if (arrived.has(e.key)) return { ...e, state: ROSTER_STATES.IN };\n const flag = batch ? batchFlagLabel(ctx, e.key) : flagFor(def, e.row);\n return flag ? { ...e, state: ROSTER_STATES.FLAGGED, flag } : { ...e, state: ROSTER_STATES.WAITING };\n });\n const count = (s: RosterState) => entries.filter((e) => e.state === s).length;\n const waiting = count(ROSTER_STATES.WAITING);\n return {\n entries,\n counts: {\n expected: entries.length,\n in: count(ROSTER_STATES.IN),\n flagged: count(ROSTER_STATES.FLAGGED),\n waiting,\n outstanding: waiting,\n },\n };\n}\n\n/** The header line: \"3 of 5 in · 1 Missing\". */\nexport function rosterHeadline(result: RosterResult): string {\n const { counts } = result;\n const parts = [`${counts.in} of ${counts.expected} in`];\n const byFlag = new Map<string, number>();\n for (const e of result.entries) {\n if (e.state === ROSTER_STATES.FLAGGED && e.flag) byFlag.set(e.flag, (byFlag.get(e.flag) ?? 0) + 1);\n }\n for (const [flag, n] of byFlag) parts.push(`${n} ${flag}`);\n return parts.join(' · ');\n}\n","import { CheckCircle2, Circle, Flag } from 'lucide-react';\nimport { OpenDetailButton } from './OpenDetailButton';\nimport { InlineConfirm } from './InlineConfirm';\nimport { InlineCodeEntry } from './InlineCodeEntry';\nimport { FormattedValue } from '../../common/display/FormattedValue';\nimport { interpolateHelp } from '../../../lib/x-lt-help';\nimport { interpolateItemTemplate, type EscalationItem } from '../../../lib/escalation-items';\nimport type { EmbedColumnDef } from '../../../lib/embed-row';\nimport type { RosterActionDef } from '../../../lib/x-lt-actions';\nimport { ROSTER_STATES, type RosterEntry, type RosterState } from '../../../lib/x-lt-roster';\nimport type { ShowIfContext } from '../../../lib/x-lt-show-if';\n\n/** An action the entry offers, with its index among the field's actions. */\nexport interface OfferedAction {\n index: number;\n action: RosterActionDef;\n}\n\nconst STATE_TEXT: Record<RosterState, string> = { waiting: 'Waiting', in: 'In', flagged: 'Flagged' };\n\nfunction StateMark({ state }: { state: RosterState }) {\n if (state === ROSTER_STATES.IN) return <CheckCircle2 className=\"w-4 h-4 text-status-success shrink-0\" strokeWidth={2} aria-hidden />;\n if (state === ROSTER_STATES.FLAGGED) return <Flag className=\"w-4 h-4 text-status-warning shrink-0\" strokeWidth={2} aria-hidden />;\n return <Circle className=\"w-4 h-4 text-text-tertiary shrink-0\" strokeWidth={2} aria-hidden />;\n}\n\n/**\n * One roster entry: its state mark, columns, state label, and the actions\n * its state offers. Columns read the member row's domains (a query set) or\n * the host row's, beside `{{item.*}}`: the entry key, a batch label, and\n * the item's payload, actor and time once it is in.\n */\nexport function RosterEntryRow({\n entry, item, hostCtx, columns, offered, asking, pending, error, onAction, onConfirm, onCancel,\n}: {\n entry: RosterEntry;\n item: EscalationItem & { label?: unknown };\n hostCtx: ShowIfContext;\n columns: EmbedColumnDef[];\n offered: OfferedAction[];\n /** The action asking in place: its confirmation, or its code entry. */\n asking: OfferedAction | null;\n pending: boolean;\n error?: string;\n onAction: (offer: OfferedAction) => void;\n onConfirm: (code?: string) => void;\n onCancel: () => void;\n}) {\n const ctx = entry.row ?? hostCtx;\n const done = entry.state === ROSTER_STATES.IN;\n const stateLabel = entry.state === ROSTER_STATES.FLAGGED ? entry.flag ?? STATE_TEXT.flagged : STATE_TEXT[entry.state];\n\n return (\n <li\n className=\"py-2 flex items-start gap-3 border-b border-surface-border/50 last:border-0\"\n data-testid={`roster-entry-${entry.key}`}\n data-state={entry.state}\n >\n <span className=\"pt-0.5\"><StateMark state={entry.state} /></span>\n <div className=\"min-w-0 flex-1 flex flex-wrap items-baseline gap-x-4 gap-y-0.5\">\n {columns.map((col) => (\n <span key={col.label} className={`text-sm min-w-0 ${done ? 'text-text-secondary' : 'text-text-primary'}`}>\n <span className=\"sr-only\">{col.label}: </span>\n <FormattedValue raw={interpolateItemTemplate(col.value, item, ctx)} format={col.format} />\n </span>\n ))}\n </div>\n <span\n className={`text-xs font-medium shrink-0 pt-0.5 ${done ? 'text-status-success' : entry.state === ROSTER_STATES.FLAGGED ? 'text-status-warning' : 'text-text-tertiary'}`}\n data-testid={`roster-state-${entry.key}`}\n >\n {stateLabel}\n </span>\n {(offered.length > 0 || asking || error) && (\n <span className=\"shrink-0 flex flex-col items-end gap-0.5\">\n {asking?.action.fill?.enterCode ? (\n <InlineCodeEntry\n label={asking.action.label}\n onConfirm={(code) => onConfirm(code)}\n onCancel={onCancel}\n testId={`roster-code-${entry.key}`}\n />\n ) : asking ? (\n <InlineConfirm\n message={interpolateHelp(asking.action.confirm ?? '', ctx)}\n onConfirm={() => onConfirm()}\n onCancel={onCancel}\n testId={`roster-confirm-${entry.key}`}\n />\n ) : (\n <span className=\"flex gap-1\">\n {offered.map((offer) => (\n <button\n key={offer.index}\n type=\"button\"\n onClick={() => onAction(offer)}\n disabled={pending}\n className=\"px-2 py-0.5 text-2xs font-medium text-accent border border-accent/40 rounded hover:bg-accent/10 disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n data-testid={`roster-action-${entry.key}`}\n >\n {offer.action.label}\n </button>\n ))}\n </span>\n )}\n {error && (\n <span className=\"text-2xs text-status-error max-w-[16rem] text-right\" data-testid={`roster-error-${entry.key}`}>{error}</span>\n )}\n </span>\n )}\n {entry.row && (\n <OpenDetailButton to={`/escalations/detail/${String(entry.row.escalation.id)}`} />\n )}\n </li>\n );\n}\n","import { useQueries } from '@tanstack/react-query';\nimport { escalationListQuery } from '../api/escalations';\nimport { schemaNeedsEnvelope } from '../lib/schema-needs-envelope';\nimport {\n computeRoster,\n readRosterDefs,\n resolveRosterQuery,\n rosterQueryOf,\n rosterRowContext,\n type RosterDef,\n type RosterResult,\n type RosterRow,\n} from '../lib/x-lt-roster';\nimport type { ShowIfContext } from '../lib/x-lt-show-if';\n\n/** A roster's result, or null while its member rows are loading or failed to load. */\nexport type RosterView = RosterResult | null;\n\nfunction listFiltersFor(def: RosterDef, ctx: ShowIfContext) {\n const query = rosterQueryOf(def);\n const scoped = query ? resolveRosterQuery(query, ctx) : null;\n if (!scoped) return null;\n return {\n roles: scoped.roles,\n status: scoped.status,\n facets: scoped.facets,\n limit: scoped.limit,\n include: schemaNeedsEnvelope({ key: def.key, flagged: def.flagged }) ? ('envelope' as const) : undefined,\n };\n}\n\n/**\n * Every roster of a form, by field name. Member rows load through the shared\n * list query, so a roster refreshes on the same escalation events as every\n * list, and the widget and the page read one cached result. `ctx` carries\n * the live form values under `resolver`.\n */\nexport function useRosters(\n schema: Record<string, unknown> | null | undefined,\n ctx: ShowIfContext | undefined,\n): Record<string, RosterView> {\n const defs = Object.entries(readRosterDefs(schema));\n const host = ctx ?? {};\n const filters = defs.map(([, def]) => listFiltersFor(def, host));\n const reads = useQueries({\n queries: filters.map((f) => ({\n ...escalationListQuery(f ?? {}),\n enabled: !!f,\n })),\n });\n\n const views: Record<string, RosterView> = {};\n defs.forEach(([field, def], i) => {\n if (!filters[i]) {\n views[field] = computeRoster(def, host);\n return;\n }\n const read = reads[i];\n if (!read.isSuccess) {\n views[field] = null;\n return;\n }\n const rows: RosterRow[] = read.data.escalations.map((e) => rosterRowContext(e as unknown as Record<string, unknown>));\n views[field] = computeRoster(def, host, rows);\n });\n return views;\n}\n\n/** The `roster` context domain: each loaded roster's counts. */\nexport function rosterContext(views: Record<string, RosterView>): Record<string, unknown> | null {\n const loaded = Object.entries(views).filter(([, v]) => v !== null);\n if (!loaded.length) return null;\n return Object.fromEntries(loaded.map(([field, v]) => [field, v!.counts]));\n}\n","/**\n * x-lt-actions on a roster field: the acts an entry offers, read the same way\n * by the dashboard (which shows them) and the API (which runs them). Each\n * action is exactly one act:\n *\n * { \"label\": \"Missing\", \"resolverPayload\": { \"outcome\": \"missing\" } } resolve the member row\n * { \"label\": \"Key in\", \"fill\": { \"payload\": { \"source\": \"key-in\" }, \"enterCode\": true } }\n * { \"label\": \"Missing\", \"flag\": { \"label\": \"Missing\" } } flag the batch key\n * { \"label\": \"Found it\", \"unflag\": true } clear the flag\n *\n * `when` names the entry states that offer it. `roles` limits who may run it:\n * the action shows to everyone and runs only for a person holding one of the\n * roles; `refuse` is what anyone else is told. The server re-reads the action\n * from the row's form schema and decides; the dashboard only displays.\n */\nimport { interpolateHelp, type HelpTokenContext } from './x-lt-help';\nimport { ROSTER_STATES, type RosterEntry, type RosterState } from './x-lt-roster';\nimport { displayGtin, isValidGtin, normalizeGtin } from '../scan-code/gtin';\n\nexport const X_LT_ACTIONS = 'x-lt-actions';\n\nexport const ROSTER_ACTION_KINDS = {\n RESOLVE: 'resolve',\n FILL: 'fill',\n FLAG: 'flag',\n UNFLAG: 'unflag',\n} as const;\nexport type RosterActionKind = (typeof ROSTER_ACTION_KINDS)[keyof typeof ROSTER_ACTION_KINDS];\n\n/** The separator of counted batch keys when the roster names none. */\nexport const ROSTER_KEY_SEPARATOR_DEFAULT = '#';\n\n/** The payload key a key-in records the entered code under. */\nexport const ENTERED_CODE_KEY = 'enteredCode';\n\nexport interface RosterActionDef {\n label: string;\n /** The entry states that offer it; the default follows the act. */\n when?: RosterState | RosterState[];\n /** A confirmation asked in place before firing; tokens interpolate per entry. */\n confirm?: string;\n /** Resolve the entry's member row with this canned payload (a query set). */\n resolverPayload?: Record<string, unknown>;\n /** Fill the entry's batch key; `enterCode` asks for the code and checks it against the key. */\n fill?: { payload?: Record<string, unknown>; enterCode?: boolean };\n /** Flag the entry's batch key. */\n flag?: { label: string; payload?: Record<string, unknown> };\n /** Clear the entry's flag. */\n unflag?: true;\n /** Runs only for a person holding one of these roles. */\n roles?: string[];\n /** What a person without the roles is told. */\n refuse?: string;\n}\n\nconst DEFAULT_WHEN: Record<RosterActionKind, RosterState[]> = {\n resolve: [ROSTER_STATES.WAITING],\n fill: [ROSTER_STATES.WAITING, ROSTER_STATES.FLAGGED],\n flag: [ROSTER_STATES.WAITING],\n unflag: [ROSTER_STATES.FLAGGED],\n};\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return !!v && typeof v === 'object' && !Array.isArray(v);\n}\n\n/** The one act an action declares, or null when it declares none or several. */\nexport function rosterActionKind(action: RosterActionDef): RosterActionKind | null {\n const kinds: RosterActionKind[] = [];\n if (isRecord(action.resolverPayload)) kinds.push(ROSTER_ACTION_KINDS.RESOLVE);\n if (isRecord(action.fill)) kinds.push(ROSTER_ACTION_KINDS.FILL);\n if (isRecord(action.flag) && typeof action.flag.label === 'string' && action.flag.label) {\n kinds.push(ROSTER_ACTION_KINDS.FLAG);\n }\n if (action.unflag === true) kinds.push(ROSTER_ACTION_KINDS.UNFLAG);\n return kinds.length === 1 ? kinds[0] : null;\n}\n\n/** The field's actions with a label and exactly one act, in declared order. */\nexport function readRosterActions(fieldSchema: Record<string, unknown> | null | undefined): RosterActionDef[] {\n const raw = fieldSchema?.[X_LT_ACTIONS];\n if (!Array.isArray(raw)) return [];\n return raw.filter((a): a is RosterActionDef =>\n isRecord(a) && typeof a.label === 'string' && !!a.label && rosterActionKind(a as unknown as RosterActionDef) !== null);\n}\n\n/**\n * True when the entry offers the action: the entry is in one of its states,\n * and the act fits the entry (a resolve needs a member row; batch acts need\n * a batch set).\n */\nexport function offersAction(action: RosterActionDef, entry: RosterEntry, batch: boolean): boolean {\n const kind = rosterActionKind(action);\n if (!kind) return false;\n if (kind === ROSTER_ACTION_KINDS.RESOLVE ? !entry.row : !batch) return false;\n const when = action.when === undefined ? DEFAULT_WHEN[kind]\n : Array.isArray(action.when) ? action.when : [action.when];\n return when.includes(entry.state);\n}\n\n/** True when a person holding `roles` may run the action. */\nexport function holdsActionRole(action: Pick<RosterActionDef, 'roles'>, roles: string[], superadmin = false): boolean {\n const required = Array.isArray(action.roles) ? action.roles.filter((r) => typeof r === 'string' && r) : [];\n return required.length === 0 || superadmin || required.some((r) => roles.includes(r));\n}\n\n/** What a person without the action's roles is told. */\nexport function actionRefusal(action: Pick<RosterActionDef, 'label' | 'roles' | 'refuse'>): string {\n if (typeof action.refuse === 'string' && action.refuse.trim()) return action.refuse;\n const roles = (action.roles ?? []).filter(Boolean);\n return `${action.label} needs ${roles.length > 1 ? 'one of these roles' : 'the role'}: ${roles.join(', ')}.`;\n}\n\n/** Deep-walk a payload template: string leaves interpolate against the context; other types pass through typed. */\nexport function interpolatePayload(value: unknown, ctx: HelpTokenContext): unknown {\n if (typeof value === 'string') return interpolateHelp(value, ctx);\n if (Array.isArray(value)) return value.map((v) => interpolatePayload(v, ctx));\n if (isRecord(value)) {\n return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, interpolatePayload(v, ctx)]));\n }\n return value;\n}\n\n/** The code a batch key names, without its ordinal suffix. */\nexport function batchKeyCode(key: string, separator = ROSTER_KEY_SEPARATOR_DEFAULT): string {\n const at = key.lastIndexOf(separator);\n return at > 0 && /^[0-9]+$/.test(key.slice(at + 1)) ? key.slice(0, at) : key;\n}\n\n/** The batch key's code as its label prints it: a GTIN in its EAN-13 or EAN-8 form. */\nexport function printedKeyCode(key: string, separator?: string): string {\n const code = batchKeyCode(key, separator);\n return isValidGtin(code) ? displayGtin(normalizeGtin(code)) : code;\n}\n\n/**\n * True when an entered code names the batch key's code. GTINs compare in\n * their 14-digit form, so a UPC-A typed from the label matches its GTIN-14\n * key; anything else compares as trimmed text.\n */\nexport function enteredCodeMatches(entered: string, key: string, separator?: string): boolean {\n const typed = entered.trim();\n const code = batchKeyCode(key, separator);\n if (!typed) return false;\n if (isValidGtin(typed) && isValidGtin(code)) return normalizeGtin(typed) === normalizeGtin(code);\n return typed === code;\n}\n","import { useState } from 'react';\nimport { FieldLabel, FieldHelper } from '../resolver-form/FieldChrome';\nimport { RosterEntryRow, type OfferedAction } from './RosterEntryRow';\nimport { useEmbedWrite } from './embed-write';\nimport { useRosters } from '../../../hooks/useRosters';\nimport { ApiError } from '../../../api/client';\nimport { ROSTER_ACTION_OUTCOMES, useRosterAction } from '../../../api/escalations';\nimport { getDeep } from '../../../lib/x-lt-bind';\nimport type { EmbedColumnDef } from '../../../lib/embed-row';\nimport { offersAction, readRosterActions } from '../../../lib/x-lt-actions';\nimport { readRosterDef, rosterHeadline, type RosterEntry } from '../../../lib/x-lt-roster';\nimport type { EscalationItem } from '../../../lib/escalation-items';\nimport type { ShowIfContext } from '../../../lib/x-lt-show-if';\nimport type { WidgetProps } from './index';\n\nconst DEFAULT_COLUMNS: EmbedColumnDef[] = [{ label: 'Item', value: '{{item.itemKey}}' }];\nconst EMBED_WRITE_VERB = 'continue';\nconst BADGE_OUTCOMES: string[] = [ROSTER_ACTION_OUTCOMES.NEEDS_BADGE, ROSTER_ACTION_OUTCOMES.ROLE_REFUSED];\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return !!v && typeof v === 'object' && !Array.isArray(v);\n}\n\n/** The value a per-key envelope map holds for the entry, when it is a string. */\nfunction keyed(ctx: ShowIfContext, map: string, key: string): string | undefined {\n const values = getDeep(ctx.envelope, map);\n const value = isRecord(values) ? values[key] : undefined;\n return typeof value === 'string' ? value : undefined;\n}\n\n/**\n * The entry's `item` domain: its key, a batch label, and the item once it is\n * in. A held item reads its payload, time and actor from `accumulate_items`;\n * a batch entry reads its payload from `batch_items` and its time and actor\n * from `batch_filled_at` and `batch_filled_by`.\n */\nfunction itemFor(entry: RosterEntry, ctx: ShowIfContext): EscalationItem & { label?: unknown } {\n const held = getDeep(ctx.envelope, 'accumulate_items');\n const batchPayload = getDeep(ctx.envelope, 'batch_items');\n const h = isRecord(held) && isRecord(held[entry.key]) ? held[entry.key] as Record<string, unknown> : null;\n const payload = h && isRecord(h.payload) ? h.payload\n : isRecord(batchPayload) && isRecord(batchPayload[entry.key]) ? batchPayload[entry.key] as Record<string, unknown>\n : undefined;\n const at = typeof h?.at === 'string' ? h.at : h ? undefined : keyed(ctx, 'batch_filled_at', entry.key);\n const actor = typeof h?.actor === 'string' ? h.actor : h ? undefined : keyed(ctx, 'batch_filled_by', entry.key);\n return {\n itemKey: entry.key,\n at: at ?? '',\n ...(payload ? { payload } : {}),\n ...(actor ? { actor } : {}),\n ...(entry.label !== undefined ? { label: entry.label } : {}),\n };\n}\n\n/**\n * Roster widget: every member the host row expects, each marked waiting, in,\n * or flagged, with the count in the heading. The entries come from the same\n * shared computation the page reads for `roster.*` and the roster guard,\n * against the live form, so a scan into a form field ticks its entry in at\n * once and an arrival on any device ticks it in on the next escalation\n * event.\n *\n * Actions run on the server (`/escalations/:id/roster-action`), which\n * re-reads the declaration: a resolve of the entry's member row, or a fill,\n * flag or unflag of its batch key. An action limited to roles asks for a\n * badge of that role when the person acting lacks it.\n *\n * Schema usage:\n * \"x-lt-widget\": \"roster\",\n * \"x-lt-roster\": { \"expected\": { ... }, \"key\": \"...\", \"in\": [...], \"flagged\": [...] },\n * \"x-lt-columns\": [{ \"label\": \"Order\", \"value\": \"{{metadata.orderId}}\" }],\n * \"x-lt-actions\": [{ \"label\": \"Missing\", \"when\": \"waiting\",\n * \"resolverPayload\": { \"outcome\": \"missing\" },\n * \"confirm\": \"Mark {{metadata.orderId}} missing?\" }]\n *\n * Display-only: produces no value of its own in the resolver payload.\n */\nexport function RosterWidget({ fieldKey, schema, escalationContext }: WidgetProps) {\n const ctx = escalationContext ?? {};\n const view = useRosters({ properties: { [fieldKey]: schema ?? {} } }, ctx)[fieldKey];\n const def = readRosterDef(schema);\n const batch = !!def && 'batch' in def.expected;\n const columns = (schema?.['x-lt-columns'] as EmbedColumnDef[] | undefined) ?? DEFAULT_COLUMNS;\n const actions = readRosterActions(schema);\n const label = (schema?.title as string | undefined) ?? 'Expected items';\n const helperText = schema?.description as string | undefined;\n const hostId = String((ctx.escalation as Record<string, unknown> | undefined)?.id ?? '');\n\n const runAction = useRosterAction();\n const guard = useEmbedWrite();\n const [asking, setAsking] = useState<{ key: string; offer: OfferedAction } | null>(null);\n const [pendingKey, setPendingKey] = useState<string | null>(null);\n const [errors, setErrors] = useState<Record<string, string>>({});\n\n const fire = async (entry: RosterEntry, offer: OfferedAction, code?: string): Promise<void> => {\n setPendingKey(entry.key);\n setErrors((prev) => ({ ...prev, [entry.key]: '' }));\n try {\n await runAction.mutateAsync({ id: hostId, field: fieldKey, action: offer.index, entry: entry.key, code });\n } catch (err) {\n const message = (err as Error).message;\n setErrors((prev) => ({ ...prev, [entry.key]: message }));\n const outcome = err instanceof ApiError && isRecord(err.body) ? err.body.outcome : undefined;\n if (typeof outcome === 'string' && BADGE_OUTCOMES.includes(outcome)) {\n guard(EMBED_WRITE_VERB, () => fire(entry, offer, code), { badge: message });\n }\n } finally {\n setPendingKey(null);\n }\n };\n\n const act = (entry: RosterEntry, offer: OfferedAction, code?: string) => {\n setAsking(null);\n guard(EMBED_WRITE_VERB, () => fire(entry, offer, code));\n };\n\n const request = (entry: RosterEntry, offer: OfferedAction) => {\n if (offer.action.confirm || offer.action.fill?.enterCode) setAsking({ key: entry.key, offer });\n else act(entry, offer);\n };\n\n const offeredFor = (entry: RosterEntry): OfferedAction[] =>\n actions\n .map((action, index) => ({ action, index }))\n .filter(({ action }) => offersAction(action, entry, batch));\n\n return (\n <div data-field-key={fieldKey} data-testid={`roster-widget-${fieldKey}`}>\n <div className=\"flex items-baseline justify-between gap-3\">\n <FieldLabel>{label}</FieldLabel>\n {view && (\n <span className=\"text-sm font-medium text-text-primary\" data-testid={`roster-headline-${fieldKey}`}>\n {rosterHeadline(view)}\n </span>\n )}\n </div>\n {helperText && <FieldHelper>{helperText}</FieldHelper>}\n {!view ? (\n <p className=\"text-xs text-text-tertiary py-2\" data-testid={`roster-loading-${fieldKey}`}>Loading expected items…</p>\n ) : view.entries.length === 0 ? (\n <p className=\"text-xs text-text-tertiary italic py-2\" data-testid={`roster-empty-${fieldKey}`}>Nothing expected.</p>\n ) : (\n <ul className=\"mt-1\" data-testid={`roster-list-${fieldKey}`}>\n {view.entries.map((entry) => (\n <RosterEntryRow\n key={entry.key}\n entry={entry}\n item={itemFor(entry, ctx)}\n hostCtx={ctx}\n columns={columns}\n offered={hostId ? offeredFor(entry) : []}\n asking={asking?.key === entry.key ? asking.offer : null}\n pending={pendingKey === entry.key}\n error={errors[entry.key] || undefined}\n onAction={(offer) => request(entry, offer)}\n onConfirm={(code) => asking && act(entry, asking.offer, code)}\n onCancel={() => setAsking(null)}\n />\n ))}\n </ul>\n )}\n </div>\n );\n}\n"],"names":["INTERPOLATION_PATTERN","hasInterpolation","token","resolveCtxPath","path","ctx","dot","root","getDeep","interpolatePath","template","unresolved","concrete","_match","rawPath","value","isTruthy","asComparable","resolvePath","expr","domain","HELP_DOMAINS","evaluateShowIf","condition","c","negate","neqAt","eqAt","isNeq","opAt","expected","known","matches","result","isHiddenIfEmpty","fieldSchema","X_LT_HIDDEN","isHiddenField","FieldLabel","children","isRequired","htmlFor","jsxs","jsx","FieldHelper","id","FieldError","error","inputClass","hasError","selectClass","OpenDetailButton","to","className","Link","ArrowUpRight","InlineConfirm","message","onConfirm","onCancel","testId","runNow","_verb","run","options","EmbedWriteContext","createContext","useEmbedWrite","useContext","InlineCodeEntry","label","code","setCode","useState","submit","SCAN_CAPTURE_ATTR","SCAN_CAPTURE_OFF","e","X_LT_ROSTER","ROSTER_QUERY_LIMIT","ROSTER_ITEMS_SOURCE","ROSTER_ANY_STATUS","ROSTER_STATES","DEFAULT_KEY","MISSING","BATCH_KEYS","BATCH_PENDING","BATCH_FLAGS","ACCUMULATE_KEYS","isRecord","v","strings","s","readRosterDef","raw","readRosterDefs","schema","properties","defs","field","def","roster","rosterQueryOf","resolveRosterQuery","query","facets","k","resolved","interpolateHelp","roles","status","parseJson","parsed","rosterRowContext","row","heldKeys","metadata","accumulated","envelopeItems","pending","countedKeys","values","separator","seen","n","arrivedKeys","arrived","source","batchFlagLabel","key","flags","flag","flagFor","rule","conditions","createdAt","ms","expectedEntries","rows","out","push","extra","newest","held","labels","_a","computeRoster","batch","entries","count","waiting","rosterHeadline","counts","parts","byFlag","STATE_TEXT","StateMark","state","CheckCircle2","Flag","Circle","RosterEntryRow","entry","item","hostCtx","columns","offered","asking","onAction","done","stateLabel","col","FormattedValue","interpolateItemTemplate","offer","listFiltersFor","scoped","schemaNeedsEnvelope","useRosters","host","filters","reads","useQueries","f","escalationListQuery","views","i","read","rosterContext","loaded","X_LT_ACTIONS","ROSTER_ACTION_KINDS","DEFAULT_WHEN","rosterActionKind","action","kinds","readRosterActions","a","offersAction","kind","DEFAULT_COLUMNS","EMBED_WRITE_VERB","BADGE_OUTCOMES","ROSTER_ACTION_OUTCOMES","keyed","map","itemFor","batchPayload","h","payload","at","actor","RosterWidget","fieldKey","escalationContext","view","actions","helperText","hostId","runAction","useRosterAction","guard","setAsking","pendingKey","setPendingKey","errors","setErrors","fire","prev","err","outcome","ApiError","act","request","offeredFor","index"],"mappings":"0WAeO,MAAMA,GAAwB,2BAG9B,SAASC,GAAiBC,EAAiC,CAChE,OAAO,OAAOA,GAAU,UAAY,iBAAiB,KAAKA,CAAK,CACjE,CAGO,SAASC,EACdC,EACAC,EACS,CACT,GAAI,CAACA,EAAK,OACV,MAAMC,EAAMF,EAAK,QAAQ,GAAG,EACtBG,EAAOF,EAAIC,IAAQ,GAAKF,EAAOA,EAAK,MAAM,EAAGE,CAAG,CAAC,EACvD,GAAIA,IAAQ,GAAI,OAAOC,EACvB,GAAI,EAAAA,IAAS,MAAQ,OAAOA,GAAS,UACrC,OAAOC,EAAQD,EAAMH,EAAK,MAAME,EAAM,CAAC,CAAC,CAC1C,CAQO,SAASG,GACdC,EACAL,EACe,CACf,IAAIM,EAAa,GACjB,MAAMC,EAAWF,EAAS,QAAQV,GAAuB,CAACa,EAAQC,IAAoB,CACpF,MAAMC,EAAQZ,EAAeW,EAAST,CAAG,EACzC,OAAI,OAAOU,GAAU,UAAYA,EAAM,OAAO,OAAS,EAAUA,EAC7D,OAAOA,GAAU,UAAY,OAAO,SAASA,CAAK,EAAU,OAAOA,CAAK,GAC5EJ,EAAa,GACN,GACT,CAAC,EACD,OAAOA,EAAa,KAAOC,CAC7B,CC1BA,SAASI,EAASD,EAAyB,CACzC,OAAOA,GAAU,MAA+BA,IAAU,IAAMA,IAAU,IAASA,IAAU,CAC/F,CAGA,SAASE,GAAaF,EAAwB,CAC5C,OAAIA,GAAU,KAAoC,GAC9C,OAAOA,GAAU,SAAiB,KAAK,UAAUA,CAAK,EACnD,OAAOA,CAAK,CACrB,CAEA,SAASG,EAAYC,EAAcd,EAAwD,CACzF,MAAMC,EAAMa,EAAK,QAAQ,GAAG,EACtBC,EAAUd,IAAQ,GAAKa,EAAOA,EAAK,MAAM,EAAGb,CAAG,EACrD,GAAI,CAAEe,GAAmC,SAASD,CAAM,QAAU,CAAE,MAAO,GAAO,MAAO,MAAA,EACzF,MAAMb,EAAOF,EAAIe,CAAM,EACvB,GAAId,IAAQ,GAAI,MAAO,CAAE,MAAO,GAAM,MAAOC,CAAA,EAC7C,GAAI,CACF,MAAO,CAAE,MAAO,GAAM,MAAOC,EAAQD,EAAMY,EAAK,MAAMb,EAAM,CAAC,CAAC,CAAA,CAChE,MAAQ,CACN,MAAO,CAAE,MAAO,GAAM,MAAO,MAAA,CAC/B,CACF,CAOO,SAASgB,EAAeC,EAAoBlB,EAAgD,CACjG,GAAI,MAAM,QAAQkB,CAAS,EAAG,OAAOA,EAAU,MAAOC,GAAMF,EAAeE,EAAGnB,CAAG,CAAC,EAElF,GADI,OAAOkB,GAAc,UAAYA,EAAU,SAAW,GACtD,CAAClB,EAAK,MAAO,GACjB,MAAMoB,EAASF,EAAU,WAAW,GAAG,EACjCJ,EAAOM,EAASF,EAAU,MAAM,CAAC,EAAIA,EAGrCG,EAAQP,EAAK,QAAQ,IAAI,EACzBQ,EAAOR,EAAK,QAAQ,GAAG,EAC7B,GAAIO,IAAU,IAAOC,IAAS,IAAMA,IAASD,EAAQ,EAAI,CACvD,MAAME,EAAQF,IAAU,KAAOC,IAAS,IAAMD,EAAQC,GAChDE,EAAOD,EAAQF,EAAQC,EACvBvB,EAAOe,EAAK,MAAM,EAAGU,CAAI,EAAE,KAAA,EAC3BC,EAAWX,EAAK,MAAMU,GAAQD,EAAQ,EAAI,EAAE,EAAE,KAAA,EAC9C,CAAE,MAAAG,EAAO,MAAAhB,GAAUG,EAAYd,EAAMC,CAAG,EAC9C,GAAI,CAAC0B,EAAO,MAAO,GACnB,MAAMC,EAAUf,GAAaF,CAAK,IAAMe,EAClCG,EAASL,EAAQ,CAACI,EAAUA,EAClC,OAAOP,EAAS,CAACQ,EAASA,CAC5B,CAEA,KAAM,CAAE,MAAAF,EAAO,MAAAhB,CAAA,EAAUG,EAAYC,EAAMd,CAAG,EAC9C,OAAK0B,EACEN,EAAS,CAACT,EAASD,CAAK,EAAIC,EAASD,CAAK,EAD9B,EAErB,CAMO,SAASmB,GAAgBC,EAAkDpB,EAAyB,CACzG,OAAIoB,GAAA,YAAAA,EAAc,yBAA0B,GAAa,GAClDpB,GAAU,MAA+BA,IAAU,IAAMA,IAAU,IAASA,IAAU,CAC/F,CAQO,MAAMqB,GAAc,cAEpB,SAASC,GAAcF,EAA2D,CACvF,OAAOA,GAAA,YAAAA,EAAcC,OAAiB,EACxC,CClGO,SAASE,GAAW,CAAE,SAAAC,EAAU,WAAAC,EAAY,QAAAC,GAIhD,CAMD,OACEC,EAAAA,KAAC,QAAA,CAAM,QAAAD,EAAkB,UAAU,4EAChC,SAAA,CAAAF,EACAC,GAAcG,EAAAA,IAAC,OAAA,CAAK,UAAU,2BAA2B,SAAA,GAAA,CAAC,CAAA,EAC7D,CAEJ,CAEO,SAASC,GAAY,CAAE,GAAAC,EAAI,SAAAN,GAAwD,CACxF,OACEI,EAAAA,IAAC,IAAA,CAAE,GAAAE,EAAQ,UAAU,kDAClB,SAAAN,EACH,CAEJ,CAEO,SAASO,GAAW,CAAE,MAAAC,EAAO,GAAAF,GAAuC,CACzE,OAAKE,QAEF,IAAA,CAAE,GAAAF,EAAQ,KAAK,QAAQ,UAAU,yEAC/B,SAAAE,EACH,EAJiB,IAMrB,CAEO,SAASC,GAAWC,EAA4B,CACrD,OAAOA,EACH,oHACA,2BACN,CAOO,SAASC,GAAYD,EAA4B,CACtD,OAAOA,EACH,iJACA,wDACN,CC7CO,SAASE,GAAiB,CAAE,GAAAC,EAAI,UAAAC,EAAY,IAA0C,CAC3F,OACEX,EAAAA,KAACY,GAAA,CACC,GAAAF,EACA,MAAM,eACN,SAAU,GACV,UAAW,6LAA6LC,CAAS,GAEjN,SAAA,CAAAV,EAAAA,IAACY,GAAA,CAAa,UAAU,cAAc,YAAa,EAAG,EACtDZ,EAAAA,IAAC,OAAA,CAAK,UAAU,UAAU,SAAA,cAAA,CAAY,CAAA,CAAA,CAAA,CAG5C,CCjBO,SAASa,GAAc,CAAE,QAAAC,EAAS,UAAAC,EAAW,SAAAC,EAAU,OAAAC,GAK3D,CACD,OACElB,OAAC,QAAK,UAAU,2CAA2C,KAAK,QAAQ,aAAW,iBAAiB,cAAakB,EAC/G,SAAA,CAAAjB,EAAAA,IAAC,OAAA,CAAK,UAAU,8CAA+C,SAAAc,EAAQ,EACvEd,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASe,EACT,UAAU,4GACV,cAAaE,EAAS,GAAGA,CAAM,OAAS,OACxC,UAAS,GACV,SAAA,SAAA,CAAA,EAGDjB,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASgB,EACT,UAAU,qIACV,cAAaC,EAAS,GAAGA,CAAM,MAAQ,OACxC,SAAA,QAAA,CAAA,CAED,EACF,CAEJ,CCpBA,MAAMC,GAA0B,CAACC,EAAOC,EAAKC,IAAY,CAClDA,GAAA,MAAAA,EAAS,OAAYD,EAAA,CAC5B,EAMaE,GAAoBC,EAAAA,cAA+BL,EAAM,EAE/D,SAASM,IAAiC,CAC/C,OAAOC,EAAAA,WAAWH,EAAiB,CACrC,CChBO,SAASI,GAAgB,CAAE,MAAAC,EAAO,UAAAZ,EAAW,SAAAC,EAAU,OAAAC,GAK3D,CACD,KAAM,CAACW,EAAMC,CAAO,EAAIC,EAAAA,SAAS,EAAE,EAC7BC,EAAS,IAAM,CAAMH,EAAK,KAAA,GAAQb,EAAUa,EAAK,MAAM,CAAG,EAChE,OACE7B,EAAAA,KAAC,OAAA,CACC,UAAU,2CACV,KAAK,QACL,aAAY4B,EACZ,cAAaV,EACP,CAACe,EAAiB,EAAGC,GAE3B,SAAA,CAAAjC,EAAAA,IAAC,QAAA,CACC,KAAK,OACL,UAAU,UACV,MAAO4B,EACP,SAAWM,GAAML,EAAQK,EAAE,OAAO,KAAK,EACvC,UAAYA,GAAM,CACZA,EAAE,MAAQ,SAASH,EAAA,EACnBG,EAAE,MAAQ,UAAUlB,EAAA,CAC1B,EACA,YAAY,oBACZ,aAAW,oBACX,UAAU,sCACV,cAAaC,EAAS,GAAGA,CAAM,SAAW,OAC1C,UAAS,EAAA,CAAA,EAEXjB,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAAS+B,EACT,SAAU,CAACH,EAAK,KAAA,EAChB,UAAU,4JACV,cAAaX,EAAS,GAAGA,CAAM,OAAS,OAEvC,SAAAU,CAAA,CAAA,EAEH3B,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASgB,EACT,UAAU,qIACV,cAAaC,EAAS,GAAGA,CAAM,MAAQ,OACxC,SAAA,QAAA,CAAA,CAED,CAAA,CAAA,CAGN,CCtBO,MAAMkB,GAAc,cAKdC,GAAqB,IAErBC,EAAsB,QAEtBC,GAAoB,MAEpBC,EAAgB,CAAE,QAAS,UAAW,GAAI,KAAM,QAAS,SAAA,EA2DhEC,GAAc,oBACdC,EAAU,IACVC,EAAa,aACbC,EAAgB,gBAChBC,GAAc,cACdC,GAAkB,kBAExB,SAASC,EAASC,EAA0C,CAC1D,MAAO,CAAC,CAACA,GAAK,OAAOA,GAAM,UAAY,CAAC,MAAM,QAAQA,CAAC,CACzD,CAEA,SAASC,EAAQD,EAAsB,CACrC,OAAI,OAAOA,GAAM,SAAiBA,EAAI,CAACA,CAAC,EAAI,CAAA,EACvC,MAAM,QAAQA,CAAC,EACbA,EAAE,OAAQE,GAAmB,OAAOA,GAAM,UAAYA,EAAE,OAAS,CAAC,EAD3C,CAAA,CAEhC,CAGO,SAASC,EAAc1D,EAAgF,CAC5G,MAAM2D,EAAM3D,GAAA,YAAAA,EAAc2C,IAC1B,GAAI,CAACW,EAASK,CAAG,GAAK,CAACL,EAASK,EAAI,QAAQ,EAAG,OAC/C,MAAMjB,EAAIiB,EAAI,SAEd,OADkBL,EAASZ,EAAE,KAAK,GAAK,OAAOA,EAAE,MAAS,UAAYA,EAAE,QAAU,GAC7DiB,EAA+B,MACrD,CAGO,SAASC,GAAeC,EAA+E,CAC5G,MAAMC,EAAaR,EAASO,GAAA,YAAAA,EAAQ,UAAU,EAAKA,EAAQ,WAAyC,CAAA,EAC9FE,EAAkC,CAAA,EACxC,SAAW,CAACC,EAAOC,CAAG,IAAK,OAAO,QAAQH,CAAU,EAAG,CACrD,MAAMI,EAASZ,EAASW,CAAG,EAAIP,EAAcO,CAAG,EAAI,OAChDC,IAAQH,EAAKC,CAAK,EAAIE,EAC5B,CACA,OAAOH,CACT,CAGO,SAASI,GAAcF,EAAoC,CAChE,MAAO,UAAWA,EAAI,UAAYX,EAASW,EAAI,SAAS,KAAK,EAAIA,EAAI,SAAS,MAAQ,IACxF,CAGO,SAASG,GACdC,EACAnG,EAC6F,CAC7F,MAAMoG,EAAiC,CAAA,EACvC,SAAW,CAACC,EAAGhB,CAAC,IAAK,OAAO,QAAQc,EAAM,QAAU,CAAA,CAAE,EAAG,CACvD,GAAI,OAAOd,GAAM,SAAU,SAC3B,MAAMiB,EAAWC,EAAgBlB,EAAGrF,CAAG,EACvC,GAAI,CAACsG,GAAYA,IAAavB,EAAS,OAAO,KAC9CqB,EAAOC,CAAC,EAAIC,CACd,CACA,MAAME,EAAQ,CAAC,GAAIL,EAAM,KAAO,CAACA,EAAM,IAAI,EAAI,CAAA,EAAK,GAAGb,EAAQa,EAAM,KAAK,CAAC,EAC3E,GAAI,CAACK,EAAM,QAAU,CAAC,OAAO,KAAKJ,CAAM,EAAE,OAAQ,OAAO,KACzD,MAAMK,EAASN,EAAM,QAAUA,EAAM,SAAWvB,GAAoBuB,EAAM,OAAS,OACnF,MAAO,CAAE,GAAIK,EAAM,OAAS,CAAE,MAAAA,CAAA,EAAU,CAAA,EAAK,OAAAJ,EAAQ,GAAIK,EAAS,CAAE,OAAAA,CAAA,EAAW,CAAA,EAAK,MAAO/B,EAAA,CAC7F,CAEA,SAASgC,EAAUrB,EAA4C,CAC7D,GAAID,EAASC,CAAC,EAAG,OAAOA,EACxB,GAAI,OAAOA,GAAM,UAAY,CAACA,EAAG,OAAO,KACxC,GAAI,CACF,MAAMsB,EAAS,KAAK,MAAMtB,CAAC,EAC3B,OAAOD,EAASuB,CAAM,EAAIA,EAAS,IACrC,MAAQ,CACN,OAAO,IACT,CACF,CAGO,SAASC,GAAiBC,EAAyC,CACxE,MAAO,CACL,WAAYA,EACZ,SAAUzB,EAASyB,EAAI,QAAQ,EAAIA,EAAI,SAAWH,EAAUG,EAAI,QAAQ,EACxE,SAAUH,EAAUG,EAAI,QAAQ,EAChC,QAASH,EAAUG,EAAI,kBAAkB,EACzC,SAAUH,EAAUG,EAAI,gBAAgB,CAAA,CAE5C,CAGA,SAASC,GAAS9G,EAAoC,CACpD,MAAM+G,EAAW/G,EAAI,UAAY,CAAA,EAC3BgH,EAAcD,EAAS5B,EAAe,EAC5C,GAAI,MAAM,QAAQ6B,CAAW,SAAU,IAAI,IAAI1B,EAAQ0B,CAAW,CAAC,EACnE,MAAMC,EAAgB9G,EAAQH,EAAI,SAAU,kBAAkB,EAC9D,GAAIoF,EAAS6B,CAAa,EAAG,OAAO,IAAI,IAAI,OAAO,KAAKA,CAAa,CAAC,EACtE,GAAI,MAAM,QAAQF,EAAS9B,CAAa,CAAC,EAAG,CAC1C,MAAMiC,EAAU,IAAI,IAAI5B,EAAQyB,EAAS9B,CAAa,CAAC,CAAC,EACxD,OAAO,IAAI,IAAIK,EAAQyB,EAAS/B,CAAU,CAAC,EAAE,OAAQqB,GAAM,CAACa,EAAQ,IAAIb,CAAC,CAAC,CAAC,CAC7E,CACA,WAAW,GACb,CAGA,SAASc,GAAYC,EAAkBC,EAAyC,CAC9E,GAAI,CAACA,EAAW,OAAOD,EACvB,MAAME,MAAW,IACjB,OAAOF,EAAO,QAAS/B,GAAM,CAC3B,MAAMkC,GAAKD,EAAK,IAAIjC,CAAC,GAAK,GAAK,EAC/B,OAAAiC,EAAK,IAAIjC,EAAGkC,CAAC,EACN,CAAClC,EAAG,GAAGA,CAAC,GAAGgC,CAAS,GAAGE,CAAC,EAAE,CACnC,CAAC,CACH,CAEA,SAASC,GAAYzB,EAAgB/F,EAAoC,CACvE,MAAMyH,MAAc,IACdJ,EAAY,OAAOtB,EAAI,WAAc,UAAYA,EAAI,UAAYA,EAAI,UAAY,OACvF,UAAW2B,KAAU3B,EAAI,IAAM,CAACpB,CAAmB,GACpC+C,IAAW/C,EACpB,CAAC,GAAGmC,GAAS9G,CAAG,CAAC,EACjBmH,GAAY7B,EAAQxF,EAAe4H,EAAQ1H,CAA8B,CAAC,EAAGqH,CAAS,GACrF,QAAShB,GAAMoB,EAAQ,IAAIpB,CAAC,CAAC,EAEpC,OAAOoB,CACT,CAGA,SAASE,GAAe3H,EAAuB4H,EAAiC,CAC9E,MAAMC,EAAQ1H,EAAQH,EAAI,SAAUkF,EAAW,EACzC4C,EAAO1C,EAASyC,CAAK,EAAIA,EAAMD,CAAG,EAAI,OAC5C,OAAOxC,EAAS0C,CAAI,GAAK,OAAOA,EAAK,OAAU,UAAYA,EAAK,MAAQA,EAAK,MAAQ,MACvF,CAEA,SAASC,GAAQhC,EAAgBc,EAAgD,CAC/E,GAAKA,EACL,UAAWmB,KAAQjC,EAAI,SAAW,CAAA,EAAI,CACpC,MAAMkC,EAAa3C,EAAQ0C,EAAK,IAAI,EACpC,GAAI,GAACC,EAAW,QAAU,OAAOD,EAAK,OAAU,WAC5C/G,EAAegH,EAAYpB,CAAG,SAAUmB,EAAK,KACnD,CAEF,CAGA,SAASE,EAAUrB,EAAwB,CACzC,MAAMpB,EAAMoB,EAAI,WAAW,WACrBsB,EAAK1C,aAAe,KAAOA,EAAI,QAAA,EAAY,OAAOA,GAAQ,SAAW,KAAK,MAAMA,CAAG,EAAI,IAC7F,OAAO,OAAO,MAAM0C,CAAE,EAAI,EAAIA,CAChC,CAOA,SAASC,GACPrC,EACA/F,EACAqI,EAC0D,OAC1D,MAAMf,MAAW,IACXgB,EAAgE,CAAA,EAChEC,EAAO,CAACX,EAAaY,EAA8C,CAAA,IAAO,CAC1E,CAACZ,GAAOA,IAAQ7C,GAAWuC,EAAK,IAAIM,CAAG,IAC3CN,EAAK,IAAIM,CAAG,EACZU,EAAI,KAAK,CAAE,IAAAV,EAAK,GAAGY,EAAO,EAC5B,EACMhE,EAAIuB,EAAI,SACd,GAAI,UAAWvB,EAAG,CAChB,MAAMnE,EAAW0F,EAAI,KAAOjB,GACtB2D,MAAa,IACnB,UAAW5B,KAAOwB,EAAM,CACtB,MAAMT,EAAMrB,EAAgBlG,EAAUwG,CAAG,EACnC6B,EAAOD,EAAO,IAAIb,CAAG,GACvB,CAACc,GAAQR,EAAUrB,CAAG,EAAIqB,EAAUQ,CAAI,IAAGD,EAAO,IAAIb,EAAKf,CAAG,CACpE,CACA,UAAWA,KAAOwB,EAAM,CACtB,MAAMT,EAAMrB,EAAgBlG,EAAUwG,CAAG,EACzC0B,EAAKX,EAAK,CAAE,IAAKa,EAAO,IAAIb,CAAG,EAAG,CACpC,CACF,SAAW,SAAUpD,EACnBc,EAAQxF,EAAe0E,EAAE,KAAMxE,CAA8B,CAAC,EAAE,QAASqG,GAAMkC,EAAKlC,CAAC,CAAC,MACjF,CACL,MAAMsC,EAASnE,EAAE,OAAS1E,EAAe0E,EAAE,OAAQxE,CAA8B,EAAI,OACrF,UAAW4H,KAAOtC,GAAQsD,EAAA5I,EAAI,WAAJ,YAAA4I,EAAe5D,EAAW,EAClDuD,EAAKX,EAAKxC,EAASuD,CAAM,GAAKf,KAAOe,EAAS,CAAE,MAAOA,EAAOf,CAAG,CAAA,EAAM,CAAA,CAAE,CAE7E,CACA,OAAOU,CACT,CAOO,SAASO,EAAc9C,EAAgB/F,EAAuBqI,EAAoB,CAAA,EAAkB,CACzG,MAAMZ,EAAUD,GAAYzB,EAAK/F,CAAG,EAC9B8I,EAAQ,UAAW/C,EAAI,SACvBgD,EAAyBX,GAAgBrC,EAAK/F,EAAKqI,CAAI,EAAE,IAAK7D,GAAM,CACxE,GAAIiD,EAAQ,IAAIjD,EAAE,GAAG,EAAG,MAAO,CAAE,GAAGA,EAAG,MAAOK,EAAc,EAAA,EAC5D,MAAMiD,EAAOgB,EAAQnB,GAAe3H,EAAKwE,EAAE,GAAG,EAAIuD,GAAQhC,EAAKvB,EAAE,GAAG,EACpE,OAAOsD,EAAO,CAAE,GAAGtD,EAAG,MAAOK,EAAc,QAAS,KAAAiD,CAAA,EAAS,CAAE,GAAGtD,EAAG,MAAOK,EAAc,OAAA,CAC5F,CAAC,EACKmE,EAASzD,GAAmBwD,EAAQ,OAAQvE,GAAMA,EAAE,QAAUe,CAAC,EAAE,OACjE0D,EAAUD,EAAMnE,EAAc,OAAO,EAC3C,MAAO,CACL,QAAAkE,EACA,OAAQ,CACN,SAAUA,EAAQ,OAClB,GAAIC,EAAMnE,EAAc,EAAE,EAC1B,QAASmE,EAAMnE,EAAc,OAAO,EACpC,QAAAoE,EACA,YAAaA,CAAA,CACf,CAEJ,CAGO,SAASC,GAAetH,EAA8B,CAC3D,KAAM,CAAE,OAAAuH,GAAWvH,EACbwH,EAAQ,CAAC,GAAGD,EAAO,EAAE,OAAOA,EAAO,QAAQ,KAAK,EAChDE,MAAa,IACnB,UAAW7E,KAAK5C,EAAO,QACjB4C,EAAE,QAAUK,EAAc,SAAWL,EAAE,MAAM6E,EAAO,IAAI7E,EAAE,MAAO6E,EAAO,IAAI7E,EAAE,IAAI,GAAK,GAAK,CAAC,EAEnG,SAAW,CAACsD,EAAMP,CAAC,IAAK8B,EAAQD,EAAM,KAAK,GAAG7B,CAAC,IAAIO,CAAI,EAAE,EACzD,OAAOsB,EAAM,KAAK,KAAK,CACzB,CCtTA,MAAME,EAA0C,CAAE,QAAS,UAAW,GAAI,KAAM,QAAS,SAAA,EAEzF,SAASC,GAAU,CAAE,MAAAC,GAAiC,CACpD,OAAIA,IAAU3E,EAAc,GAAWvC,EAAAA,IAACmH,GAAA,CAAa,UAAU,uCAAuC,YAAa,EAAG,cAAW,EAAA,CAAC,EAC9HD,IAAU3E,EAAc,QAAgBvC,EAAAA,IAACoH,GAAA,CAAK,UAAU,uCAAuC,YAAa,EAAG,cAAW,EAAA,CAAC,QACvHC,GAAA,CAAO,UAAU,sCAAsC,YAAa,EAAG,cAAW,GAAC,CAC7F,CAQO,SAASC,GAAe,CAC7B,MAAAC,EAAO,KAAAC,EAAM,QAAAC,EAAS,QAAAC,EAAS,QAAAC,EAAS,OAAAC,EAAQ,QAAAhD,EAAS,MAAAxE,EAAO,SAAAyH,EAAU,UAAA9G,EAAW,SAAAC,CACvF,EAaG,OACD,MAAMtD,EAAM6J,EAAM,KAAOE,EACnBK,EAAOP,EAAM,QAAUhF,EAAc,GACrCwF,EAAaR,EAAM,QAAUhF,EAAc,QAAUgF,EAAM,MAAQP,EAAW,QAAUA,EAAWO,EAAM,KAAK,EAEpH,OACExH,EAAAA,KAAC,KAAA,CACC,UAAU,8EACV,cAAa,gBAAgBwH,EAAM,GAAG,GACtC,aAAYA,EAAM,MAElB,SAAA,CAAAvH,EAAAA,IAAC,OAAA,CAAK,UAAU,SAAS,SAAAA,EAAAA,IAACiH,IAAU,MAAOM,EAAM,MAAO,CAAA,CAAE,EAC1DvH,MAAC,MAAA,CAAI,UAAU,iEACZ,WAAQ,IAAKgI,GACZjI,EAAAA,KAAC,QAAqB,UAAW,mBAAmB+H,EAAO,sBAAwB,mBAAmB,GACpG,SAAA,CAAA/H,EAAAA,KAAC,OAAA,CAAK,UAAU,UAAW,SAAA,CAAAiI,EAAI,MAAM,IAAA,EAAE,EACvChI,EAAAA,IAACiI,GAAA,CAAe,IAAKC,GAAwBF,EAAI,MAAOR,EAAM9J,CAAG,EAAG,OAAQsK,EAAI,MAAA,CAAQ,CAAA,CAAA,EAF/EA,EAAI,KAGf,CACD,EACH,EACAhI,EAAAA,IAAC,OAAA,CACC,UAAW,uCAAuC8H,EAAO,sBAAwBP,EAAM,QAAUhF,EAAc,QAAU,sBAAwB,oBAAoB,GACrK,cAAa,gBAAgBgF,EAAM,GAAG,GAErC,SAAAQ,CAAA,CAAA,GAEDJ,EAAQ,OAAS,GAAKC,GAAUxH,IAChCL,EAAAA,KAAC,OAAA,CAAK,UAAU,2CACb,SAAA,EAAAuG,EAAAsB,GAAA,YAAAA,EAAQ,OAAO,OAAf,MAAAtB,EAAqB,UACpBtG,EAAAA,IAAC0B,GAAA,CACC,MAAOkG,EAAO,OAAO,MACrB,UAAYhG,GAASb,EAAUa,CAAI,EACnC,SAAAZ,EACA,OAAQ,eAAeuG,EAAM,GAAG,EAAA,CAAA,EAEhCK,EACF5H,EAAAA,IAACa,GAAA,CACC,QAASoD,EAAgB2D,EAAO,OAAO,SAAW,GAAIlK,CAAG,EACzD,UAAW,IAAMqD,EAAA,EACjB,SAAAC,EACA,OAAQ,kBAAkBuG,EAAM,GAAG,EAAA,CAAA,QAGpC,OAAA,CAAK,UAAU,aACb,SAAAI,EAAQ,IAAKQ,GACZnI,EAAAA,IAAC,SAAA,CAEC,KAAK,SACL,QAAS,IAAM6H,EAASM,CAAK,EAC7B,SAAUvD,EACV,UAAU,oKACV,cAAa,iBAAiB2C,EAAM,GAAG,GAEtC,WAAM,OAAO,KAAA,EAPTY,EAAM,KAAA,CASd,EACH,EAED/H,GACCJ,EAAAA,IAAC,OAAA,CAAK,UAAU,sDAAsD,cAAa,gBAAgBuH,EAAM,GAAG,GAAK,SAAAnH,CAAA,CAAM,CAAA,EAE3H,EAEDmH,EAAM,KACLvH,EAAAA,IAACQ,GAAA,CAAiB,GAAI,uBAAuB,OAAO+G,EAAM,IAAI,WAAW,EAAE,CAAC,EAAA,CAAI,CAAA,CAAA,CAAA,CAIxF,CCjGA,SAASa,GAAe3E,EAAgB/F,EAAoB,CAC1D,MAAMmG,EAAQF,GAAcF,CAAG,EACzB4E,EAASxE,EAAQD,GAAmBC,EAAOnG,CAAG,EAAI,KACxD,OAAK2K,EACE,CACL,MAAOA,EAAO,MACd,OAAQA,EAAO,OACf,OAAQA,EAAO,OACf,MAAOA,EAAO,MACd,QAASC,GAAoB,CAAE,IAAK7E,EAAI,IAAK,QAASA,EAAI,QAAS,EAAK,WAAuB,MAAA,EAN7E,IAQtB,CAQO,SAAS8E,GACdlF,EACA3F,EAC4B,CAC5B,MAAM6F,EAAO,OAAO,QAAQH,GAAeC,CAAM,CAAC,EAC5CmF,EAAO9K,GAAO,CAAA,EACd+K,EAAUlF,EAAK,IAAI,CAAC,CAAA,CAAGE,CAAG,IAAM2E,GAAe3E,EAAK+E,CAAI,CAAC,EACzDE,EAAQC,GAAW,CACvB,QAASF,EAAQ,IAAKG,IAAO,CAC3B,GAAGC,GAAoBD,GAAK,EAAE,EAC9B,QAAS,CAAC,CAACA,CAAA,EACX,CAAA,CACH,EAEKE,EAAoC,CAAA,EAC1C,OAAAvF,EAAK,QAAQ,CAAC,CAACC,EAAOC,CAAG,EAAGsF,IAAM,CAChC,GAAI,CAACN,EAAQM,CAAC,EAAG,CACfD,EAAMtF,CAAK,EAAI+C,EAAc9C,EAAK+E,CAAI,EACtC,MACF,CACA,MAAMQ,EAAON,EAAMK,CAAC,EACpB,GAAI,CAACC,EAAK,UAAW,CACnBF,EAAMtF,CAAK,EAAI,KACf,MACF,CACA,MAAMuC,EAAoBiD,EAAK,KAAK,YAAY,IAAK9G,GAAMoC,GAAiBpC,CAAuC,CAAC,EACpH4G,EAAMtF,CAAK,EAAI+C,EAAc9C,EAAK+E,EAAMzC,CAAI,CAC9C,CAAC,EACM+C,CACT,CAGO,SAASG,GAAcH,EAAmE,CAC/F,MAAMI,EAAS,OAAO,QAAQJ,CAAK,EAAE,OAAO,CAAC,EAAG/F,CAAC,IAAMA,IAAM,IAAI,EACjE,OAAKmG,EAAO,OACL,OAAO,YAAYA,EAAO,IAAI,CAAC,CAAC1F,EAAOT,CAAC,IAAM,CAACS,EAAOT,EAAG,MAAM,CAAC,CAAC,EAD7C,IAE7B,CCtDO,MAAMoG,GAAe,eAEfC,EAAsB,CACjC,QAAS,UACT,KAAM,OACN,KAAM,OACN,OAAQ,QACV,EA6BMC,GAAwD,CAC5D,QAAS,CAAC9G,EAAc,OAAO,EAC/B,KAAM,CAACA,EAAc,QAASA,EAAc,OAAO,EACnD,KAAM,CAACA,EAAc,OAAO,EAC5B,OAAQ,CAACA,EAAc,OAAO,CAChC,EAEA,SAASO,EAASC,EAA0C,CAC1D,MAAO,CAAC,CAACA,GAAK,OAAOA,GAAM,UAAY,CAAC,MAAM,QAAQA,CAAC,CACzD,CAGO,SAASuG,EAAiBC,EAAkD,CACjF,MAAMC,EAA4B,CAAA,EAClC,OAAI1G,EAASyG,EAAO,eAAe,GAAGC,EAAM,KAAKJ,EAAoB,OAAO,EACxEtG,EAASyG,EAAO,IAAI,GAAGC,EAAM,KAAKJ,EAAoB,IAAI,EAC1DtG,EAASyG,EAAO,IAAI,GAAK,OAAOA,EAAO,KAAK,OAAU,UAAYA,EAAO,KAAK,OAChFC,EAAM,KAAKJ,EAAoB,IAAI,EAEjCG,EAAO,SAAW,IAAMC,EAAM,KAAKJ,EAAoB,MAAM,EAC1DI,EAAM,SAAW,EAAIA,EAAM,CAAC,EAAI,IACzC,CAGO,SAASC,GAAkBjK,EAA4E,CAC5G,MAAM2D,EAAM3D,GAAA,YAAAA,EAAc2J,IAC1B,OAAK,MAAM,QAAQhG,CAAG,EACfA,EAAI,OAAQuG,GACjB5G,EAAS4G,CAAC,GAAK,OAAOA,EAAE,OAAU,UAAY,CAAC,CAACA,EAAE,OAASJ,EAAiBI,CAA+B,IAAM,IAAI,EAFvF,CAAA,CAGlC,CAOO,SAASC,GAAaJ,EAAyBhC,EAAoBf,EAAyB,CACjG,MAAMoD,EAAON,EAAiBC,CAAM,EAEpC,MADI,CAACK,IACDA,IAASR,EAAoB,QAAU,CAAC7B,EAAM,IAAM,CAACf,GAAc,IAC1D+C,EAAO,OAAS,OAAYF,GAAaO,CAAI,EACtD,MAAM,QAAQL,EAAO,IAAI,EAAIA,EAAO,KAAO,CAACA,EAAO,IAAI,GAC/C,SAAShC,EAAM,KAAK,CAClC,CCnFA,MAAMsC,GAAoC,CAAC,CAAE,MAAO,OAAQ,MAAO,mBAAoB,EACjFC,EAAmB,WACnBC,GAA2B,CAACC,EAAuB,YAAaA,EAAuB,YAAY,EAEzG,SAASlH,EAASC,EAA0C,CAC1D,MAAO,CAAC,CAACA,GAAK,OAAOA,GAAM,UAAY,CAAC,MAAM,QAAQA,CAAC,CACzD,CAGA,SAASkH,EAAMvM,EAAoBwM,EAAa5E,EAAiC,CAC/E,MAAMR,EAASjH,EAAQH,EAAI,SAAUwM,CAAG,EAClC9L,EAAQ0E,EAASgC,CAAM,EAAIA,EAAOQ,CAAG,EAAI,OAC/C,OAAO,OAAOlH,GAAU,SAAWA,EAAQ,MAC7C,CAQA,SAAS+L,GAAQ5C,EAAoB7J,EAA0D,CAC7F,MAAM0I,EAAOvI,EAAQH,EAAI,SAAU,kBAAkB,EAC/C0M,EAAevM,EAAQH,EAAI,SAAU,aAAa,EAClD2M,EAAIvH,EAASsD,CAAI,GAAKtD,EAASsD,EAAKmB,EAAM,GAAG,CAAC,EAAInB,EAAKmB,EAAM,GAAG,EAA+B,KAC/F+C,EAAUD,GAAKvH,EAASuH,EAAE,OAAO,EAAIA,EAAE,QACzCvH,EAASsH,CAAY,GAAKtH,EAASsH,EAAa7C,EAAM,GAAG,CAAC,EAAI6C,EAAa7C,EAAM,GAAG,EACpF,OACEgD,EAAK,OAAOF,GAAA,YAAAA,EAAG,KAAO,SAAWA,EAAE,GAAKA,EAAI,OAAYJ,EAAMvM,EAAK,kBAAmB6J,EAAM,GAAG,EAC/FiD,EAAQ,OAAOH,GAAA,YAAAA,EAAG,QAAU,SAAWA,EAAE,MAAQA,EAAI,OAAYJ,EAAMvM,EAAK,kBAAmB6J,EAAM,GAAG,EAC9G,MAAO,CACL,QAASA,EAAM,IACf,GAAIgD,GAAM,GACV,GAAID,EAAU,CAAE,QAAAA,CAAA,EAAY,CAAA,EAC5B,GAAIE,EAAQ,CAAE,MAAAA,CAAA,EAAU,CAAA,EACxB,GAAIjD,EAAM,QAAU,OAAY,CAAE,MAAOA,EAAM,OAAU,CAAA,CAAC,CAE9D,CAyBO,SAASkD,GAAa,CAAE,SAAAC,EAAU,OAAArH,EAAQ,kBAAAsH,GAAkC,OACjF,MAAMjN,EAAMiN,GAAqB,CAAA,EAC3BC,EAAOrC,GAAW,CAAE,WAAY,CAAE,CAACmC,CAAQ,EAAGrH,GAAU,EAAC,CAAE,EAAK3F,CAAG,EAAEgN,CAAQ,EAC7EjH,EAAMP,EAAcG,CAAM,EAC1BmD,EAAQ,CAAC,CAAC/C,GAAO,UAAWA,EAAI,SAChCiE,GAAWrE,GAAA,YAAAA,EAAS,kBAAoDwG,GACxEgB,EAAUpB,GAAkBpG,CAAM,EAClC1B,GAAS0B,GAAA,YAAAA,EAAQ,QAAgC,iBACjDyH,EAAazH,GAAA,YAAAA,EAAQ,YACrB0H,EAAS,SAAQzE,EAAA5I,EAAI,aAAJ,YAAA4I,EAAwD,KAAM,EAAE,EAEjF0E,EAAYC,GAAA,EACZC,EAAQ1J,GAAA,EACR,CAACoG,EAAQuD,CAAS,EAAIrJ,EAAAA,SAAuD,IAAI,EACjF,CAACsJ,GAAYC,CAAa,EAAIvJ,EAAAA,SAAwB,IAAI,EAC1D,CAACwJ,GAAQC,CAAS,EAAIzJ,EAAAA,SAAiC,CAAA,CAAE,EAEzD0J,EAAO,MAAOjE,EAAoBY,EAAsBvG,IAAiC,CAC7FyJ,EAAc9D,EAAM,GAAG,EACvBgE,EAAWE,IAAU,CAAE,GAAGA,EAAM,CAAClE,EAAM,GAAG,EAAG,EAAA,EAAK,EAClD,GAAI,CACF,MAAMyD,EAAU,YAAY,CAAE,GAAID,EAAQ,MAAOL,EAAU,OAAQvC,EAAM,MAAO,MAAOZ,EAAM,IAAK,KAAA3F,EAAM,CAC1G,OAAS8J,EAAK,CACZ,MAAM5K,EAAW4K,EAAc,QAC/BH,EAAWE,KAAU,CAAE,GAAGA,GAAM,CAAClE,EAAM,GAAG,EAAGzG,CAAA,EAAU,EACvD,MAAM6K,EAAUD,aAAeE,IAAY9I,EAAS4I,EAAI,IAAI,EAAIA,EAAI,KAAK,QAAU,OAC/E,OAAOC,GAAY,UAAY5B,GAAe,SAAS4B,CAAO,GAChET,EAAMpB,EAAkB,IAAM0B,EAAKjE,EAAOY,EAAOvG,CAAI,EAAG,CAAE,MAAOd,EAAS,CAE9E,QAAA,CACEuK,EAAc,IAAI,CACpB,CACF,EAEMQ,EAAM,CAACtE,EAAoBY,EAAsBvG,IAAkB,CACvEuJ,EAAU,IAAI,EACdD,EAAMpB,EAAkB,IAAM0B,EAAKjE,EAAOY,EAAOvG,CAAI,CAAC,CACxD,EAEMkK,GAAU,CAACvE,EAAoBY,IAAyB,OACxDA,EAAM,OAAO,UAAW7B,EAAA6B,EAAM,OAAO,OAAb,MAAA7B,EAAmB,UAAW6E,EAAU,CAAE,IAAK5D,EAAM,IAAK,MAAAY,EAAO,EACxF0D,EAAItE,EAAOY,CAAK,CACvB,EAEM4D,GAAcxE,GAClBsD,EACG,IAAI,CAACtB,EAAQyC,KAAW,CAAE,OAAAzC,EAAQ,MAAAyC,CAAA,EAAQ,EAC1C,OAAO,CAAC,CAAE,OAAAzC,CAAA,IAAaI,GAAaJ,EAAQhC,EAAOf,CAAK,CAAC,EAE9D,cACG,MAAA,CAAI,iBAAgBkE,EAAU,cAAa,iBAAiBA,CAAQ,GACnE,SAAA,CAAA3K,EAAAA,KAAC,MAAA,CAAI,UAAU,4CACb,SAAA,CAAAC,EAAAA,IAACL,IAAY,SAAAgC,CAAA,CAAM,EAClBiJ,GACC5K,EAAAA,IAAC,OAAA,CAAK,UAAU,wCAAwC,cAAa,mBAAmB0K,CAAQ,GAC7F,SAAA9D,GAAegE,CAAI,CAAA,CACtB,CAAA,EAEJ,EACCE,GAAc9K,EAAAA,IAACC,GAAA,CAAa,SAAA6K,CAAA,CAAW,EACtCF,EAEEA,EAAK,QAAQ,SAAW,QACzB,IAAA,CAAE,UAAU,yCAAyC,cAAa,gBAAgBF,CAAQ,GAAI,SAAA,mBAAA,CAAiB,QAE/G,KAAA,CAAG,UAAU,OAAO,cAAa,eAAeA,CAAQ,GACtD,WAAK,QAAQ,IAAKnD,GACjBvH,EAAAA,IAACsH,GAAA,CAEC,MAAAC,EACA,KAAM4C,GAAQ5C,EAAO7J,CAAG,EACxB,QAASA,EACT,QAAAgK,EACA,QAASqD,EAASgB,GAAWxE,CAAK,EAAI,CAAA,EACtC,QAAQK,GAAA,YAAAA,EAAQ,OAAQL,EAAM,IAAMK,EAAO,MAAQ,KACnD,QAASwD,KAAe7D,EAAM,IAC9B,MAAO+D,GAAO/D,EAAM,GAAG,GAAK,OAC5B,SAAWY,GAAU2D,GAAQvE,EAAOY,CAAK,EACzC,UAAYvG,GAASgG,GAAUiE,EAAItE,EAAOK,EAAO,MAAOhG,CAAI,EAC5D,SAAU,IAAMuJ,EAAU,IAAI,CAAA,EAXzB5D,EAAM,GAAA,CAad,CAAA,CACH,EArBAvH,MAAC,IAAA,CAAE,UAAU,kCAAkC,cAAa,kBAAkB0K,CAAQ,GAAI,mCAAuB,CAqBjH,EAEJ,CAEJ"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{j as e,a as c,b as Ne}from"./vendor-query-DvWWuNIB.js";import{al as oe,bC as we,bD as ce,bE as ke,M as ie,ah as F,ap as Se,aq as Ce,$ as Ee,ao as ve,Q as Te,Z as De,bF as Ae,bG as b,bH as _e,b0 as Ie,bI as Pe,ac as U,bJ as Me,bs as Fe}from"./index-ygxyAKcc.js";import{a as W,B as Re,au as de,aM as xe,bg as Le,aL as Be}from"./vendor-icons-en0_uSRD.js";import{s as Oe}from"./metadata-display-B7X5hGxG.js";import{F as Ue}from"./escalation-items-DFGRwo49.js";import{X as We,R as He,k as $e}from"./RosterWidget-BJMx0a8Z.js";import{a as qe,u as Ve}from"./vendor-react-_9U4mKFr.js";import"./UserName-DKXnK7DD.js";function Xe(t,s){return Array.isArray(t)?t.includes(s):t===s}const Je=2;function ne(t){const s=t==null?void 0:t.scan_done;if(!s||typeof s!="object"||Array.isArray(s))return null;const n=s,a=n.return;if(typeof a!="string"||!(a==="home"||a.startsWith("/")))return null;const u=n.after_seconds;return{return:a,...typeof u=="number"&&u>=0?{after_seconds:u}:{}}}function Ke(t,s){return t.return==="home"?s:t.return}function Qe(t,s){const n=t.policy?t:s;if(!(n!=null&&n.policy))return null;const a=Ke(n.policy,n.homePath);return a?{path:a,afterMs:(n.policy.after_seconds??Je)*1e3}:null}function Ye({stationName:t,primedName:s}){return e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-center text-center py-24",children:[e.jsx(W,{className:"w-10 h-10 text-accent-muted mb-8",strokeWidth:1}),e.jsx("h1",{className:"text-3xl font-light text-text-primary tracking-tight",children:t}),e.jsx("div",{className:"w-16 border-t border-surface-border my-8"}),s?e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"text-lg text-text-secondary",children:"Scan the next item"}),e.jsxs("p",{className:"text-sm text-text-tertiary mt-2",children:["Badged in as ",s]})]}):e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"text-lg text-text-secondary",children:"Scan your badge to begin"}),e.jsx("p",{className:"text-sm text-text-tertiary mt-2",children:"or scan an item"})]})]})}function Ge(t){const s=Math.floor(t/60),n=t%60;return`${s}:${String(n).padStart(2,"0")}`}function Ze(){const{identity:t}=oe(),s=we();return t?e.jsxs("div",{className:"flex items-center gap-2.5 pb-3 mb-6 border-b border-surface-border",children:[e.jsx(Re,{className:"w-4 h-4 text-status-success shrink-0",strokeWidth:1.5}),e.jsxs("span",{className:"text-sm font-medium text-text-primary",children:["Hi ",t.displayName]}),t.expiresAt&&e.jsx("span",{className:"ml-auto text-sm font-mono tabular-nums text-text-tertiary",children:Ge(s)})]}):null}function me(t,s){return!t.withheld||s}function ze(t,s,n){return t.find(a=>!!a.code&&a.code===n&&me(a,s))??null}function et(t){return t==null||t===""?"—":typeof t=="boolean"?t?"Yes":"No":typeof t=="object"?JSON.stringify(t):String(t)}function tt({label:t,value:s,format:n}){return e.jsxs("div",{className:"flex items-baseline gap-4 py-2",children:[e.jsx("span",{className:"w-32 shrink-0 text-2xs uppercase tracking-wide text-text-quaternary",children:t}),e.jsx("span",{className:"text-sm text-text-primary break-words","data-testid":"station-fact-value",children:n?e.jsx(Ue,{raw:s,format:n}):s})]})}function q(){return e.jsx("span",{className:"text-text-quaternary select-none",children:"·"})}function st({response:t,hasActingIdentity:s,selfId:n,busy:a,onExecute:u,onWithheldSelect:g}){var w,A;const{pushCodeInterceptor:y}=ce(),[f,l]=c.useState(null),j=t.escalation??{},N=t.choices??[],v=j.metadata??{},T=r=>{r.confirm?l(r):u(r)},B=c.useRef({choices:N,hasActingIdentity:s,select:T});B.current={choices:N,hasActingIdentity:s,select:T},c.useEffect(()=>y(r=>{const S=B.current,_=ze(S.choices,S.hasActingIdentity,r);return _?(S.select(_),!0):!1}),[y]);const I=j.assigned_to??null,R=I?I===n?"Claimed by you":"Claimed":"Unclaimed",h=I===n?"text-accent":"text-text-secondary",k=[j.type,j.subtype].filter(Boolean).join(" · "),D=t.facts?t.facts.map(r=>[r.label,r.value,r.format]):Oe(v);return e.jsxs("div",{className:"flex-1 min-h-0 flex flex-col max-w-form",children:[e.jsxs("div",{children:[((w=t.rule)==null?void 0:w.name)&&e.jsx("div",{className:"text-2xs font-semibold uppercase tracking-widest text-accent mb-2",children:t.rule.name}),e.jsx("h2",{className:"text-2xl font-medium leading-tight text-text-primary mb-2",children:j.description||k||"Located item"}),e.jsxs("div",{className:"flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-text-secondary mb-5",children:[e.jsx("span",{children:String(j.role??"—")}),k&&e.jsxs(e.Fragment,{children:[e.jsx(q,{}),e.jsx("span",{children:k})]}),e.jsx(q,{}),e.jsx("span",{className:h,children:R}),typeof j.created_at=="string"&&e.jsxs(e.Fragment,{children:[e.jsx(q,{}),e.jsx("span",{children:ke(j.created_at)})]})]}),D.length>0&&e.jsx("div",{className:"divide-y divide-surface-border border-t border-surface-border",children:D.map(([r,S,_],x)=>e.jsx(tt,{label:r,value:et(S),format:_},`${x}-${r}`))})]}),e.jsx("div",{className:"mt-8 space-y-3",children:N.map(r=>{const S=me(r,s);return e.jsx("div",{children:e.jsx("button",{type:"button",disabled:a,onClick:()=>S?T(r):g(r),className:"w-full text-left px-5 py-4 text-lg text-text-primary border border-surface-border rounded hover:bg-surface-sunken transition-colors disabled:opacity-40 disabled:cursor-not-allowed",children:e.jsxs("span",{className:"flex items-baseline gap-3",children:[r.label,r.code&&e.jsx("span",{className:"ml-auto text-2xs font-mono text-text-quaternary",children:r.code})]})})},r.index)})}),f&&e.jsx(ie,{open:!0,onClose:()=>l(null),title:f.label,children:e.jsxs("div",{className:"space-y-4",children:[e.jsx("p",{className:"text-sm text-text-secondary",children:(A=f.confirm)==null?void 0:A.prompt}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{type:"button",onClick:()=>l(null),disabled:a,className:"btn-secondary text-xs",children:"No, go back"}),e.jsx("button",{type:"button",onClick:()=>{const r=f;l(null),u(r)},disabled:a,className:"btn-primary text-xs",children:"Yes, continue"})]})]})})]})}function at({choice:t,notPrimedMarkdown:s,message:n,primed:a,busy:u,onExecute:g,onCancel:y}){var N;const[f,l]=c.useState(!1),j=c.useRef(!1);return c.useEffect(()=>{if(!a){j.current=!1;return}j.current||(j.current=!0,t.confirm?l(!0):g(t))},[a,t,g]),e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-center text-center py-24",children:[e.jsxs("div",{className:"flex items-center gap-4 mb-8",children:[e.jsx(W,{className:"w-8 h-8 text-text-quaternary",strokeWidth:1}),e.jsx(de,{className:"w-10 h-10 text-accent-muted",strokeWidth:1})]}),e.jsx("h2",{className:"text-2xl font-light text-text-primary tracking-tight",children:"Scan your badge to continue"}),e.jsxs("p",{className:"text-lg text-text-secondary mt-2",children:["to ",t.label]}),n&&e.jsx("p",{className:"text-sm text-status-warning mt-4 max-w-prose","data-testid":"badge-prompt-message",children:n}),s&&e.jsx("div",{className:"text-sm text-text-tertiary mt-6 max-w-prose",children:e.jsx(F,{content:s,compact:!0})}),e.jsx("div",{className:"w-16 border-t border-surface-border my-8"}),e.jsx("button",{type:"button",onClick:y,disabled:u,className:"text-sm text-text-tertiary hover:text-text-secondary hover:underline",children:"Cancel"}),f&&e.jsx(ie,{open:!0,onClose:y,title:t.label,children:e.jsxs("div",{className:"space-y-4",children:[e.jsx("p",{className:"text-sm text-text-secondary",children:(N=t.confirm)==null?void 0:N.prompt}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{type:"button",onClick:y,disabled:u,className:"btn-secondary text-xs",children:"No, go back"}),e.jsx("button",{type:"button",onClick:()=>{l(!1),g(t)},disabled:u,className:"btn-primary text-xs",children:"Yes, continue"})]})]})})]})}function nt({escalationId:t,field:s,refreshKey:n}){const a=Ne(),{data:u}=Se(t);Ce(t),c.useEffect(()=>{n&&a.invalidateQueries({queryKey:["escalations",t]})},[n,t,a]);const g=c.useMemo(()=>{var v,T;const y=u,f=((v=y==null?void 0:y.metadata)==null?void 0:v.form_schema)??(y==null?void 0:y.form_schema),l=(T=f==null?void 0:f.properties)==null?void 0:T[s];if(!l)return null;const{[We]:j,...N}=l;return N},[u,s]);return!u||!g?null:e.jsx("div",{className:"w-full max-w-2xl mt-8 text-left","data-testid":"held-roster",children:e.jsx(He,{fieldKey:s,value:"",onChange:()=>{},schema:g,escalationContext:$e(u)})})}function ue(t){return t.join(t.some(s=>s.includes(","))?"; ":", ")}function rt({markdown:t,expected:s}){return e.jsxs("div",{role:"alert",className:"flex-1 flex flex-col items-center justify-center text-center py-24","data-testid":"refusal-panel",children:[e.jsx(xe,{className:"w-12 h-12 text-status-error mb-8",strokeWidth:1.25}),e.jsx("div",{className:"text-2xl font-light text-text-primary tracking-tight max-w-prose",children:e.jsx(F,{content:t,inherit:!0})}),s&&s.length>0&&e.jsxs("p",{className:"text-base text-text-secondary mt-6",children:["Expected ",e.jsx("span",{className:"font-mono text-text-primary",children:ue(s)})]}),e.jsx("div",{className:"w-16 border-t border-surface-border my-8"}),e.jsx("p",{className:"text-sm text-text-tertiary",children:"Scan the right one to place it."})]})}function lt(t){return Math.max(0,Math.ceil((Date.parse(t)-Date.now())/1e3))}function ot({subject:t,primedName:s,progress:n,progressLabel:a="checked off",note:u,refusal:g,refreshKey:y=0,onRelease:f}){var N;const[,l]=c.useState(0);c.useEffect(()=>{const v=setInterval(()=>l(T=>T+1),1e3);return()=>clearInterval(v)},[]);const j=!!t.headline;return e.jsxs("div",{className:`flex-1 flex flex-col items-center ${t.show?"justify-start":"justify-center"} text-center py-16 animate-page-enter`,"data-testid":"hold-screen",children:[j?e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"text-sm text-text-tertiary",children:["Holding ",e.jsx("span",{className:"font-mono text-text-secondary",children:t.label})]}),e.jsx("h1",{className:"mt-6 font-mono font-light text-7xl leading-none tracking-tight text-text-primary max-w-full break-all","data-testid":"hold-headline",children:t.headline}),t.subline&&e.jsx("p",{className:"heading-2 mt-4","data-testid":"hold-subline",children:t.subline})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-4 mb-8",children:[e.jsx(Le,{className:"w-10 h-10 text-accent-muted",strokeWidth:1}),e.jsx(W,{className:"w-8 h-8 text-text-quaternary",strokeWidth:1})]}),e.jsx("p",{className:"text-sm text-text-tertiary",children:"Holding"}),e.jsx("h1",{className:"text-3xl font-light text-text-primary tracking-tight mt-1 font-mono",children:t.label})]}),(N=t.expect)!=null&&N.prompt?e.jsx("div",{className:"text-lg text-text-secondary mt-8 max-w-prose",children:e.jsx(F,{content:t.expect.prompt,inherit:!0})}):e.jsx("p",{className:"text-lg text-text-secondary mt-8",children:"Scan where it goes"}),g&&e.jsxs("div",{role:"alert",className:"mt-6 flex items-start gap-3 text-left max-w-prose","data-testid":"hold-refusal",children:[e.jsx(xe,{className:"w-6 h-6 text-status-error shrink-0 mt-0.5",strokeWidth:1.5}),e.jsxs("div",{children:[e.jsx("div",{className:"text-lg text-text-primary",children:e.jsx(F,{content:g.markdown,inherit:!0})}),g.expected&&g.expected.length>0&&e.jsxs("p",{className:"text-sm text-text-secondary mt-1",children:["Expected ",e.jsx("span",{className:"text-text-primary",children:ue(g.expected)})]})]})]}),u?e.jsx("div",{className:"text-base text-text-primary mt-4","data-testid":"hold-progress",children:e.jsx(F,{content:u,inherit:!0})}):n&&n.total>0&&e.jsxs("p",{className:"text-base text-text-primary mt-4 tabular-nums","data-testid":"hold-progress",children:[n.filled," of ",n.total," ",a]}),t.claimedBy&&e.jsxs("p",{className:"text-sm text-status-warning mt-4",children:["Claimed by ",t.claimedBy.displayName]}),e.jsx("div",{className:"w-16 border-t border-surface-border my-8"}),e.jsxs("p",{className:"text-sm text-text-tertiary",children:[s?`Badge: ${s}`:"Scan your badge when you place it",e.jsx("span",{className:"mx-2",children:"·"}),e.jsxs("span",{className:"font-mono tabular-nums",children:[lt(t.expiresAt),"s"]})]}),e.jsx("button",{type:"button",onClick:f,className:"mt-6 text-sm text-text-tertiary hover:text-text-secondary hover:underline",children:"Put it down"}),t.show&&e.jsx(nt,{escalationId:t.escalationId,field:t.show,refreshKey:y})]},t.escalationId)}function ct({what:t,notPrimedMarkdown:s,onCancel:n}){return e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-center text-center py-24","data-testid":"scan-badge-prompt",children:[e.jsxs("div",{className:"flex items-center gap-4 mb-8",children:[e.jsx(W,{className:"w-8 h-8 text-text-quaternary",strokeWidth:1}),e.jsx(de,{className:"w-10 h-10 text-accent-muted",strokeWidth:1})]}),e.jsx("h2",{className:"text-2xl font-light text-text-primary tracking-tight",children:"Scan your badge to finish"}),t&&e.jsx("p",{className:"text-lg text-text-secondary mt-2 font-mono",children:t}),s&&e.jsx("div",{className:"text-sm text-text-tertiary mt-6 max-w-prose",children:e.jsx(F,{content:s,compact:!0})}),e.jsx("div",{className:"w-16 border-t border-surface-border my-8"}),e.jsx("button",{type:"button",onClick:n,className:"text-sm text-text-tertiary hover:text-text-secondary hover:underline",children:"Cancel"})]})}function re({markdown:t,nextPrompt:s}){return e.jsxs("div",{role:"status",className:"flex-1 flex flex-col items-center justify-center text-center py-24 animate-page-enter","data-testid":"done-panel",children:[e.jsx(Be,{className:"w-14 h-14 text-status-success-graphic mb-8",strokeWidth:1.25}),e.jsx("div",{className:"text-4xl font-light text-text-primary tracking-tight max-w-prose leading-snug",children:e.jsx(F,{content:t,inherit:!0})}),e.jsx("div",{className:"w-16 border-t border-surface-border my-8"}),e.jsx("p",{className:"text-lg text-text-secondary",children:s})]})}const it=8e3,dt=[U.SHOW_DETAIL,U.CLAIM,U.CLAIM_SHOW_DETAIL];function le(t){switch(t.outcome){case b.HELD:case b.REFUSED:case b.SUBJECT_STALE:return!0;case b.NOT_PRIMED:return!!t.replayable;case b.EXECUTED:return!!(t.clearSubject||t.progress||t.done);default:return!1}}function jt(){var Q,Y,G,Z,z,ee,te,se,ae;const t=qe(),s=Ve(),{user:n}=Ee(),{identity:a,clear:u,settle:g}=oe(),{viewerId:y}=ve(),{lastResult:f,subject:l,dropSubject:j,adoptResponse:N,followCode:v,pendingScan:T,dropPendingScan:B}=ce(),I=Te(),{data:R}=De(),[h,k]=c.useState(null),[D,w]=c.useState(null),[A,r]=c.useState(null),[S,_]=c.useState(null),[x,H]=c.useState(null),[V,X]=c.useState(!1);c.useEffect(()=>{var i,m;const o=(i=t.state)==null?void 0:i[Ae];if(!o)return;k(o),r(null),_(null);const p=((m=o.choices)==null?void 0:m.length)===1?o.choices[0]:void 0;w(o.autoSelect&&p?{choice:p,returnTo:"idle"}:null),s(t.pathname,{replace:!0,state:null})},[t,s]);const d=(f==null?void 0:f.response)??null,L=(f==null?void 0:f.at)??0;c.useEffect(()=>{var o,p;!d||!le(d)||(k(null),w(null),r(null),_(null),d.outcome===b.SUBJECT_STALE&&r({at:Date.now(),tone:"text-status-warning",text:d.error||"Scan it again."}),d.outcome===b.EXECUTED&&d.follow&&H({at:L,follow:d.follow,markdown:((o=d.done)==null?void 0:o.markdown)??"Done.",role:(p=d.escalation)==null?void 0:p.role}))},[d,L]),c.useEffect(()=>{x&&(l||d&&L>x.at&&d.outcome!==b.NO_MATCH_FALLBACK)&&H(null)},[x,l,d,L]),c.useEffect(()=>{l&&_(null)},[l]);const fe=c.useMemo(()=>x?x.follow.roles.flatMap(o=>_e({role:o,verbs:["created"]})):[],[x]);Ie(fe,o=>{var E;if(!x)return;const{facet:p,value:i}=x.follow.target,m=(E=o==null?void 0:o.data)==null?void 0:E.metadata;m&&typeof m=="object"&&m[p]!==void 0&&!Xe(m[p],i)||v(x.follow.code)}),c.useEffect(()=>{if(!x)return;const o=x.at+x.follow.waitSeconds*1e3-Date.now(),p=setTimeout(async()=>{await v(x.follow.code)||_({at:Date.now(),markdown:x.markdown,role:x.role}),H(m=>(m==null?void 0:m.at)===x.at?null:m)},Math.max(0,o));return()=>clearTimeout(p)},[x,v]),c.useEffect(()=>{if(!A)return;const o=setTimeout(()=>r(null),it);return()=>clearTimeout(o)},[A]);const J=c.useCallback(async o=>{var p;if(!(!(h!=null&&h.rule)||!h.escalation)){X(!0);try{const i=await Pe({schemeVersion:h.rule.schemeVersion,category:h.rule.category,stepIndex:h.stepIndex??0,choiceIndex:o.index,escalationId:String(h.escalation.id),actingToken:a==null?void 0:a.actingToken});switch(a!=null&&a.actingToken&&g(a.actingToken,i),N(i),i.outcome){case b.HELD:k(null),w(null);break;case b.EXECUTED:if(k(null),w(null),dt.includes(o.verb)&&i.escalation){s(`/escalations/detail/${i.escalation.id}`);break}if(i.done){_({at:Date.now(),markdown:i.done.markdown,role:(p=i.escalation)==null?void 0:p.role});break}r({at:Date.now(),tone:"text-status-success",text:`${o.label} — done`});break;case b.CONFLICT:k(null),w(null),r({at:Date.now(),tone:"text-status-warning",text:i.error||"The item changed since it was scanned — scan it again."});break;case b.UNCONFIGURED:k(null),w(null),r({at:Date.now(),tone:"text-status-warning",text:i.error||"This choice is no longer configured."});break;case b.NOT_PRIMED:u(),r(null),w(m=>{var E;return{choice:o,returnTo:(m==null?void 0:m.returnTo)??"choices",...(E=o.roles)!=null&&E.length&&i.error?{message:i.error}:{}}});break;case b.REFUSED:u(),r(null),w(m=>{var E;return{choice:o,returnTo:(m==null?void 0:m.returnTo)??"choices",message:((E=i.refusal)==null?void 0:E.markdown)??i.error??"That badge cannot do this."}});break;default:r({at:Date.now(),tone:"text-status-error",text:i.error||"The choice did not run."})}}catch(i){r({at:Date.now(),tone:"text-status-error",text:i.message})}finally{X(!1)}}},[h,a,s,u,g,N]),he=c.useCallback(o=>{w({choice:o,returnTo:"choices"})},[]),pe=c.useCallback(()=>{(D==null?void 0:D.returnTo)==="idle"&&k(null),w(null)},[D]),ge=(n==null?void 0:n.displayName)||(n==null?void 0:n.username)||"Scan station",ye=!!(h!=null&&h.choices&&h.escalation),P=(d==null?void 0:d.outcome)===b.REFUSED?d:null,C=(d==null?void 0:d.outcome)===b.EXECUTED&&le(d)?d:null,je=l&&C?C.progress:null,$=C&&!l?{at:L,markdown:((Q=C.done)==null?void 0:Q.markdown)??(C.already?"Already there.":"Done."),role:(Y=C.escalation)==null?void 0:Y.role}:null,M=S&&(!$||S.at>$.at)?S:$,K=M==null?void 0:M.role,O=c.useMemo(()=>{var i;const o=m=>{var E;return m?(E=R==null?void 0:R.roles)==null?void 0:E.find(be=>be.role===m):void 0},p=o(K);return Qe({policy:ne((i=o(I.role))==null?void 0:i.properties),homePath:I.homePath},p?{policy:ne(p.properties),homePath:Me(p.role,Fe(p))}:null)},[I.role,I.homePath,K,R]);return c.useEffect(()=>{if(!M||x||l||!O)return;const o=setTimeout(()=>s(O.path),O.afterMs);return()=>clearTimeout(o)},[M,x,l,O,s]),e.jsxs("div",{className:"flex-1 min-h-0 flex flex-col",children:[e.jsx(Ze,{}),D&&h?e.jsx(at,{choice:D.choice,notPrimedMarkdown:(G=h.notPrimed)==null?void 0:G.markdown,message:D.message,primed:!!a,busy:V,onExecute:J,onCancel:pe}):T?e.jsx(ct,{what:l?l.headline?`${l.label} → ${l.headline}`:l.label:null,notPrimedMarkdown:(Z=d==null?void 0:d.notPrimed)==null?void 0:Z.markdown,onCancel:B}):P&&!(l!=null&&l.show)?e.jsx(rt,{markdown:((z=P.refusal)==null?void 0:z.markdown)??P.error??"Not placed.",expected:(ee=P.refusal)==null?void 0:ee.expected}):l?e.jsx(ot,{subject:l,primedName:(a==null?void 0:a.displayName)??null,progress:je,progressLabel:(C==null?void 0:C.verb)===U.ACCUMULATE?"added":"checked off",note:l&&C?((te=C.done)==null?void 0:te.markdown)??null:null,refusal:P?{markdown:((se=P.refusal)==null?void 0:se.markdown)??P.error??"Not placed.",expected:(ae=P.refusal)==null?void 0:ae.expected}:null,refreshKey:L,onRelease:j}):x?e.jsx(re,{markdown:x.markdown,nextPrompt:"Finding its next step"},x.at):M?e.jsx(re,{markdown:M.markdown,nextPrompt:"Scan the next item"},M.at):ye?e.jsx(st,{response:h,hasActingIdentity:!!a,selfId:y??null,busy:V,onExecute:J,onWithheldSelect:he},String(h.escalation.id)):e.jsx(Ye,{stationName:ge,primedName:(a==null?void 0:a.displayName)??null}),A&&e.jsxs("div",{role:"status",className:"mt-8 pt-3 border-t border-surface-border",children:[e.jsx("span",{className:`text-sm font-medium ${A.tone}`,children:A.text}),A.markdown&&e.jsx("div",{className:"text-sm text-text-secondary mt-1",children:e.jsx(F,{content:A.markdown,compact:!0})})]})]})}export{jt as ScanStationPage};
|
|
2
|
-
//# sourceMappingURL=ScanStationPage-nWYz-OD3.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ScanStationPage-nWYz-OD3.js","sources":["../../../shared/scan-code/target.ts","../../src/lib/scan-done.ts","../../src/components/scan/station/StationIdle.tsx","../../src/components/scan/station/PrimedChrome.tsx","../../src/components/scan/station/choice-code.ts","../../src/components/scan/station/InfoChoiceScreen.tsx","../../src/components/scan/station/BadgePrompt.tsx","../../src/components/scan/station/HeldRoster.tsx","../../src/components/scan/station/RefusalPanel.tsx","../../src/components/scan/station/HoldScreen.tsx","../../src/components/scan/station/ScanBadgePrompt.tsx","../../src/components/scan/station/DonePanel.tsx","../../src/pages/scan/ScanStationPage.tsx"],"sourcesContent":["// How a row's facet value matches a scanned target. Pure and isomorphic.\n\n/** True when the facet holds the target: equal to it, or a list containing it. */\nexport function facetHolds(value: unknown, target: string): boolean {\n return Array.isArray(value) ? value.includes(target) : value === target;\n}\n\n/** The target a row's facet names: the value, or the first member of a list. */\nexport function facetTarget(value: unknown): string | null {\n const first = Array.isArray(value) ? value[0] : value;\n return typeof first === 'string' && first ? first : null;\n}\n","/**\n * Where a station returns once a scan act completes its row, read from the\n * station role's `properties.scan_done`. The server validates the shape; the\n * reader here only trusts what checks out.\n */\nexport interface ScanDonePolicy {\n return: 'home' | string;\n after_seconds?: number;\n}\n\nexport const SCAN_DONE_AFTER_SECONDS_DEFAULT = 2;\n\nexport function readScanDone(properties: Record<string, unknown> | null | undefined): ScanDonePolicy | null {\n const value = properties?.scan_done;\n if (!value || typeof value !== 'object' || Array.isArray(value)) return null;\n const policy = value as Record<string, unknown>;\n const ret = policy.return;\n if (typeof ret !== 'string' || !(ret === 'home' || ret.startsWith('/'))) return null;\n const after = policy.after_seconds;\n return {\n return: ret,\n ...(typeof after === 'number' && after >= 0 ? { after_seconds: after } : {}),\n };\n}\n\n/** The route the station lands on; the kiosk home when the policy says so. */\nexport function scanDonePath(policy: ScanDonePolicy, homePath: string | null): string | null {\n return policy.return === 'home' ? homePath : policy.return;\n}\n\n/** A role's return policy beside the home path its `'home'` resolves to. */\nexport interface ScanDoneSource {\n policy: ScanDonePolicy | null;\n homePath: string | null;\n}\n\n/**\n * Where the station goes, and when, once an act completes a row. A chosen\n * station queue with its own policy wins; otherwise the completed row's role decides.\n */\nexport function resolveScanDoneReturn(\n chosen: ScanDoneSource,\n completed: ScanDoneSource | null,\n): { path: string; afterMs: number } | null {\n const source = chosen.policy ? chosen : completed;\n if (!source?.policy) return null;\n const path = scanDonePath(source.policy, source.homePath);\n if (!path) return null;\n return { path, afterMs: (source.policy.after_seconds ?? SCAN_DONE_AFTER_SECONDS_DEFAULT) * 1000 };\n}\n","import { ScanBarcode } from 'lucide-react';\n\n/**\n * The station at rest: large, calm typography. The station is named for the\n * logged-in account. Before a badge, it asks for one; with a badge live, it\n * asks for the next item.\n */\nexport function StationIdle({ stationName, primedName }: { stationName: string; primedName?: string | null }) {\n return (\n <div className=\"flex-1 flex flex-col items-center justify-center text-center py-24\">\n <ScanBarcode className=\"w-10 h-10 text-accent-muted mb-8\" strokeWidth={1} />\n <h1 className=\"text-3xl font-light text-text-primary tracking-tight\">{stationName}</h1>\n <div className=\"w-16 border-t border-surface-border my-8\" />\n {primedName ? (\n <>\n <p className=\"text-lg text-text-secondary\">Scan the next item</p>\n <p className=\"text-sm text-text-tertiary mt-2\">Badged in as {primedName}</p>\n </>\n ) : (\n <>\n <p className=\"text-lg text-text-secondary\">Scan your badge to begin</p>\n <p className=\"text-sm text-text-tertiary mt-2\">or scan an item</p>\n </>\n )}\n </div>\n );\n}\n","import { BadgeCheck } from 'lucide-react';\nimport { useActingIdentity } from '../../../hooks/useActingIdentity';\nimport { useActingCountdown } from '../../../hooks/useActingCountdown';\n\nfunction formatMmSs(totalSeconds: number): string {\n const m = Math.floor(totalSeconds / 60);\n const s = totalSeconds % 60;\n return `${m}:${String(s).padStart(2, '0')}`;\n}\n\n/**\n * Slim persistent strip while an acting identity is primed: the greeting and\n * a mm:ss countdown to the grant's expiry. The context clears itself at the\n * expiry instant; this chrome only renders.\n */\nexport function PrimedChrome() {\n const { identity } = useActingIdentity();\n const seconds = useActingCountdown();\n\n if (!identity) return null;\n\n return (\n <div className=\"flex items-center gap-2.5 pb-3 mb-6 border-b border-surface-border\">\n <BadgeCheck className=\"w-4 h-4 text-status-success shrink-0\" strokeWidth={1.5} />\n <span className=\"text-sm font-medium text-text-primary\">Hi {identity.displayName}</span>\n {identity.expiresAt && (\n <span className=\"ml-auto text-sm font-mono tabular-nums text-text-tertiary\">\n {formatMmSs(seconds)}\n </span>\n )}\n </div>\n );\n}\n","import type { ScanPresentedChoice } from '../../../api/scan-codes';\n\n/**\n * Whether a presented choice can act right now. The server withholds choices\n * whose identity requirement was unsatisfied at scan time; a badge primed\n * afterwards satisfies it, so the withholding lifts client-side without a\n * fresh present. A choice the server did not withhold stays enabled.\n */\nexport function isChoiceEnabled(choice: ScanPresentedChoice, hasActingIdentity: boolean): boolean {\n return !choice.withheld || hasActingIdentity;\n}\n\n/**\n * The enabled choice whose double-scan code exactly equals the raw emitted\n * string, or null. Choice codes are short tokens that never parse as scheme\n * codes, so an exact match is unambiguous; anything else falls through to\n * normal scan execution.\n */\nexport function matchChoiceByCode(\n choices: ScanPresentedChoice[],\n hasActingIdentity: boolean,\n raw: string,\n): ScanPresentedChoice | null {\n return (\n choices.find((c) => !!c.code && c.code === raw && isChoiceEnabled(c, hasActingIdentity)) ?? null\n );\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { Modal } from '../../common/modal/Modal';\nimport { useScanInput } from '../../../hooks/useScanInput';\nimport { formatTimeAgo } from '../../../lib/format';\nimport { stationFactEntries } from '../../../lib/metadata-display';\nimport { FormattedValue } from '../../common/display/FormattedValue';\nimport { isChoiceEnabled, matchChoiceByCode } from './choice-code';\nimport type { ScanExecuteResponse, ScanPresentedChoice } from '../../../api/scan-codes';\n\n/** Format a metadata leaf for display: booleans read as Yes/No, objects compact\n * to JSON, empty values show an em dash. */\nfunction formatFactValue(value: unknown): string {\n if (value == null || value === '') return '—';\n if (typeof value === 'boolean') return value ? 'Yes' : 'No';\n if (typeof value === 'object') return JSON.stringify(value);\n return String(value);\n}\n\nfunction FactRow({ label, value, format }: { label: string; value: string; format?: string }) {\n return (\n <div className=\"flex items-baseline gap-4 py-2\">\n <span className=\"w-32 shrink-0 text-2xs uppercase tracking-wide text-text-quaternary\">{label}</span>\n <span className=\"text-sm text-text-primary break-words\" data-testid=\"station-fact-value\">\n {format ? <FormattedValue raw={value} format={format} /> : value}\n </span>\n </div>\n );\n}\n\n/** Inline dot separator for the dense summary line. */\nfunction Dot() {\n return <span className=\"text-text-quaternary select-none\">·</span>;\n}\n\n/**\n * A PRESENT response, rendered whole. Upper half states the located item's\n * reality plainly; lower half offers the step's labeled choices as large\n * buttons. Withheld choices show the badge affordance and enable fully the\n * moment an acting identity primes. While mounted, this screen\n * takes first look at raw scans: a code matching an enabled choice selects it\n * (confirm still applies); everything else falls through to normal execution.\n * Tapping a withheld choice hands it to the caller as a pending action — the\n * badge stop-over collects the identity and executes it.\n */\nexport function InfoChoiceScreen({\n response,\n hasActingIdentity,\n selfId,\n busy,\n onExecute,\n onWithheldSelect,\n}: {\n response: ScanExecuteResponse;\n hasActingIdentity: boolean;\n selfId: string | null;\n busy: boolean;\n onExecute: (choice: ScanPresentedChoice) => void;\n onWithheldSelect: (choice: ScanPresentedChoice) => void;\n}) {\n const { pushCodeInterceptor } = useScanInput();\n const [pendingChoice, setPendingChoice] = useState<ScanPresentedChoice | null>(null);\n\n const escalation = (response.escalation ?? {}) as Record<string, unknown>;\n const choices = response.choices ?? [];\n const metadata = (escalation.metadata ?? {}) as Record<string, unknown>;\n\n const select = (choice: ScanPresentedChoice) => {\n if (choice.confirm) setPendingChoice(choice);\n else onExecute(choice);\n };\n\n // Live refs so the interceptor installed once sees current state — a badge\n // primed after mount enables withheld choices for double-scan selection too.\n const liveRef = useRef({ choices, hasActingIdentity, select });\n liveRef.current = { choices, hasActingIdentity, select };\n\n useEffect(() => pushCodeInterceptor((raw) => {\n const live = liveRef.current;\n const match = matchChoiceByCode(live.choices, live.hasActingIdentity, raw);\n if (!match) return false;\n live.select(match);\n return true;\n }), [pushCodeInterceptor]);\n\n const assignedTo = (escalation.assigned_to as string | null) ?? null;\n const claimState = !assignedTo ? 'Unclaimed' : assignedTo === selfId ? 'Claimed by you' : 'Claimed';\n const claimClass = assignedTo === selfId ? 'text-accent' : 'text-text-secondary';\n const typeLine = [escalation.type, escalation.subtype].filter(Boolean).join(' · ');\n // The step's curated facts when it declares them, else the row's metadata.\n const metaEntries: [string, unknown, string?][] = response.facts\n ? response.facts.map((f) => [f.label, f.value, f.format])\n : stationFactEntries(metadata);\n\n return (\n <div className=\"flex-1 min-h-0 flex flex-col max-w-form\">\n {/* Reality — the located item's identity up top, dense summary beneath,\n then its metadata as a clean definition list. */}\n <div>\n {response.rule?.name && (\n <div className=\"text-2xs font-semibold uppercase tracking-widest text-accent mb-2\">\n {response.rule.name}\n </div>\n )}\n <h2 className=\"text-2xl font-medium leading-tight text-text-primary mb-2\">\n {(escalation.description as string) || typeLine || 'Located item'}\n </h2>\n {/* Dense one-line summary of the system facts. */}\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-text-secondary mb-5\">\n <span>{String(escalation.role ?? '—')}</span>\n {typeLine && (<><Dot /><span>{typeLine}</span></>)}\n <Dot /><span className={claimClass}>{claimState}</span>\n {typeof escalation.created_at === 'string' && (\n <><Dot /><span>{formatTimeAgo(escalation.created_at)}</span></>\n )}\n </div>\n {metaEntries.length > 0 && (\n <div className=\"divide-y divide-surface-border border-t border-surface-border\">\n {metaEntries.map(([key, value, format], i) => (\n <FactRow key={`${i}-${key}`} label={key} value={formatFactValue(value)} format={format} />\n ))}\n </div>\n )}\n </div>\n\n {/* Choices — the human's tap (or a second scan) disambiguates */}\n <div className=\"mt-8 space-y-3\">\n {choices.map((choice) => {\n const enabled = isChoiceEnabled(choice, hasActingIdentity);\n // Withheld choices stay fully presented and tappable — the identity\n // requirement is collected on the ensuing badge screen, not announced\n // here (one instruction at a time keeps this screen clear).\n return (\n <div key={choice.index}>\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => (enabled ? select(choice) : onWithheldSelect(choice))}\n className=\"w-full text-left px-5 py-4 text-lg text-text-primary border border-surface-border rounded hover:bg-surface-sunken transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n <span className=\"flex items-baseline gap-3\">\n {choice.label}\n {choice.code && (\n <span className=\"ml-auto text-2xs font-mono text-text-quaternary\">{choice.code}</span>\n )}\n </span>\n </button>\n </div>\n );\n })}\n </div>\n\n {pendingChoice && (\n <Modal open onClose={() => setPendingChoice(null)} title={pendingChoice.label}>\n <div className=\"space-y-4\">\n <p className=\"text-sm text-text-secondary\">{pendingChoice.confirm?.prompt}</p>\n <div className=\"flex justify-end gap-3 pt-2\">\n <button\n type=\"button\"\n onClick={() => setPendingChoice(null)}\n disabled={busy}\n className=\"btn-secondary text-xs\"\n >\n No, go back\n </button>\n <button\n type=\"button\"\n onClick={() => {\n const choice = pendingChoice;\n setPendingChoice(null);\n onExecute(choice);\n }}\n disabled={busy}\n className=\"btn-primary text-xs\"\n >\n Yes, continue\n </button>\n </div>\n </div>\n </Modal>\n )}\n </div>\n );\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { IdCard, ScanBarcode } from 'lucide-react';\nimport { Modal } from '../../common/modal/Modal';\nimport { SimpleMarkdown } from '../../common/display/SimpleMarkdown';\nimport type { ScanPresentedChoice } from '../../../api/scan-codes';\n\n/**\n * The badge stop-over: a chosen action wants an acting identity that is not\n * primed yet. The screen holds the choice and waits — a badge scan flows\n * through the normal scan pipeline and primes the identity; the moment\n * `primed` flips true this component executes the pending choice (asking\n * first when the choice carries a confirm). Cancel hands control back to the\n * caller, which decides where to return.\n */\nexport function BadgePrompt({\n choice,\n notPrimedMarkdown,\n message,\n primed,\n busy,\n onExecute,\n onCancel,\n}: {\n choice: ScanPresentedChoice;\n notPrimedMarkdown?: string;\n /** Why the last badge did not run the choice (a role it lacks). */\n message?: string;\n primed: boolean;\n busy: boolean;\n onExecute: (choice: ScanPresentedChoice) => void;\n onCancel: () => void;\n}) {\n const [confirming, setConfirming] = useState(false);\n // One execution per priming — re-arms if the grant lapses before it lands.\n const firedRef = useRef(false);\n\n useEffect(() => {\n if (!primed) {\n firedRef.current = false;\n return;\n }\n if (firedRef.current) return;\n firedRef.current = true;\n if (choice.confirm) setConfirming(true);\n else onExecute(choice);\n }, [primed, choice, onExecute]);\n\n return (\n <div className=\"flex-1 flex flex-col items-center justify-center text-center py-24\">\n <div className=\"flex items-center gap-4 mb-8\">\n <ScanBarcode className=\"w-8 h-8 text-text-quaternary\" strokeWidth={1} />\n <IdCard className=\"w-10 h-10 text-accent-muted\" strokeWidth={1} />\n </div>\n <h2 className=\"text-2xl font-light text-text-primary tracking-tight\">\n Scan your badge to continue\n </h2>\n <p className=\"text-lg text-text-secondary mt-2\">to {choice.label}</p>\n {message && (\n <p className=\"text-sm text-status-warning mt-4 max-w-prose\" data-testid=\"badge-prompt-message\">{message}</p>\n )}\n {notPrimedMarkdown && (\n <div className=\"text-sm text-text-tertiary mt-6 max-w-prose\">\n <SimpleMarkdown content={notPrimedMarkdown} compact />\n </div>\n )}\n <div className=\"w-16 border-t border-surface-border my-8\" />\n <button\n type=\"button\"\n onClick={onCancel}\n disabled={busy}\n className=\"text-sm text-text-tertiary hover:text-text-secondary hover:underline\"\n >\n Cancel\n </button>\n\n {confirming && (\n <Modal open onClose={onCancel} title={choice.label}>\n <div className=\"space-y-4\">\n <p className=\"text-sm text-text-secondary\">{choice.confirm?.prompt}</p>\n <div className=\"flex justify-end gap-3 pt-2\">\n <button type=\"button\" onClick={onCancel} disabled={busy} className=\"btn-secondary text-xs\">\n No, go back\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setConfirming(false);\n onExecute(choice);\n }}\n disabled={busy}\n className=\"btn-primary text-xs\"\n >\n Yes, continue\n </button>\n </div>\n </div>\n </Modal>\n )}\n </div>\n );\n}\n","import { useEffect, useMemo } from 'react';\nimport { useQueryClient } from '@tanstack/react-query';\nimport { useEscalation } from '../../../api/escalations';\nimport { useEscalationDetailEvents } from '../../../hooks/useEventHooks';\nimport { RosterWidget } from '../../escalation/widgets/RosterWidget';\nimport { X_LT_ACTIONS } from '../../../lib/x-lt-actions';\nimport { rosterRowContext } from '../../../lib/x-lt-roster';\n\n/**\n * The held row's roster under the hold card: the field `hold.show` names on\n * the row's form, read-only, refreshed on the row's own events and after\n * each scan the station makes, so each fill ticks its entry in while the\n * scan motion continues.\n */\nexport function HeldRoster({ escalationId, field, refreshKey }: {\n escalationId: string;\n field: string;\n /** Changes on every bench response; the roster refetches once per change. */\n refreshKey: number;\n}) {\n const queryClient = useQueryClient();\n const { data: esc } = useEscalation(escalationId);\n useEscalationDetailEvents(escalationId);\n\n useEffect(() => {\n if (refreshKey) void queryClient.invalidateQueries({ queryKey: ['escalations', escalationId] });\n }, [refreshKey, escalationId, queryClient]);\n\n const schema = useMemo(() => {\n const record = esc as unknown as Record<string, any> | undefined;\n const form = record?.metadata?.form_schema ?? record?.form_schema;\n const fieldSchema = form?.properties?.[field] as Record<string, unknown> | undefined;\n if (!fieldSchema) return null;\n const { [X_LT_ACTIONS]: _actions, ...readOnly } = fieldSchema;\n return readOnly;\n }, [esc, field]);\n\n if (!esc || !schema) return null;\n return (\n <div className=\"w-full max-w-2xl mt-8 text-left\" data-testid=\"held-roster\">\n <RosterWidget\n fieldKey={field}\n value=\"\"\n onChange={() => {}}\n schema={schema}\n escalationContext={rosterRowContext(esc as unknown as Record<string, unknown>)}\n />\n </div>\n );\n}\n","import { CircleX } from 'lucide-react';\nimport { SimpleMarkdown } from '../../common/display/SimpleMarkdown';\n\n/** The expected entries as one line: codes comma-joined, labels (which carry commas) semicolon-joined. */\nexport function expectedLine(expected: string[]): string {\n return expected.join(expected.some((e) => e.includes(',')) ? '; ' : ', ');\n}\n\n/**\n * A refused scan, with nothing written. The words name what is wrong and,\n * when the rule knows it, where the item goes instead. It stays until the\n * next scan, so the associate can read it after looking up from the bench.\n */\nexport function RefusalPanel({\n markdown,\n expected,\n}: {\n markdown: string;\n expected?: string[];\n}) {\n return (\n <div\n role=\"alert\"\n className=\"flex-1 flex flex-col items-center justify-center text-center py-24\"\n data-testid=\"refusal-panel\"\n >\n <CircleX className=\"w-12 h-12 text-status-error mb-8\" strokeWidth={1.25} />\n <div className=\"text-2xl font-light text-text-primary tracking-tight max-w-prose\">\n <SimpleMarkdown content={markdown} inherit />\n </div>\n {expected && expected.length > 0 && (\n <p className=\"text-base text-text-secondary mt-6\">\n Expected <span className=\"font-mono text-text-primary\">{expectedLine(expected)}</span>\n </p>\n )}\n <div className=\"w-16 border-t border-surface-border my-8\" />\n <p className=\"text-sm text-text-tertiary\">Scan the right one to place it.</p>\n </div>\n );\n}\n","import { useEffect, useState } from 'react';\nimport { CircleX, Package, ScanBarcode } from 'lucide-react';\nimport { SimpleMarkdown } from '../../common/display/SimpleMarkdown';\nimport { HeldRoster } from './HeldRoster';\nimport { expectedLine } from './RefusalPanel';\nimport type { StationSubject } from '../../../lib/scan-subject';\n\nfunction secondsLeft(expiresAt: string): number {\n return Math.max(0, Math.ceil((Date.parse(expiresAt) - Date.now()) / 1000));\n}\n\n/**\n * The station holding an item. With a headline (where the item goes) the\n * destination leads, read from across the bench: the container code largest, its\n * place name under it, the item itself as a quiet line above. Without one,\n * the item leads. The subject lapses on its own (the scan pipeline clears it\n * at expiry); the per-second tick is a visible clock, not polling.\n *\n * With `show`, the held row's roster stays under the card for the whole\n * motion, and a refused scan reads on the card above it.\n */\nexport function HoldScreen({\n subject,\n primedName,\n progress,\n progressLabel = 'checked off',\n note,\n refusal,\n refreshKey = 0,\n onRelease,\n}: {\n subject: StationSubject;\n primedName: string | null;\n progress?: { filled: number; total: number; remaining: number } | null;\n /** What the count measures: a fill checks items off, an accumulate adds them. */\n progressLabel?: string;\n /** The last act's done copy while the item is still held (a fill in progress). */\n note?: string | null;\n /** A refused scan while the list stays on screen. */\n refusal?: { markdown: string; expected?: string[] } | null;\n /** Changes on every bench response, so the shown roster refetches. */\n refreshKey?: number;\n onRelease: () => void;\n}) {\n const [, setTick] = useState(0);\n useEffect(() => {\n const interval = setInterval(() => setTick((t) => t + 1), 1_000);\n return () => clearInterval(interval);\n }, []);\n\n const destination = !!subject.headline;\n\n return (\n <div\n key={subject.escalationId}\n className={`flex-1 flex flex-col items-center ${subject.show ? 'justify-start' : 'justify-center'} text-center py-16 animate-page-enter`}\n data-testid=\"hold-screen\"\n >\n {destination ? (\n <>\n <p className=\"text-sm text-text-tertiary\">\n Holding <span className=\"font-mono text-text-secondary\">{subject.label}</span>\n </p>\n <h1\n className=\"mt-6 font-mono font-light text-7xl leading-none tracking-tight text-text-primary max-w-full break-all\"\n data-testid=\"hold-headline\"\n >\n {subject.headline}\n </h1>\n {subject.subline && (\n <p className=\"heading-2 mt-4\" data-testid=\"hold-subline\">{subject.subline}</p>\n )}\n </>\n ) : (\n <>\n <div className=\"flex items-center gap-4 mb-8\">\n <Package className=\"w-10 h-10 text-accent-muted\" strokeWidth={1} />\n <ScanBarcode className=\"w-8 h-8 text-text-quaternary\" strokeWidth={1} />\n </div>\n <p className=\"text-sm text-text-tertiary\">Holding</p>\n <h1 className=\"text-3xl font-light text-text-primary tracking-tight mt-1 font-mono\">{subject.label}</h1>\n </>\n )}\n {subject.expect?.prompt ? (\n <div className=\"text-lg text-text-secondary mt-8 max-w-prose\">\n <SimpleMarkdown content={subject.expect.prompt} inherit />\n </div>\n ) : (\n <p className=\"text-lg text-text-secondary mt-8\">Scan where it goes</p>\n )}\n {refusal && (\n <div role=\"alert\" className=\"mt-6 flex items-start gap-3 text-left max-w-prose\" data-testid=\"hold-refusal\">\n <CircleX className=\"w-6 h-6 text-status-error shrink-0 mt-0.5\" strokeWidth={1.5} />\n <div>\n <div className=\"text-lg text-text-primary\"><SimpleMarkdown content={refusal.markdown} inherit /></div>\n {refusal.expected && refusal.expected.length > 0 && (\n <p className=\"text-sm text-text-secondary mt-1\">\n Expected <span className=\"text-text-primary\">{expectedLine(refusal.expected)}</span>\n </p>\n )}\n </div>\n </div>\n )}\n {note ? (\n <div className=\"text-base text-text-primary mt-4\" data-testid=\"hold-progress\">\n <SimpleMarkdown content={note} inherit />\n </div>\n ) : progress && progress.total > 0 && (\n <p className=\"text-base text-text-primary mt-4 tabular-nums\" data-testid=\"hold-progress\">\n {progress.filled} of {progress.total} {progressLabel}\n </p>\n )}\n {subject.claimedBy && (\n <p className=\"text-sm text-status-warning mt-4\">Claimed by {subject.claimedBy.displayName}</p>\n )}\n <div className=\"w-16 border-t border-surface-border my-8\" />\n <p className=\"text-sm text-text-tertiary\">\n {primedName ? `Badge: ${primedName}` : 'Scan your badge when you place it'}\n <span className=\"mx-2\">·</span>\n <span className=\"font-mono tabular-nums\">{secondsLeft(subject.expiresAt)}s</span>\n </p>\n <button\n type=\"button\"\n onClick={onRelease}\n className=\"mt-6 text-sm text-text-tertiary hover:text-text-secondary hover:underline\"\n >\n Put it down\n </button>\n {subject.show && (\n <HeldRoster escalationId={subject.escalationId} field={subject.show} refreshKey={refreshKey} />\n )}\n </div>\n );\n}\n","import { IdCard, ScanBarcode } from 'lucide-react';\nimport { SimpleMarkdown } from '../../common/display/SimpleMarkdown';\n\n/**\n * A scan that needs a badge first. The scan is held by the pipeline; the\n * badge scan primes the identity and the held scan replays on its own. The\n * order of scans never matters: item, badge, container and item, container,\n * badge both land.\n */\nexport function ScanBadgePrompt({\n what,\n notPrimedMarkdown,\n onCancel,\n}: {\n what: string | null;\n notPrimedMarkdown?: string;\n onCancel: () => void;\n}) {\n return (\n <div className=\"flex-1 flex flex-col items-center justify-center text-center py-24\" data-testid=\"scan-badge-prompt\">\n <div className=\"flex items-center gap-4 mb-8\">\n <ScanBarcode className=\"w-8 h-8 text-text-quaternary\" strokeWidth={1} />\n <IdCard className=\"w-10 h-10 text-accent-muted\" strokeWidth={1} />\n </div>\n <h2 className=\"text-2xl font-light text-text-primary tracking-tight\">Scan your badge to finish</h2>\n {what && <p className=\"text-lg text-text-secondary mt-2 font-mono\">{what}</p>}\n {notPrimedMarkdown && (\n <div className=\"text-sm text-text-tertiary mt-6 max-w-prose\">\n <SimpleMarkdown content={notPrimedMarkdown} compact />\n </div>\n )}\n <div className=\"w-16 border-t border-surface-border my-8\" />\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"text-sm text-text-tertiary hover:text-text-secondary hover:underline\"\n >\n Cancel\n </button>\n </div>\n );\n}\n","import { CircleCheck } from 'lucide-react';\nimport { SimpleMarkdown } from '../../common/display/SimpleMarkdown';\n\n/**\n * A write that landed at the bench: what to do with the item now (\"Place it\n * in **C-12**.\"), large, until the next scan replaces it. Neutral surface;\n * the check carries the status.\n */\nexport function DonePanel({ markdown, nextPrompt }: { markdown: string; nextPrompt: string }) {\n return (\n <div\n role=\"status\"\n className=\"flex-1 flex flex-col items-center justify-center text-center py-24 animate-page-enter\"\n data-testid=\"done-panel\"\n >\n <CircleCheck className=\"w-14 h-14 text-status-success-graphic mb-8\" strokeWidth={1.25} />\n <div className=\"text-4xl font-light text-text-primary tracking-tight max-w-prose leading-snug\">\n <SimpleMarkdown content={markdown} inherit />\n </div>\n <div className=\"w-16 border-t border-surface-border my-8\" />\n <p className=\"text-lg text-text-secondary\">{nextPrompt}</p>\n </div>\n );\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { useAuth } from '../../hooks/useAuth';\nimport { useActingIdentity } from '../../hooks/useActingIdentity';\nimport { useViewerIdentity } from '../../hooks/useViewerIdentity';\nimport { kioskHomePath, useKioskMode } from '../../hooks/useKioskMode';\nimport { useEventSubscriptions } from '../../hooks/useEventContext';\nimport { SCAN_CHOICES_STATE, useScanInput } from '../../hooks/useScanInput';\nimport { useRoleDetails } from '../../api/roles';\nimport { escalationPatterns } from '../../lib/events/subjects';\nimport { readScanDone, resolveScanDoneReturn } from '../../lib/scan-done';\nimport { portalsOf } from '../../lib/portal-path';\nimport { facetHolds } from '../../../../shared/scan-code';\nimport {\n executeScanChoice,\n SCAN_OUTCOMES,\n SCAN_VERBS,\n type ScanExecuteResponse,\n type ScanFollow,\n type ScanPresentedChoice,\n type ScanVerb,\n} from '../../api/scan-codes';\nimport {\n StationIdle,\n PrimedChrome,\n InfoChoiceScreen,\n BadgePrompt,\n HoldScreen,\n RefusalPanel,\n ScanBadgePrompt,\n DonePanel,\n} from '../../components/scan/station';\nimport { SimpleMarkdown } from '../../components/common/display/SimpleMarkdown';\n\nconst NOTICE_DISMISS_MS = 8_000;\n\n/** Choice verbs whose execution lands the person on the escalation's detail page. */\nconst DETAIL_VERBS: ScanVerb[] = [\n SCAN_VERBS.SHOW_DETAIL,\n SCAN_VERBS.CLAIM,\n SCAN_VERBS.CLAIM_SHOW_DETAIL,\n];\n\n/** Responses from the bench motion (hold, place, refuse); badge scans and choices are not. */\nfunction isBenchResponse(response: ScanExecuteResponse): boolean {\n switch (response.outcome) {\n case SCAN_OUTCOMES.HELD:\n case SCAN_OUTCOMES.REFUSED:\n case SCAN_OUTCOMES.SUBJECT_STALE:\n return true;\n case SCAN_OUTCOMES.NOT_PRIMED:\n return !!response.replayable;\n case SCAN_OUTCOMES.EXECUTED:\n return !!(response.clearSubject || response.progress || response.done);\n default:\n return false;\n }\n}\n\n/** A completed act's copy, shown large until the station moves on, and the role of the row it completed. */\ninterface DoneScreen {\n at: number;\n markdown: string;\n role?: string;\n}\n\n/** The station waiting for the completed subject's next row. */\ninterface Following {\n at: number;\n follow: ScanFollow;\n markdown: string;\n role?: string;\n}\n\ninterface StationNotice {\n at: number;\n tone: string;\n text: string;\n markdown?: string;\n}\n\n/** A choice waiting on a badge, where Cancel returns, and why the last badge did not run it. */\ninterface PendingBadge {\n choice: ScanPresentedChoice;\n returnTo: 'choices' | 'idle';\n message?: string;\n}\n\n/**\n * The scan station: a full-page surface for badge + item work. Idle until a\n * scan presents an item's reality and choices; a badge scan primes an acting\n * identity that unlocks withheld choices and rides along on executions. A\n * choice that needs a badge first parks in the stop-over (BadgePrompt) — one\n * badge scan primes the identity and the pending choice executes itself.\n * Claim and show choices land on the escalation's detail page for the work.\n */\nexport function ScanStationPage() {\n const location = useLocation();\n const navigate = useNavigate();\n const { user } = useAuth();\n const { identity, clear, settle } = useActingIdentity();\n const { viewerId } = useViewerIdentity();\n const { lastResult, subject, dropSubject, adoptResponse, followCode, pendingScan, dropPendingScan } = useScanInput();\n const kiosk = useKioskMode();\n const { data: roleDetails } = useRoleDetails();\n const [screen, setScreen] = useState<ScanExecuteResponse | null>(null);\n const [pendingBadge, setPendingBadge] = useState<PendingBadge | null>(null);\n const [notice, setNotice] = useState<StationNotice | null>(null);\n const [actDone, setActDone] = useState<DoneScreen | null>(null);\n const [following, setFollowing] = useState<Following | null>(null);\n const [busy, setBusy] = useState(false);\n\n // Adopt a CHOICES response arriving in route state, then drop it from\n // history so refresh/back land on the idle station, never a stale reality.\n // An autoSelect response skips the choice screen: the server would have\n // executed its single choice but identity stopped it — straight to the\n // stop-over with that choice pending; Cancel returns to idle.\n useEffect(() => {\n const incoming = (location.state as Record<string, unknown> | null)\n ?.[SCAN_CHOICES_STATE] as ScanExecuteResponse | undefined;\n if (!incoming) return;\n setScreen(incoming);\n setNotice(null);\n setActDone(null);\n const single = incoming.choices?.length === 1 ? incoming.choices[0] : undefined;\n setPendingBadge(incoming.autoSelect && single ? { choice: single, returnTo: 'idle' } : null);\n navigate(location.pathname, { replace: true, state: null });\n }, [location, navigate]);\n\n // A bench scan (hold, refusal, placed) replaces whatever the station showed.\n const bench = lastResult?.response ?? null;\n const benchAt = lastResult?.at ?? 0;\n useEffect(() => {\n if (!bench || !isBenchResponse(bench)) return;\n setScreen(null);\n setPendingBadge(null);\n setNotice(null);\n setActDone(null);\n if (bench.outcome === SCAN_OUTCOMES.SUBJECT_STALE) {\n setNotice({ at: Date.now(), tone: 'text-status-warning', text: bench.error || 'Scan it again.' });\n }\n // A completing act that names the subject's next step: wait for that row.\n if (bench.outcome === SCAN_OUTCOMES.EXECUTED && bench.follow) {\n setFollowing({ at: benchAt, follow: bench.follow, markdown: bench.done?.markdown ?? 'Done.', role: bench.escalation?.role });\n }\n }, [bench, benchAt]);\n\n // Following ends the moment a hold lands (the next row is held) or a new scan arrives.\n useEffect(() => {\n if (!following) return;\n if (subject || (bench && benchAt > following.at && bench.outcome !== SCAN_OUTCOMES.NO_MATCH_FALLBACK)) {\n setFollowing(null);\n }\n }, [following, subject, bench, benchAt]);\n\n // A hold that lands while an act's copy is up replaces it.\n useEffect(() => {\n if (subject) setActDone(null);\n }, [subject]);\n\n // The next row announces itself: a created event in one of the follow roles\n // for the same target replays the held code, and the hold lands.\n const followPatterns = useMemo(\n () => (following ? following.follow.roles.flatMap((role) => escalationPatterns({ role, verbs: ['created'] })) : []),\n [following],\n );\n useEventSubscriptions(followPatterns, (event: any) => {\n if (!following) return;\n const { facet, value } = following.follow.target;\n const meta = event?.data?.metadata;\n if (meta && typeof meta === 'object' && meta[facet] !== undefined && !facetHolds(meta[facet], value)) return;\n void followCode(following.follow.code);\n });\n\n // Nothing arrived in time: one last look. A row found then is held; otherwise\n // the completed act's copy stands on its own, since the replay's answer took the bench.\n useEffect(() => {\n if (!following) return;\n const remaining = following.at + following.follow.waitSeconds * 1000 - Date.now();\n const timer = setTimeout(async () => {\n const held = await followCode(following.follow.code);\n if (!held) setActDone({ at: Date.now(), markdown: following.markdown, role: following.role });\n setFollowing((current) => (current?.at === following.at ? null : current));\n }, Math.max(0, remaining));\n return () => clearTimeout(timer);\n }, [following, followCode]);\n\n // Notices self-dismiss — one timeout keyed to the notice.\n useEffect(() => {\n if (!notice) return;\n const timer = setTimeout(() => setNotice(null), NOTICE_DISMISS_MS);\n return () => clearTimeout(timer);\n }, [notice]);\n\n const executeChoice = useCallback(async (choice: ScanPresentedChoice) => {\n if (!screen?.rule || !screen.escalation) return;\n setBusy(true);\n try {\n const result = await executeScanChoice({\n schemeVersion: screen.rule.schemeVersion,\n category: screen.rule.category,\n stepIndex: screen.stepIndex ?? 0,\n choiceIndex: choice.index,\n escalationId: String(screen.escalation.id),\n actingToken: identity?.actingToken,\n });\n // A claim spends the badge: retire it when the server says none is left.\n if (identity?.actingToken) settle(identity.actingToken, result);\n adoptResponse(result);\n switch (result.outcome) {\n case SCAN_OUTCOMES.HELD:\n setScreen(null);\n setPendingBadge(null);\n break;\n case SCAN_OUTCOMES.EXECUTED:\n setScreen(null);\n setPendingBadge(null);\n if (DETAIL_VERBS.includes(choice.verb) && result.escalation) {\n // The claim (or show) landed — go work the item where it lives.\n navigate(`/escalations/detail/${result.escalation.id}`);\n break;\n }\n if (result.done) {\n // The choice's own done copy takes the screen, badge first or second.\n setActDone({ at: Date.now(), markdown: result.done.markdown, role: result.escalation?.role });\n break;\n }\n // Done — back to idle, ready for the next item.\n setNotice({ at: Date.now(), tone: 'text-status-success', text: `${choice.label} — done` });\n break;\n case SCAN_OUTCOMES.CONFLICT:\n // Someone else won the row; the presented reality is stale.\n setScreen(null);\n setPendingBadge(null);\n setNotice({\n at: Date.now(),\n tone: 'text-status-warning',\n text: result.error || 'The item changed since it was scanned — scan it again.',\n });\n break;\n case SCAN_OUTCOMES.UNCONFIGURED:\n setScreen(null);\n setPendingBadge(null);\n setNotice({\n at: Date.now(),\n tone: 'text-status-warning',\n text: result.error || 'This choice is no longer configured.',\n });\n break;\n case SCAN_OUTCOMES.NOT_PRIMED:\n // The grant died between render and tap, or the choice needs a role\n // the person acting lacks: park it; the next badge scan satisfies it.\n clear();\n setNotice(null);\n setPendingBadge((prev) => ({\n choice,\n returnTo: prev?.returnTo ?? 'choices',\n ...(choice.roles?.length && result.error ? { message: result.error } : {}),\n }));\n break;\n case SCAN_OUTCOMES.REFUSED:\n // A badge without the choice's role: drop it and wait for one that has it.\n clear();\n setNotice(null);\n setPendingBadge((prev) => ({\n choice,\n returnTo: prev?.returnTo ?? 'choices',\n message: result.refusal?.markdown ?? result.error ?? 'That badge cannot do this.',\n }));\n break;\n default:\n setNotice({\n at: Date.now(),\n tone: 'text-status-error',\n text: result.error || 'The choice did not run.',\n });\n }\n } catch (err: any) {\n setNotice({ at: Date.now(), tone: 'text-status-error', text: err.message });\n } finally {\n setBusy(false);\n }\n }, [screen, identity, navigate, clear, settle, adoptResponse]);\n\n const holdForBadge = useCallback((choice: ScanPresentedChoice) => {\n setPendingBadge({ choice, returnTo: 'choices' });\n }, []);\n\n const cancelBadge = useCallback(() => {\n if (pendingBadge?.returnTo === 'idle') setScreen(null);\n setPendingBadge(null);\n }, [pendingBadge]);\n\n const stationName = user?.displayName || user?.username || 'Scan station';\n const showChoices = !!(screen?.choices && screen.escalation);\n const refusal = bench?.outcome === SCAN_OUTCOMES.REFUSED ? bench : null;\n const executedBench = bench?.outcome === SCAN_OUTCOMES.EXECUTED && isBenchResponse(bench) ? bench : null;\n const progress = subject && executedBench ? executedBench.progress : null;\n const benchDone: DoneScreen | null = executedBench && !subject\n ? {\n at: benchAt,\n markdown: executedBench.done?.markdown ?? (executedBench.already ? 'Already there.' : 'Done.'),\n role: executedBench.escalation?.role,\n }\n : null;\n const done = actDone && (!benchDone || actDone.at > benchDone.at) ? actDone : benchDone;\n\n // Where the station returns: the chosen queue's policy, else the completed row's role.\n const completedRole = done?.role;\n const scanDone = useMemo(() => {\n const detailOf = (role: string | null | undefined) => (role ? roleDetails?.roles?.find((r) => r.role === role) : undefined);\n const completed = detailOf(completedRole);\n return resolveScanDoneReturn(\n { policy: readScanDone(detailOf(kiosk.role)?.properties), homePath: kiosk.homePath },\n completed ? { policy: readScanDone(completed.properties), homePath: kioskHomePath(completed.role, portalsOf(completed)) } : null,\n );\n }, [kiosk.role, kiosk.homePath, completedRole, roleDetails]);\n\n // The row is complete, nothing is held and the station is not following: return per the policy.\n useEffect(() => {\n if (!done || following || subject || !scanDone) return;\n const timer = setTimeout(() => navigate(scanDone.path), scanDone.afterMs);\n return () => clearTimeout(timer);\n }, [done, following, subject, scanDone, navigate]);\n\n return (\n <div className=\"flex-1 min-h-0 flex flex-col\">\n <PrimedChrome />\n {pendingBadge && screen ? (\n <BadgePrompt\n choice={pendingBadge.choice}\n notPrimedMarkdown={screen.notPrimed?.markdown}\n message={pendingBadge.message}\n primed={!!identity}\n busy={busy}\n onExecute={executeChoice}\n onCancel={cancelBadge}\n />\n ) : pendingScan ? (\n <ScanBadgePrompt\n what={subject ? (subject.headline ? `${subject.label} → ${subject.headline}` : subject.label) : null}\n notPrimedMarkdown={bench?.notPrimed?.markdown}\n onCancel={dropPendingScan}\n />\n ) : refusal && !subject?.show ? (\n <RefusalPanel\n markdown={refusal.refusal?.markdown ?? refusal.error ?? 'Not placed.'}\n expected={refusal.refusal?.expected}\n />\n ) : subject ? (\n <HoldScreen\n subject={subject}\n primedName={identity?.displayName ?? null}\n progress={progress}\n progressLabel={executedBench?.verb === SCAN_VERBS.ACCUMULATE ? 'added' : 'checked off'}\n note={subject && executedBench ? executedBench.done?.markdown ?? null : null}\n refusal={refusal ? { markdown: refusal.refusal?.markdown ?? refusal.error ?? 'Not placed.', expected: refusal.refusal?.expected } : null}\n refreshKey={benchAt}\n onRelease={dropSubject}\n />\n ) : following ? (\n <DonePanel key={following.at} markdown={following.markdown} nextPrompt=\"Finding its next step\" />\n ) : done ? (\n <DonePanel key={done.at} markdown={done.markdown} nextPrompt=\"Scan the next item\" />\n ) : showChoices ? (\n <InfoChoiceScreen\n key={String(screen!.escalation!.id)}\n response={screen!}\n hasActingIdentity={!!identity}\n selfId={viewerId ?? null}\n busy={busy}\n onExecute={executeChoice}\n onWithheldSelect={holdForBadge}\n />\n ) : (\n <StationIdle stationName={stationName} primedName={identity?.displayName ?? null} />\n )}\n {notice && (\n <div role=\"status\" className=\"mt-8 pt-3 border-t border-surface-border\">\n <span className={`text-sm font-medium ${notice.tone}`}>{notice.text}</span>\n {notice.markdown && (\n <div className=\"text-sm text-text-secondary mt-1\">\n <SimpleMarkdown content={notice.markdown} compact />\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"names":["facetHolds","value","target","SCAN_DONE_AFTER_SECONDS_DEFAULT","readScanDone","properties","policy","ret","after","scanDonePath","homePath","resolveScanDoneReturn","chosen","completed","source","path","StationIdle","stationName","primedName","jsxs","jsx","ScanBarcode","Fragment","formatMmSs","totalSeconds","m","s","PrimedChrome","identity","useActingIdentity","seconds","useActingCountdown","BadgeCheck","isChoiceEnabled","choice","hasActingIdentity","matchChoiceByCode","choices","raw","c","formatFactValue","FactRow","label","format","FormattedValue","Dot","InfoChoiceScreen","response","selfId","busy","onExecute","onWithheldSelect","pushCodeInterceptor","useScanInput","pendingChoice","setPendingChoice","useState","escalation","metadata","select","liveRef","useRef","useEffect","live","match","assignedTo","claimState","claimClass","typeLine","metaEntries","f","stationFactEntries","_a","formatTimeAgo","key","i","enabled","Modal","_b","BadgePrompt","notPrimedMarkdown","message","primed","onCancel","confirming","setConfirming","firedRef","IdCard","SimpleMarkdown","HeldRoster","escalationId","field","refreshKey","queryClient","useQueryClient","esc","useEscalation","useEscalationDetailEvents","schema","useMemo","record","form","fieldSchema","X_LT_ACTIONS","_actions","readOnly","RosterWidget","rosterRowContext","expectedLine","expected","e","RefusalPanel","markdown","CircleX","secondsLeft","expiresAt","HoldScreen","subject","progress","progressLabel","note","refusal","onRelease","setTick","interval","t","destination","Package","ScanBadgePrompt","what","DonePanel","nextPrompt","CircleCheck","NOTICE_DISMISS_MS","DETAIL_VERBS","SCAN_VERBS","isBenchResponse","SCAN_OUTCOMES","ScanStationPage","location","useLocation","navigate","useNavigate","user","useAuth","clear","settle","viewerId","useViewerIdentity","lastResult","dropSubject","adoptResponse","followCode","pendingScan","dropPendingScan","kiosk","useKioskMode","roleDetails","useRoleDetails","screen","setScreen","pendingBadge","setPendingBadge","notice","setNotice","actDone","setActDone","following","setFollowing","setBusy","incoming","SCAN_CHOICES_STATE","single","bench","benchAt","followPatterns","role","escalationPatterns","useEventSubscriptions","event","facet","meta","remaining","timer","current","executeChoice","useCallback","result","executeScanChoice","prev","err","holdForBadge","cancelBadge","showChoices","executedBench","benchDone","done","completedRole","scanDone","detailOf","r","kioskHomePath","portalsOf","_c","_d","_e","_f","_g","_h","_i"],"mappings":"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"}
|