@hotmeshio/long-tail 0.30.1 → 0.30.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/build/api/escalations/accumulate.d.ts +2 -1
  2. package/build/api/escalations/accumulate.js +2 -1
  3. package/build/api/escalations/metadata.d.ts +3 -2
  4. package/build/api/escalations/metadata.js +4 -3
  5. package/build/api/escalations/resolve-batch.d.ts +3 -1
  6. package/build/api/escalations/resolve-batch.js +14 -1
  7. package/build/api/scan-codes/choice.js +3 -2
  8. package/build/api/scan-codes/context.d.ts +6 -0
  9. package/build/api/scan-codes/context.js +10 -1
  10. package/build/api/scan-codes/locate.js +1 -0
  11. package/build/api/scan-codes/subject.js +32 -3
  12. package/build/api/scan-codes/verb-accumulate.js +1 -1
  13. package/build/api/scan-codes/verb-fill.js +3 -2
  14. package/build/api/scan-codes/verb-into-subject.js +2 -2
  15. package/build/api/scan-codes/verbs-subject.js +3 -3
  16. package/build/api/scan-codes/verbs.js +4 -4
  17. package/build/lib/db/schemas/043_scan_pattern_and_member_targets.sql +26 -0
  18. package/build/lib/facet-value.d.ts +3 -0
  19. package/build/lib/facet-value.js +9 -0
  20. package/build/routes/scan-codes.js +3 -0
  21. package/build/sdk/index.d.ts +3 -3
  22. package/build/services/escalation/batch.d.ts +4 -3
  23. package/build/services/escalation/batch.js +5 -3
  24. package/build/services/escalation/claim-asserted.d.ts +2 -1
  25. package/build/services/escalation/crud.d.ts +3 -2
  26. package/build/services/orchestrator/condition.d.ts +6 -0
  27. package/build/services/orchestrator/condition.js +6 -0
  28. package/build/services/scan-code/read.js +3 -0
  29. package/build/services/scan-code/sql.d.ts +3 -3
  30. package/build/services/scan-code/sql.js +19 -8
  31. package/build/services/scan-code/validate-scheme-pattern.d.ts +16 -0
  32. package/build/services/scan-code/validate-scheme-pattern.js +75 -0
  33. package/build/services/scan-code/validate.d.ts +3 -1
  34. package/build/services/scan-code/validate.js +6 -1
  35. package/build/services/scan-code/write.d.ts +3 -0
  36. package/build/services/scan-code/write.js +3 -0
  37. package/build/shared/scan-code/index.d.ts +2 -1
  38. package/build/shared/scan-code/index.js +8 -1
  39. package/build/shared/scan-code/parse.d.ts +22 -1
  40. package/build/shared/scan-code/parse.js +78 -0
  41. package/build/shared/scan-code/target.d.ts +4 -0
  42. package/build/shared/scan-code/target.js +14 -0
  43. package/build/system/mcp-servers/admin/schemas.d.ts +86 -77
  44. package/build/system/mcp-servers/admin/schemas.js +4 -1
  45. package/build/system/seed/tool-manifests-admin.js +1 -1
  46. package/build/tsconfig.tsbuildinfo +1 -1
  47. package/build/types/escalation.d.ts +15 -0
  48. package/build/types/escalation.js +16 -1
  49. package/build/types/facets.d.ts +5 -0
  50. package/build/types/index.d.ts +3 -3
  51. package/build/types/index.js +5 -1
  52. package/build/types/scan-code/constants.d.ts +20 -0
  53. package/build/types/scan-code/constants.js +20 -1
  54. package/build/types/scan-code/response.d.ts +2 -1
  55. package/build/types/scan-code/rule.d.ts +11 -1
  56. package/dashboard/dist/assets/{AdminDashboard-CZIeiLe0.js → AdminDashboard-VQ1fhhJP.js} +2 -2
  57. package/dashboard/dist/assets/{AdminDashboard-CZIeiLe0.js.map → AdminDashboard-VQ1fhhJP.js.map} +1 -1
  58. package/dashboard/dist/assets/{AgentConfigPage-DO3ATfCU.js → AgentConfigPage-BOe_W2Ij.js} +2 -2
  59. package/dashboard/dist/assets/{AgentConfigPage-DO3ATfCU.js.map → AgentConfigPage-BOe_W2Ij.js.map} +1 -1
  60. package/dashboard/dist/assets/{AgentDetailPage-BWAlHQfB.js → AgentDetailPage-5ov5D9V2.js} +3 -3
  61. package/dashboard/dist/assets/{AgentDetailPage-BWAlHQfB.js.map → AgentDetailPage-5ov5D9V2.js.map} +1 -1
  62. package/dashboard/dist/assets/{AgentsPage-Cs4IKeec.js → AgentsPage-DDFMKHhI.js} +2 -2
  63. package/dashboard/dist/assets/{AgentsPage-Cs4IKeec.js.map → AgentsPage-DDFMKHhI.js.map} +1 -1
  64. package/dashboard/dist/assets/{AvailableEscalationsPage-CiRxaing.js → AvailableEscalationsPage-GFn8Sgg1.js} +2 -2
  65. package/dashboard/dist/assets/{AvailableEscalationsPage-CiRxaing.js.map → AvailableEscalationsPage-GFn8Sgg1.js.map} +1 -1
  66. package/dashboard/dist/assets/{BotPicker-DGLkc9PQ.js → BotPicker-Dqpo36dM.js} +2 -2
  67. package/dashboard/dist/assets/{BotPicker-DGLkc9PQ.js.map → BotPicker-Dqpo36dM.js.map} +1 -1
  68. package/dashboard/dist/assets/{BulkAssignModal-C4LV8s0y.js → BulkAssignModal-CmLVxkz-.js} +2 -2
  69. package/dashboard/dist/assets/{BulkAssignModal-C4LV8s0y.js.map → BulkAssignModal-CmLVxkz-.js.map} +1 -1
  70. package/dashboard/dist/assets/{CapabilitiesPage-BLMMV3-W.js → CapabilitiesPage-Dfkip6_b.js} +2 -2
  71. package/dashboard/dist/assets/{CapabilitiesPage-BLMMV3-W.js.map → CapabilitiesPage-Dfkip6_b.js.map} +1 -1
  72. package/dashboard/dist/assets/{CollapsibleSection-BAizcNCt.js → CollapsibleSection-CYNYMYSa.js} +2 -2
  73. package/dashboard/dist/assets/{CollapsibleSection-BAizcNCt.js.map → CollapsibleSection-CYNYMYSa.js.map} +1 -1
  74. package/dashboard/dist/assets/{ConfirmDeleteModal-DlNWHVxi.js → ConfirmDeleteModal-CpJNP-8w.js} +2 -2
  75. package/dashboard/dist/assets/{ConfirmDeleteModal-DlNWHVxi.js.map → ConfirmDeleteModal-CpJNP-8w.js.map} +1 -1
  76. package/dashboard/dist/assets/{ConnectedAppsPage-D94kx0v3.js → ConnectedAppsPage-DXIp2Dpl.js} +2 -2
  77. package/dashboard/dist/assets/{ConnectedAppsPage-D94kx0v3.js.map → ConnectedAppsPage-DXIp2Dpl.js.map} +1 -1
  78. package/dashboard/dist/assets/{CountdownTimer-CSdAwgwZ.js → CountdownTimer-CuPY7zkb.js} +2 -2
  79. package/dashboard/dist/assets/{CountdownTimer-CSdAwgwZ.js.map → CountdownTimer-CuPY7zkb.js.map} +1 -1
  80. package/dashboard/dist/assets/{CredentialsPage-pOyC1GfC.js → CredentialsPage-CtrnkHcj.js} +2 -2
  81. package/dashboard/dist/assets/{CredentialsPage-pOyC1GfC.js.map → CredentialsPage-CtrnkHcj.js.map} +1 -1
  82. package/dashboard/dist/assets/{CronLabel-BVlOOcyo.js → CronLabel-DVjTw5Ri.js} +2 -2
  83. package/dashboard/dist/assets/{CronLabel-BVlOOcyo.js.map → CronLabel-DVjTw5Ri.js.map} +1 -1
  84. package/dashboard/dist/assets/{ElapsedCell-Bnjp3onG.js → ElapsedCell-gY_mGMTF.js} +2 -2
  85. package/dashboard/dist/assets/{ElapsedCell-Bnjp3onG.js.map → ElapsedCell-gY_mGMTF.js.map} +1 -1
  86. package/dashboard/dist/assets/{EntityTimelinePanel-D6Z7YXuY.js → EntityTimelinePanel-DJN_ZEQa.js} +2 -2
  87. package/dashboard/dist/assets/{EntityTimelinePanel-D6Z7YXuY.js.map → EntityTimelinePanel-DJN_ZEQa.js.map} +1 -1
  88. package/dashboard/dist/assets/{EscalationListSchemaPage-D2aa_arC.js → EscalationListSchemaPage-A4KpTdJA.js} +3 -3
  89. package/dashboard/dist/assets/{EscalationListSchemaPage-D2aa_arC.js.map → EscalationListSchemaPage-A4KpTdJA.js.map} +1 -1
  90. package/dashboard/dist/assets/{EscalationSchemaPage-DuOje0Ke.js → EscalationSchemaPage-nfCn42hT.js} +2 -2
  91. package/dashboard/dist/assets/{EscalationSchemaPage-DuOje0Ke.js.map → EscalationSchemaPage-nfCn42hT.js.map} +1 -1
  92. package/dashboard/dist/assets/{EscalationTimeline-DFkhU2Z2.js → EscalationTimeline-CLvSr1SD.js} +2 -2
  93. package/dashboard/dist/assets/{EscalationTimeline-DFkhU2Z2.js.map → EscalationTimeline-CLvSr1SD.js.map} +1 -1
  94. package/dashboard/dist/assets/{EscalationTitleSelect-CgYnMM_O.js → EscalationTitleSelect-CT7mYHkb.js} +2 -2
  95. package/dashboard/dist/assets/{EscalationTitleSelect-CgYnMM_O.js.map → EscalationTitleSelect-CT7mYHkb.js.map} +1 -1
  96. package/dashboard/dist/assets/{EscalationsOverview-BTkFoklS.js → EscalationsOverview-CKaGRh-E.js} +2 -2
  97. package/dashboard/dist/assets/{EscalationsOverview-BTkFoklS.js.map → EscalationsOverview-CKaGRh-E.js.map} +1 -1
  98. package/dashboard/dist/assets/{EventTable-MJmAbu6N.js → EventTable-2ywJsOLy.js} +2 -2
  99. package/dashboard/dist/assets/{EventTable-MJmAbu6N.js.map → EventTable-2ywJsOLy.js.map} +1 -1
  100. package/dashboard/dist/assets/{FilterBar-Blt7qcUc.js → FilterBar-Dy0b7wwf.js} +2 -2
  101. package/dashboard/dist/assets/{FilterBar-Blt7qcUc.js.map → FilterBar-Dy0b7wwf.js.map} +1 -1
  102. package/dashboard/dist/assets/{GraphInvokePage-B4K3mT_c.js → GraphInvokePage-yOVpraAy.js} +2 -2
  103. package/dashboard/dist/assets/{GraphInvokePage-B4K3mT_c.js.map → GraphInvokePage-yOVpraAy.js.map} +1 -1
  104. package/dashboard/dist/assets/{HomePage-BN5wXq6V.js → HomePage-67xXjKjN.js} +2 -2
  105. package/dashboard/dist/assets/{HomePage-BN5wXq6V.js.map → HomePage-67xXjKjN.js.map} +1 -1
  106. package/dashboard/dist/assets/{LinePage-CuHHHwBy.js → LinePage-CMsYtukW.js} +3 -3
  107. package/dashboard/dist/assets/{LinePage-CuHHHwBy.js.map → LinePage-CMsYtukW.js.map} +1 -1
  108. package/dashboard/dist/assets/{LinesPage-D9TRHWyt.js → LinesPage-pwL46mOS.js} +3 -3
  109. package/dashboard/dist/assets/{LinesPage-D9TRHWyt.js.map → LinesPage-pwL46mOS.js.map} +1 -1
  110. package/dashboard/dist/assets/{ListToolbar-GGj6X36p.js → ListToolbar-CJmvGy2B.js} +2 -2
  111. package/dashboard/dist/assets/{ListToolbar-GGj6X36p.js.map → ListToolbar-CJmvGy2B.js.map} +1 -1
  112. package/dashboard/dist/assets/{McpOverview-Do31A1jL.js → McpOverview-DA9LLvNG.js} +2 -2
  113. package/dashboard/dist/assets/{McpOverview-Do31A1jL.js.map → McpOverview-DA9LLvNG.js.map} +1 -1
  114. package/dashboard/dist/assets/{McpQueryDetailPage-D6FSB1bS.js → McpQueryDetailPage-N7qLmfE8.js} +2 -2
  115. package/dashboard/dist/assets/{McpQueryDetailPage-D6FSB1bS.js.map → McpQueryDetailPage-N7qLmfE8.js.map} +1 -1
  116. package/dashboard/dist/assets/{McpQueryPage-CyT2d0Y_.js → McpQueryPage-CpsP3w7x.js} +2 -2
  117. package/dashboard/dist/assets/{McpQueryPage-CyT2d0Y_.js.map → McpQueryPage-CpsP3w7x.js.map} +1 -1
  118. package/dashboard/dist/assets/{McpRunDetailPage-C3mmTl4Y.js → McpRunDetailPage-qHRQ1pEY.js} +2 -2
  119. package/dashboard/dist/assets/{McpRunDetailPage-C3mmTl4Y.js.map → McpRunDetailPage-qHRQ1pEY.js.map} +1 -1
  120. package/dashboard/dist/assets/{McpRunsPage-CTeFFUE2.js → McpRunsPage-BRDDYpTM.js} +2 -2
  121. package/dashboard/dist/assets/{McpRunsPage-CTeFFUE2.js.map → McpRunsPage-BRDDYpTM.js.map} +1 -1
  122. package/dashboard/dist/assets/{OperationsPage-BUtQP5dm.js → OperationsPage-zUaab-CL.js} +3 -3
  123. package/dashboard/dist/assets/{OperationsPage-BUtQP5dm.js.map → OperationsPage-zUaab-CL.js.map} +1 -1
  124. package/dashboard/dist/assets/{OperatorDashboard-BwYOXyUV.js → OperatorDashboard-el5BquXN.js} +2 -2
  125. package/dashboard/dist/assets/{OperatorDashboard-BwYOXyUV.js.map → OperatorDashboard-el5BquXN.js.map} +1 -1
  126. package/dashboard/dist/assets/{PersonaDetailPage-CkrKJLNv.js → PersonaDetailPage-B_tb8gfl.js} +2 -2
  127. package/dashboard/dist/assets/{PersonaDetailPage-CkrKJLNv.js.map → PersonaDetailPage-B_tb8gfl.js.map} +1 -1
  128. package/dashboard/dist/assets/{PersonasPage-BS8aBeOv.js → PersonasPage-BPI7mqM8.js} +2 -2
  129. package/dashboard/dist/assets/{PersonasPage-BS8aBeOv.js.map → PersonasPage-BPI7mqM8.js.map} +1 -1
  130. package/dashboard/dist/assets/{PortalPage-PEBk6VVu.js → PortalPage-e_rBb1do.js} +2 -2
  131. package/dashboard/dist/assets/{PortalPage-PEBk6VVu.js.map → PortalPage-e_rBb1do.js.map} +1 -1
  132. package/dashboard/dist/assets/{ProcessDetailPage-CJ71bxDs.js → ProcessDetailPage-D35RX1bB.js} +2 -2
  133. package/dashboard/dist/assets/{ProcessDetailPage-CJ71bxDs.js.map → ProcessDetailPage-D35RX1bB.js.map} +1 -1
  134. package/dashboard/dist/assets/{ProcessesListPage-ov_HLxz5.js → ProcessesListPage-CT81miI5.js} +2 -2
  135. package/dashboard/dist/assets/{ProcessesListPage-ov_HLxz5.js.map → ProcessesListPage-CT81miI5.js.map} +1 -1
  136. package/dashboard/dist/assets/{ResolverForm-BKiUY-lN.js → ResolverForm-BxJkoKAO.js} +2 -2
  137. package/dashboard/dist/assets/{ResolverForm-BKiUY-lN.js.map → ResolverForm-BxJkoKAO.js.map} +1 -1
  138. package/dashboard/dist/assets/{RoleDetailPage-CmfWwjtG.js → RoleDetailPage-DtU7vsJm.js} +2 -2
  139. package/dashboard/dist/assets/{RoleDetailPage-CmfWwjtG.js.map → RoleDetailPage-DtU7vsJm.js.map} +1 -1
  140. package/dashboard/dist/assets/{RolesPage-DvO5DJWY.js → RolesPage-BE7RWt9q.js} +2 -2
  141. package/dashboard/dist/assets/{RolesPage-DvO5DJWY.js.map → RolesPage-BE7RWt9q.js.map} +1 -1
  142. package/dashboard/dist/assets/{RosterWidget-Cs6OTbST.js → RosterWidget-BJMx0a8Z.js} +2 -2
  143. package/dashboard/dist/assets/{RosterWidget-Cs6OTbST.js.map → RosterWidget-BJMx0a8Z.js.map} +1 -1
  144. package/dashboard/dist/assets/{RunAsSelector-VNjUn9Zp.js → RunAsSelector-Co6s9bqA.js} +2 -2
  145. package/dashboard/dist/assets/{RunAsSelector-VNjUn9Zp.js.map → RunAsSelector-Co6s9bqA.js.map} +1 -1
  146. package/dashboard/dist/assets/ScanCodesPage-C2TETaj5.js +2 -0
  147. package/dashboard/dist/assets/ScanCodesPage-C2TETaj5.js.map +1 -0
  148. package/dashboard/dist/assets/ScanSchemeDetailPage-C2UgU8l-.js +5 -0
  149. package/dashboard/dist/assets/ScanSchemeDetailPage-C2UgU8l-.js.map +1 -0
  150. package/dashboard/dist/assets/ScanStationPage-nWYz-OD3.js +2 -0
  151. package/dashboard/dist/assets/ScanStationPage-nWYz-OD3.js.map +1 -0
  152. package/dashboard/dist/assets/SchemeMatchFields-9H7SmbED.js +4 -0
  153. package/dashboard/dist/assets/SchemeMatchFields-9H7SmbED.js.map +1 -0
  154. package/dashboard/dist/assets/{StickyPagination-CJ3jjlDX.js → StickyPagination-miUdVAKw.js} +2 -2
  155. package/dashboard/dist/assets/{StickyPagination-CJ3jjlDX.js.map → StickyPagination-miUdVAKw.js.map} +1 -1
  156. package/dashboard/dist/assets/{StreamMessageDetail-yOdyJGHR.js → StreamMessageDetail-D5Rk7pn7.js} +2 -2
  157. package/dashboard/dist/assets/{StreamMessageDetail-yOdyJGHR.js.map → StreamMessageDetail-D5Rk7pn7.js.map} +1 -1
  158. package/dashboard/dist/assets/{SwimlaneTimeline-DeFWNFrL.js → SwimlaneTimeline-B1QY1ZzH.js} +2 -2
  159. package/dashboard/dist/assets/{SwimlaneTimeline-DeFWNFrL.js.map → SwimlaneTimeline-B1QY1ZzH.js.map} +1 -1
  160. package/dashboard/dist/assets/{TaskDetailPage-BPL_Zx-L.js → TaskDetailPage-DKUM37o8.js} +2 -2
  161. package/dashboard/dist/assets/{TaskDetailPage-BPL_Zx-L.js.map → TaskDetailPage-DKUM37o8.js.map} +1 -1
  162. package/dashboard/dist/assets/{TasksListPage-Bc3S63_O.js → TasksListPage-CUulwvm-.js} +2 -2
  163. package/dashboard/dist/assets/{TasksListPage-Bc3S63_O.js.map → TasksListPage-CUulwvm-.js.map} +1 -1
  164. package/dashboard/dist/assets/{TimeAgo-DAtnJQwU.js → TimeAgo-CHTelacB.js} +2 -2
  165. package/dashboard/dist/assets/{TimeAgo-DAtnJQwU.js.map → TimeAgo-CHTelacB.js.map} +1 -1
  166. package/dashboard/dist/assets/{TimestampCell-CG0erHqq.js → TimestampCell-NanLWLKo.js} +2 -2
  167. package/dashboard/dist/assets/{TimestampCell-CG0erHqq.js.map → TimestampCell-NanLWLKo.js.map} +1 -1
  168. package/dashboard/dist/assets/{ToolTestPanel-c71yqZv7.js → ToolTestPanel-CF1CHzgz.js} +2 -2
  169. package/dashboard/dist/assets/{ToolTestPanel-c71yqZv7.js.map → ToolTestPanel-CF1CHzgz.js.map} +1 -1
  170. package/dashboard/dist/assets/{TopicDetailPage-BlUP0bb1.js → TopicDetailPage-CGO8XV_a.js} +2 -2
  171. package/dashboard/dist/assets/{TopicDetailPage-BlUP0bb1.js.map → TopicDetailPage-CGO8XV_a.js.map} +1 -1
  172. package/dashboard/dist/assets/{TopicsPage-lQ9HNzOq.js → TopicsPage-Bt8gOKYr.js} +2 -2
  173. package/dashboard/dist/assets/{TopicsPage-lQ9HNzOq.js.map → TopicsPage-Bt8gOKYr.js.map} +1 -1
  174. package/dashboard/dist/assets/{UserName-Vf97ofcW.js → UserName-DKXnK7DD.js} +2 -2
  175. package/dashboard/dist/assets/{UserName-Vf97ofcW.js.map → UserName-DKXnK7DD.js.map} +1 -1
  176. package/dashboard/dist/assets/{WorkflowExecutionPage-B195cnHb.js → WorkflowExecutionPage-Crf7AIFc.js} +2 -2
  177. package/dashboard/dist/assets/{WorkflowExecutionPage-B195cnHb.js.map → WorkflowExecutionPage-Crf7AIFc.js.map} +1 -1
  178. package/dashboard/dist/assets/{WorkflowsDashboard-gH-PGsKq.js → WorkflowsDashboard--isjt06C.js} +2 -2
  179. package/dashboard/dist/assets/{WorkflowsDashboard-gH-PGsKq.js.map → WorkflowsDashboard--isjt06C.js.map} +1 -1
  180. package/dashboard/dist/assets/{WorkflowsOverview-D_wYDqw3.js → WorkflowsOverview-D7Oqf4-V.js} +2 -2
  181. package/dashboard/dist/assets/{WorkflowsOverview-D_wYDqw3.js.map → WorkflowsOverview-D7Oqf4-V.js.map} +1 -1
  182. package/dashboard/dist/assets/{YamlWorkflowDetailPage-Imob5F8H.js → YamlWorkflowDetailPage-B0wxgrGP.js} +8 -8
  183. package/dashboard/dist/assets/{YamlWorkflowDetailPage-Imob5F8H.js.map → YamlWorkflowDetailPage-B0wxgrGP.js.map} +1 -1
  184. package/dashboard/dist/assets/{YamlWorkflowsPage-DVEVSKKJ.js → YamlWorkflowsPage-BVdLnm6K.js} +2 -2
  185. package/dashboard/dist/assets/{YamlWorkflowsPage-DVEVSKKJ.js.map → YamlWorkflowsPage-BVdLnm6K.js.map} +1 -1
  186. package/dashboard/dist/assets/{agents-B-8z_DV8.js → agents-CHjbjHXA.js} +2 -2
  187. package/dashboard/dist/assets/{agents-B-8z_DV8.js.map → agents-CHjbjHXA.js.map} +1 -1
  188. package/dashboard/dist/assets/{bots-Clm-wZeG.js → bots-WrUhEPWs.js} +2 -2
  189. package/dashboard/dist/assets/{bots-Clm-wZeG.js.map → bots-WrUhEPWs.js.map} +1 -1
  190. package/dashboard/dist/assets/{capabilities-CBwgv5tr.js → capabilities-CunMmkj8.js} +2 -2
  191. package/dashboard/dist/assets/{capabilities-CBwgv5tr.js.map → capabilities-CunMmkj8.js.map} +1 -1
  192. package/dashboard/dist/assets/{controlplane-B96o1-zT.js → controlplane-D6IZIZoh.js} +2 -2
  193. package/dashboard/dist/assets/{controlplane-B96o1-zT.js.map → controlplane-D6IZIZoh.js.map} +1 -1
  194. package/dashboard/dist/assets/{escalation-columns-CFoFILF1.js → escalation-columns-Bvo6JI4Z.js} +2 -2
  195. package/dashboard/dist/assets/{escalation-columns-CFoFILF1.js.map → escalation-columns-Bvo6JI4Z.js.map} +1 -1
  196. package/dashboard/dist/assets/{escalation-items-BCUiPsfS.js → escalation-items-DFGRwo49.js} +2 -2
  197. package/dashboard/dist/assets/{escalation-items-BCUiPsfS.js.map → escalation-items-DFGRwo49.js.map} +1 -1
  198. package/dashboard/dist/assets/{index-XS-6UjQd.js → index-B8qrHwp9.js} +2 -2
  199. package/dashboard/dist/assets/{index-XS-6UjQd.js.map → index-B8qrHwp9.js.map} +1 -1
  200. package/dashboard/dist/assets/{index-C1WJs6IZ.js → index-B95LbYhW.js} +2 -2
  201. package/dashboard/dist/assets/{index-C1WJs6IZ.js.map → index-B95LbYhW.js.map} +1 -1
  202. package/dashboard/dist/assets/{index-IedmSPp1.js → index-BZFSXEkr.js} +2 -2
  203. package/dashboard/dist/assets/{index-IedmSPp1.js.map → index-BZFSXEkr.js.map} +1 -1
  204. package/dashboard/dist/assets/index-BmzscsXK.css +1 -0
  205. package/dashboard/dist/assets/{index-DvgjLvvn.js → index-Bo8QU31k.js} +2 -2
  206. package/dashboard/dist/assets/{index-DvgjLvvn.js.map → index-Bo8QU31k.js.map} +1 -1
  207. package/dashboard/dist/assets/{index-B_z-OFwk.js → index-C7EIu1mG.js} +2 -2
  208. package/dashboard/dist/assets/{index-B_z-OFwk.js.map → index-C7EIu1mG.js.map} +1 -1
  209. package/dashboard/dist/assets/{index-Czb9O4Ns.js → index-CpCchhQv.js} +2 -2
  210. package/dashboard/dist/assets/{index-Czb9O4Ns.js.map → index-CpCchhQv.js.map} +1 -1
  211. package/dashboard/dist/assets/{index-BXKDpLk5.js → index-DCJ483vt.js} +2 -2
  212. package/dashboard/dist/assets/{index-BXKDpLk5.js.map → index-DCJ483vt.js.map} +1 -1
  213. package/dashboard/dist/assets/{index-CnhNCVPc.js → index-DRK7M1_9.js} +2 -2
  214. package/dashboard/dist/assets/{index-CnhNCVPc.js.map → index-DRK7M1_9.js.map} +1 -1
  215. package/dashboard/dist/assets/{index-BOuGMe78.js → index-DRw0FXdX.js} +2 -2
  216. package/dashboard/dist/assets/{index-BOuGMe78.js.map → index-DRw0FXdX.js.map} +1 -1
  217. package/dashboard/dist/assets/{index-P22vmuEu.js → index-OuKQ_0eB.js} +2 -2
  218. package/dashboard/dist/assets/{index-P22vmuEu.js.map → index-OuKQ_0eB.js.map} +1 -1
  219. package/dashboard/dist/assets/index-P-DlgAWj.js +3 -0
  220. package/dashboard/dist/assets/index-P-DlgAWj.js.map +1 -0
  221. package/dashboard/dist/assets/{index-MGquOb7J.js → index-boT612Jo.js} +2 -2
  222. package/dashboard/dist/assets/{index-MGquOb7J.js.map → index-boT612Jo.js.map} +1 -1
  223. package/dashboard/dist/assets/index-ygxyAKcc.js +67 -0
  224. package/dashboard/dist/assets/index-ygxyAKcc.js.map +1 -0
  225. package/dashboard/dist/assets/{knowledge-d92ncKgf.js → knowledge-BubJBTwg.js} +2 -2
  226. package/dashboard/dist/assets/{knowledge-d92ncKgf.js.map → knowledge-BubJBTwg.js.map} +1 -1
  227. package/dashboard/dist/assets/{machines-BG9laURp.js → machines-DSm5NFgs.js} +2 -2
  228. package/dashboard/dist/assets/{machines-BG9laURp.js.map → machines-DSm5NFgs.js.map} +1 -1
  229. package/dashboard/dist/assets/{mcp-CsZdpCEf.js → mcp-D6MckqOV.js} +2 -2
  230. package/dashboard/dist/assets/{mcp-CsZdpCEf.js.map → mcp-D6MckqOV.js.map} +1 -1
  231. package/dashboard/dist/assets/{mcp-query-o2xqrZJv.js → mcp-query-VyCdOag6.js} +2 -2
  232. package/dashboard/dist/assets/{mcp-query-o2xqrZJv.js.map → mcp-query-VyCdOag6.js.map} +1 -1
  233. package/dashboard/dist/assets/{personas-EYROtAxm.js → personas-CyJc10xe.js} +2 -2
  234. package/dashboard/dist/assets/{personas-EYROtAxm.js.map → personas-CyJc10xe.js.map} +1 -1
  235. package/dashboard/dist/assets/{pipelines-C17xZZsa.js → pipelines-B2inDtx3.js} +2 -2
  236. package/dashboard/dist/assets/{pipelines-C17xZZsa.js.map → pipelines-B2inDtx3.js.map} +1 -1
  237. package/dashboard/dist/assets/{tasks-CUppIhu6.js → tasks-DOP4d3M6.js} +2 -2
  238. package/dashboard/dist/assets/{tasks-CUppIhu6.js.map → tasks-DOP4d3M6.js.map} +1 -1
  239. package/dashboard/dist/assets/{topics-B-lCJzVc.js → topics-CNOjSWpX.js} +2 -2
  240. package/dashboard/dist/assets/{topics-B-lCJzVc.js.map → topics-CNOjSWpX.js.map} +1 -1
  241. package/dashboard/dist/assets/{useDebouncedValue-C5mMbYoU.js → useDebouncedValue-CgO0TGMd.js} +2 -2
  242. package/dashboard/dist/assets/{useDebouncedValue-C5mMbYoU.js.map → useDebouncedValue-CgO0TGMd.js.map} +1 -1
  243. package/dashboard/dist/assets/{useNamespace-Bu42ipvu.js → useNamespace-BWHvUKtK.js} +2 -2
  244. package/dashboard/dist/assets/{useNamespace-Bu42ipvu.js.map → useNamespace-BWHvUKtK.js.map} +1 -1
  245. package/dashboard/dist/assets/{useYamlActivityEvents-C29uM9Qp.js → useYamlActivityEvents-BZQ__ZGD.js} +2 -2
  246. package/dashboard/dist/assets/{useYamlActivityEvents-C29uM9Qp.js.map → useYamlActivityEvents-BZQ__ZGD.js.map} +1 -1
  247. package/dashboard/dist/assets/{validate-Bt5QGwSc.js → validate-CAin6WM_.js} +2 -2
  248. package/dashboard/dist/assets/{validate-Bt5QGwSc.js.map → validate-CAin6WM_.js.map} +1 -1
  249. package/dashboard/dist/assets/{yaml-workflows-DgrmL_Kt.js → yaml-workflows-Dyln3od-.js} +2 -2
  250. package/dashboard/dist/assets/{yaml-workflows-DgrmL_Kt.js.map → yaml-workflows-Dyln3od-.js.map} +1 -1
  251. package/dashboard/dist/index.html +2 -2
  252. package/docs/accumulator.md +1 -1
  253. package/docs/api/http/escalations.md +1 -1
  254. package/docs/api/sdk/escalations.md +1 -1
  255. package/docs/dashboard.md +4 -2
  256. package/docs/hitl/escalation.md +16 -0
  257. package/docs/scan-codes.md +45 -14
  258. package/package.json +2 -2
  259. package/dashboard/dist/assets/GrantScopeField-BzWGzBfA.js +0 -2
  260. package/dashboard/dist/assets/GrantScopeField-BzWGzBfA.js.map +0 -1
  261. package/dashboard/dist/assets/ScanCodesPage-Dbaud0fc.js +0 -2
  262. package/dashboard/dist/assets/ScanCodesPage-Dbaud0fc.js.map +0 -1
  263. package/dashboard/dist/assets/ScanSchemeDetailPage-BfDw_Eke.js +0 -2
  264. package/dashboard/dist/assets/ScanSchemeDetailPage-BfDw_Eke.js.map +0 -1
  265. package/dashboard/dist/assets/ScanStationPage-DE-zJTiD.js +0 -2
  266. package/dashboard/dist/assets/ScanStationPage-DE-zJTiD.js.map +0 -1
  267. package/dashboard/dist/assets/index-CXNh7LuG.js +0 -67
  268. package/dashboard/dist/assets/index-CXNh7LuG.js.map +0 -1
  269. package/dashboard/dist/assets/index-C_dp4WgY.css +0 -1
  270. package/dashboard/dist/assets/index-EZkdUZwM.js +0 -3
  271. package/dashboard/dist/assets/index-EZkdUZwM.js.map +0 -1
@@ -1,2 +1,2 @@
1
- import{j as p,a as U}from"./vendor-query-DvWWuNIB.js";import{a as j}from"./StatusBadge-DHVwxre2.js";import{r as k}from"./index-CXNh7LuG.js";import{b as P}from"./vendor-icons-en0_uSRD.js";import{u as q,a as Y}from"./vendor-react-_9U4mKFr.js";function v(t){return!!(t.assigned_to&&t.assigned_until&&new Date(t.assigned_until)>new Date)}function ft(t){return!t.workflow_type}function W(t){return t.replace(/[_\-.]+/g," ").replace(/([a-z\d])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/([a-zA-Z])(\d)/g,"$1 $2").trim().split(/\s+/).filter(Boolean).map(e=>e===e.toUpperCase()&&e.length>1?e:e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function mt(t){return t.status==="pending"?v(t)?"bg-status-claimed-graphic":"bg-status-active":j[t.status]??"bg-status-active"}function At(t){const s=e=>{if(!e)return null;try{const o=JSON.parse(e);return o&&typeof o=="object"?o:null}catch{return null}};return{escalation:t,metadata:t.metadata??null,envelope:s(t.envelope),payload:s(t.escalation_payload),resolver:s(t.resolver_payload)}}const pt="200px";function gt(t){return`${Math.max(6,Math.round(t.length*.55+3.5))}rem`}const X=30;function K(t){return t.status==="pending"&&!v(t)}function yt({row:t,def:s,onView:e,prominent:o,forceView:i}){const r=(s==null?void 0:s.action)??"claim",a=i?"view":r,l=r===a&&(s!=null&&s.label)?s.label:a==="claim"?"Claim":"View",A=k(),R=q(),L=Y(),[T,h]=U.useState(""),$=a==="claim"&&!K(t),D=I=>{if(I.stopPropagation(),a==="view"){e==null||e();return}if(s!=null&&s.submitOnClaim){R(`/escalations/detail/${t.id}`,{state:{autoStart:!0,durationMinutes:s==null?void 0:s.durationMinutes,from:L.pathname}});return}h(""),A.mutate({id:t.id,durationMinutes:(s==null?void 0:s.durationMinutes)??X},{onSuccess:()=>e==null?void 0:e(),onError:N=>h(N.message)})},C=o?"btn-primary text-xs shrink-0 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-accent":"px-2 py-0.5 rounded text-2xs font-medium text-accent/70 border border-accent/30 enabled:hover:text-accent enabled:hover:border-accent/60 enabled:hover:bg-accent/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap";return p.jsxs("span",{className:"inline-flex flex-col items-end gap-0.5",children:[p.jsx("button",{type:"button",onClick:D,disabled:A.isPending||$,title:$?t.status==="pending"?"claimed":t.status:void 0,className:C,"data-testid":"row-action-button",children:A.isPending?"Claiming…":l}),T&&p.jsx("span",{className:"text-2xs text-status-error","data-testid":"row-action-error",children:T})]})}const Z=/^\{\{\s*metadata\.([a-zA-Z0-9_]+)\s*\}\}$/;function x(t){return typeof t=="string"&&t!==""||typeof t=="number"||typeof t=="boolean"}function Et(t,s){var r;const e=[],o=new Set,i=t.metadata??{};for(const a of s){const l=typeof a.value=="string"?(r=a.value.match(Z))==null?void 0:r[1]:void 0;if(!l||o.has(l))continue;const A=i[l];x(A)&&(o.add(l),e.push({key:l,label:a.label,value:A,bound:!0}))}for(const[a,l]of Object.entries(i))o.has(a)||!x(l)||(o.add(a),e.push({key:a,label:W(a),value:l}));return e}function bt({onOpen:t,className:s=""}){return p.jsx("button",{type:"button",onClick:e=>{e.stopPropagation(),t()},className:`p-1.5 rounded text-text-quaternary/70 hover:text-accent hover:bg-surface-hover transition-colors ${s}`,title:"Refine — filter or search by this row's values","aria-label":"Refine — filter or search by this row's values","data-testid":"row-refine",children:p.jsx(P,{className:"w-3.5 h-3.5",strokeWidth:1.5})})}const g={RELATED:"x-lt-related",COLUMNS:"x-lt-columns",ROW_DETAIL:"x-lt-row-detail",GROUP_BY:"x-lt-group-by",LAYOUT:"x-lt-layout"},f={ITEMS:"items",QUERY:"query"},E={COUNT:"count",MIN:"min",MAX:"max"},z={FIRST:"first",MIN:"min",MAX:"max",SUM:"sum",COUNT:"count",DISTINCT:"distinct"},u={ROLE:"role",METADATA:"metadata.",PAYLOAD:"payload.",RECIPROCAL_METADATA:"reciprocal.metadata."},d={MAX_SETS:4,MAX_QUERY_ROLES:12,MAX_ROW_DETAIL_SECTIONS:4,ROWS_MAX:100},G="facet-table",M="default",F=/^\{\{\s*([^{}]+?)\s*\}\}$/,_="item.",Q=/^[a-zA-Z0-9_]+$/,B=/^[a-zA-Z0-9_]+$/,H=/\{n\}/g;function b(t){return t===E.MIN||t===E.MAX}function O(t,s){var i;if(typeof s!="string")return null;const e=(i=s.match(F))==null?void 0:i[1];if(!e)return null;if(t===f.ITEMS){if(!e.startsWith(`${_}${u.PAYLOAD}`))return null;const r=e.slice(_.length+u.PAYLOAD.length);return r&&r.split(".").every(a=>Q.test(a))?`${u.PAYLOAD}${r}`:null}if(!e.startsWith(u.METADATA))return null;const o=e.slice(u.METADATA.length);return B.test(o)?e:null}function Tt(t,s){return b(t.aggregate)?`${t.aggregate}:${O(s,t.value)??""}`:t.splitBy??""}function ht(t,s){if(!t)return null;const e=t[String(s)]??t[M];return e===void 0?null:e.replace(H,String(s))}function $t(t,s){if(!s.length)return;const e=t===E.MIN;if(s.every(i=>typeof i=="number"))return e?Math.min(...s):Math.max(...s);const o=s.map(String).sort((i,r)=>i<r?-1:i>r?1:0);return e?o[0]:o[o.length-1]}const y=/^[a-zA-Z0-9_]+$/,J=/^[a-zA-Z][a-zA-Z0-9_-]{0,47}$/,w=/^[a-zA-Z0-9_]+$/,V=/^(0|[1-9][0-9]*)$/;class tt extends Error{}function n(t){throw new tt(t)}function c(t){return!!t&&typeof t=="object"&&!Array.isArray(t)}function m(t){return typeof t=="string"&&t.trim().length>0}function et(t){return t.length>0&&t.split(".").every(s=>w.test(s))}function st(t,s){return t===f.QUERY?s===u.ROLE||s.startsWith(u.METADATA)&&y.test(s.slice(u.METADATA.length))?null:`splitBy "${s}" on a query set must be "role" or "metadata.<key>"`:s.startsWith(u.PAYLOAD)&&et(s.slice(u.PAYLOAD.length))||s.startsWith(u.RECIPROCAL_METADATA)&&y.test(s.slice(u.RECIPROCAL_METADATA.length))?null:`splitBy "${s}" on an items set must be "payload.<path>" or "reciprocal.metadata.<key>"`}function rt(t,s){if(J.test(t)||n(`x-lt-related name "${t}" must start with a letter (letters, digits, _ or -)`),c(s)||n(`x-lt-related.${t} must be an object`),s.source===f.ITEMS)return s.query!==void 0&&n(`x-lt-related.${t}: an items set takes no query`),{source:f.ITEMS};s.source!==f.QUERY&&n(`x-lt-related.${t}.source must be "items" or "query"`);const e=s.query;c(e)||n(`x-lt-related.${t}.query is required for a query set`);const o=e.roles!==void 0,i=e.segment!==void 0;if(o===i&&n(`x-lt-related.${t}.query takes exactly one of roles or segment`),o){const r=e.roles;(!Array.isArray(r)||r.length===0||r.length>d.MAX_QUERY_ROLES||!r.every(m))&&n(`x-lt-related.${t}.query.roles must be 1..${d.MAX_QUERY_ROLES} role names`)}else m(e.segment)||n(`x-lt-related.${t}.query.segment must be a role name`);(!c(e.facets)||Object.keys(e.facets).length===0)&&n(`x-lt-related.${t}.query.facets must name at least one facet`);for(const[r,a]of Object.entries(e.facets))y.test(r)||n(`x-lt-related.${t}.query.facets key "${r}" must be letters, digits or _`),(a===null||typeof a=="object")&&n(`x-lt-related.${t}.query.facets.${r} must be a scalar or template`);if(e.narrow!==void 0){(!c(e.narrow)||Object.keys(e.narrow).length===0)&&n(`x-lt-related.${t}.query.narrow must name at least one facet`);for(const[r,a]of Object.entries(e.narrow))y.test(r)||n(`x-lt-related.${t}.query.narrow key "${r}" must be letters, digits or _`),r in e.facets&&n(`x-lt-related.${t}.query.narrow.${r} is already a required facet`),(a===null||typeof a=="object")&&n(`x-lt-related.${t}.query.narrow.${r} must be a scalar or template`)}return e.status!==void 0&&!m(e.status)&&n(`x-lt-related.${t}.query.status must be a status`),{source:f.QUERY,query:{...o?{roles:[...e.roles]}:{segment:e.segment},facets:{...e.facets},...e.narrow!==void 0?{narrow:{...e.narrow}}:{},...e.status!==void 0?{status:e.status}:{}}}}function at(t,s,e){const o=t.related;(!m(o)||!s[o])&&n(`${e}.related must name a set declared in x-lt-related`),t.aggregate!==void 0&&t.aggregate!==E.COUNT&&!b(t.aggregate)&&n(`${e}.aggregate must be "count", "min" or "max"`);const i=s[o].source;if(b(t.aggregate)?(O(i,t.value)||n(i===f.ITEMS?`${e}.value must be "{{item.payload.<path>}}" on an items set`:`${e}.value must be "{{metadata.<key>}}" on a query set`),t.splitBy!==void 0&&n(`${e}: a ${t.aggregate} column takes no splitBy`),t.display!==void 0&&n(`${e}: display applies to a count column`)):t.value!==void 0&&n(`${e}.value applies to a min or max column`),t.format!==void 0&&typeof t.format!="string"&&n(`${e}.format must be a format name`),t.display!==void 0&&(!c(t.display)||Object.keys(t.display).length===0||!Object.entries(t.display).every(([r,a])=>(r===M||V.test(r))&&typeof a=="string"))&&n(`${e}.display must map counts (or "default") to display text`),t.splitBy!==void 0){m(t.splitBy)||n(`${e}.splitBy must be a path`);const r=st(s[o].source,t.splitBy);r&&n(`${e}: ${r}`)}return t.labels!==void 0&&(!c(t.labels)||!Object.values(t.labels).every(r=>typeof r=="string"))&&n(`${e}.labels must map values to display text`),t}function nt(t,s){return t===void 0?[]:((!Array.isArray(t)||t.length===0||t.length>d.MAX_ROW_DETAIL_SECTIONS)&&n(`x-lt-row-detail must be 1..${d.MAX_ROW_DETAIL_SECTIONS} sections`),t.map((e,o)=>{const i=`x-lt-row-detail[${o}]`;c(e)||n(`${i} must be an object`),(!m(e.related)||!s[e.related])&&n(`${i}.related must name a set declared in x-lt-related`),(!Array.isArray(e.columns)||e.columns.length===0)&&n(`${i}.columns must list at least one column`);for(const[r,a]of e.columns.entries())(!c(a)||!m(a.label)||typeof a.value!="string")&&n(`${i}.columns[${r}] needs a label and a value template`);return e.limit!==void 0&&(!Number.isInteger(e.limit)||e.limit<1||e.limit>d.ROWS_MAX)&&n(`${i}.limit must be 1..${d.ROWS_MAX}`),e}))}function ot(t){const s=t[g.GROUP_BY];if(s===void 0||t[g.LAYOUT]!==G)return null;const e=typeof s=="string"&&s.startsWith(u.METADATA)?s.slice(u.METADATA.length):"";return y.test(e)||n('x-lt-group-by on a facet-table must be "metadata.<key>"'),e}const S=new Set(Object.values(z));function xt(t){const s={sets:{},columns:[],rowDetail:[],groupKey:null};if(!c(t))return s;const e=t[g.RELATED],o={};if(e!==void 0){c(e)||n("x-lt-related must map set names to declarations");const a=Object.keys(e);(a.length===0||a.length>d.MAX_SETS)&&n(`x-lt-related must declare 1..${d.MAX_SETS} sets`);for(const l of a)o[l]=rt(l,e[l])}const i=[],r=t[g.COLUMNS];return Array.isArray(r)&&r.forEach((a,l)=>{c(a)&&(a.related!==void 0&&i.push(at(a,o,`x-lt-columns[${l}]`)),a.group!==void 0&&(typeof a.group!="string"||!S.has(a.group))&&n(`x-lt-columns[${l}].group must be one of ${[...S].join(", ")}`))}),{sets:o,columns:i,rowDetail:nt(t[g.ROW_DETAIL],o),groupKey:ot(t)}}export{z as G,pt as I,Z as M,bt as R,u as S,W as a,xt as b,b as c,ht as d,mt as e,$t as f,Et as g,yt as h,v as i,gt as j,Tt as k,ft as l,At as r};
2
- //# sourceMappingURL=validate-Bt5QGwSc.js.map
1
+ import{j as p,a as U}from"./vendor-query-DvWWuNIB.js";import{a as j}from"./StatusBadge-DHVwxre2.js";import{r as k}from"./index-ygxyAKcc.js";import{b as P}from"./vendor-icons-en0_uSRD.js";import{u as q,a as Y}from"./vendor-react-_9U4mKFr.js";function v(t){return!!(t.assigned_to&&t.assigned_until&&new Date(t.assigned_until)>new Date)}function ft(t){return!t.workflow_type}function W(t){return t.replace(/[_\-.]+/g," ").replace(/([a-z\d])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/([a-zA-Z])(\d)/g,"$1 $2").trim().split(/\s+/).filter(Boolean).map(e=>e===e.toUpperCase()&&e.length>1?e:e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function mt(t){return t.status==="pending"?v(t)?"bg-status-claimed-graphic":"bg-status-active":j[t.status]??"bg-status-active"}function At(t){const s=e=>{if(!e)return null;try{const o=JSON.parse(e);return o&&typeof o=="object"?o:null}catch{return null}};return{escalation:t,metadata:t.metadata??null,envelope:s(t.envelope),payload:s(t.escalation_payload),resolver:s(t.resolver_payload)}}const pt="200px";function gt(t){return`${Math.max(6,Math.round(t.length*.55+3.5))}rem`}const X=30;function K(t){return t.status==="pending"&&!v(t)}function yt({row:t,def:s,onView:e,prominent:o,forceView:i}){const r=(s==null?void 0:s.action)??"claim",a=i?"view":r,l=r===a&&(s!=null&&s.label)?s.label:a==="claim"?"Claim":"View",A=k(),R=q(),L=Y(),[T,h]=U.useState(""),$=a==="claim"&&!K(t),D=I=>{if(I.stopPropagation(),a==="view"){e==null||e();return}if(s!=null&&s.submitOnClaim){R(`/escalations/detail/${t.id}`,{state:{autoStart:!0,durationMinutes:s==null?void 0:s.durationMinutes,from:L.pathname}});return}h(""),A.mutate({id:t.id,durationMinutes:(s==null?void 0:s.durationMinutes)??X},{onSuccess:()=>e==null?void 0:e(),onError:N=>h(N.message)})},C=o?"btn-primary text-xs shrink-0 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-accent":"px-2 py-0.5 rounded text-2xs font-medium text-accent/70 border border-accent/30 enabled:hover:text-accent enabled:hover:border-accent/60 enabled:hover:bg-accent/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap";return p.jsxs("span",{className:"inline-flex flex-col items-end gap-0.5",children:[p.jsx("button",{type:"button",onClick:D,disabled:A.isPending||$,title:$?t.status==="pending"?"claimed":t.status:void 0,className:C,"data-testid":"row-action-button",children:A.isPending?"Claiming…":l}),T&&p.jsx("span",{className:"text-2xs text-status-error","data-testid":"row-action-error",children:T})]})}const Z=/^\{\{\s*metadata\.([a-zA-Z0-9_]+)\s*\}\}$/;function x(t){return typeof t=="string"&&t!==""||typeof t=="number"||typeof t=="boolean"}function Et(t,s){var r;const e=[],o=new Set,i=t.metadata??{};for(const a of s){const l=typeof a.value=="string"?(r=a.value.match(Z))==null?void 0:r[1]:void 0;if(!l||o.has(l))continue;const A=i[l];x(A)&&(o.add(l),e.push({key:l,label:a.label,value:A,bound:!0}))}for(const[a,l]of Object.entries(i))o.has(a)||!x(l)||(o.add(a),e.push({key:a,label:W(a),value:l}));return e}function bt({onOpen:t,className:s=""}){return p.jsx("button",{type:"button",onClick:e=>{e.stopPropagation(),t()},className:`p-1.5 rounded text-text-quaternary/70 hover:text-accent hover:bg-surface-hover transition-colors ${s}`,title:"Refine — filter or search by this row's values","aria-label":"Refine — filter or search by this row's values","data-testid":"row-refine",children:p.jsx(P,{className:"w-3.5 h-3.5",strokeWidth:1.5})})}const g={RELATED:"x-lt-related",COLUMNS:"x-lt-columns",ROW_DETAIL:"x-lt-row-detail",GROUP_BY:"x-lt-group-by",LAYOUT:"x-lt-layout"},f={ITEMS:"items",QUERY:"query"},E={COUNT:"count",MIN:"min",MAX:"max"},z={FIRST:"first",MIN:"min",MAX:"max",SUM:"sum",COUNT:"count",DISTINCT:"distinct"},u={ROLE:"role",METADATA:"metadata.",PAYLOAD:"payload.",RECIPROCAL_METADATA:"reciprocal.metadata."},d={MAX_SETS:4,MAX_QUERY_ROLES:12,MAX_ROW_DETAIL_SECTIONS:4,ROWS_MAX:100},G="facet-table",M="default",F=/^\{\{\s*([^{}]+?)\s*\}\}$/,_="item.",Q=/^[a-zA-Z0-9_]+$/,B=/^[a-zA-Z0-9_]+$/,H=/\{n\}/g;function b(t){return t===E.MIN||t===E.MAX}function O(t,s){var i;if(typeof s!="string")return null;const e=(i=s.match(F))==null?void 0:i[1];if(!e)return null;if(t===f.ITEMS){if(!e.startsWith(`${_}${u.PAYLOAD}`))return null;const r=e.slice(_.length+u.PAYLOAD.length);return r&&r.split(".").every(a=>Q.test(a))?`${u.PAYLOAD}${r}`:null}if(!e.startsWith(u.METADATA))return null;const o=e.slice(u.METADATA.length);return B.test(o)?e:null}function Tt(t,s){return b(t.aggregate)?`${t.aggregate}:${O(s,t.value)??""}`:t.splitBy??""}function ht(t,s){if(!t)return null;const e=t[String(s)]??t[M];return e===void 0?null:e.replace(H,String(s))}function $t(t,s){if(!s.length)return;const e=t===E.MIN;if(s.every(i=>typeof i=="number"))return e?Math.min(...s):Math.max(...s);const o=s.map(String).sort((i,r)=>i<r?-1:i>r?1:0);return e?o[0]:o[o.length-1]}const y=/^[a-zA-Z0-9_]+$/,J=/^[a-zA-Z][a-zA-Z0-9_-]{0,47}$/,w=/^[a-zA-Z0-9_]+$/,V=/^(0|[1-9][0-9]*)$/;class tt extends Error{}function n(t){throw new tt(t)}function c(t){return!!t&&typeof t=="object"&&!Array.isArray(t)}function m(t){return typeof t=="string"&&t.trim().length>0}function et(t){return t.length>0&&t.split(".").every(s=>w.test(s))}function st(t,s){return t===f.QUERY?s===u.ROLE||s.startsWith(u.METADATA)&&y.test(s.slice(u.METADATA.length))?null:`splitBy "${s}" on a query set must be "role" or "metadata.<key>"`:s.startsWith(u.PAYLOAD)&&et(s.slice(u.PAYLOAD.length))||s.startsWith(u.RECIPROCAL_METADATA)&&y.test(s.slice(u.RECIPROCAL_METADATA.length))?null:`splitBy "${s}" on an items set must be "payload.<path>" or "reciprocal.metadata.<key>"`}function rt(t,s){if(J.test(t)||n(`x-lt-related name "${t}" must start with a letter (letters, digits, _ or -)`),c(s)||n(`x-lt-related.${t} must be an object`),s.source===f.ITEMS)return s.query!==void 0&&n(`x-lt-related.${t}: an items set takes no query`),{source:f.ITEMS};s.source!==f.QUERY&&n(`x-lt-related.${t}.source must be "items" or "query"`);const e=s.query;c(e)||n(`x-lt-related.${t}.query is required for a query set`);const o=e.roles!==void 0,i=e.segment!==void 0;if(o===i&&n(`x-lt-related.${t}.query takes exactly one of roles or segment`),o){const r=e.roles;(!Array.isArray(r)||r.length===0||r.length>d.MAX_QUERY_ROLES||!r.every(m))&&n(`x-lt-related.${t}.query.roles must be 1..${d.MAX_QUERY_ROLES} role names`)}else m(e.segment)||n(`x-lt-related.${t}.query.segment must be a role name`);(!c(e.facets)||Object.keys(e.facets).length===0)&&n(`x-lt-related.${t}.query.facets must name at least one facet`);for(const[r,a]of Object.entries(e.facets))y.test(r)||n(`x-lt-related.${t}.query.facets key "${r}" must be letters, digits or _`),(a===null||typeof a=="object")&&n(`x-lt-related.${t}.query.facets.${r} must be a scalar or template`);if(e.narrow!==void 0){(!c(e.narrow)||Object.keys(e.narrow).length===0)&&n(`x-lt-related.${t}.query.narrow must name at least one facet`);for(const[r,a]of Object.entries(e.narrow))y.test(r)||n(`x-lt-related.${t}.query.narrow key "${r}" must be letters, digits or _`),r in e.facets&&n(`x-lt-related.${t}.query.narrow.${r} is already a required facet`),(a===null||typeof a=="object")&&n(`x-lt-related.${t}.query.narrow.${r} must be a scalar or template`)}return e.status!==void 0&&!m(e.status)&&n(`x-lt-related.${t}.query.status must be a status`),{source:f.QUERY,query:{...o?{roles:[...e.roles]}:{segment:e.segment},facets:{...e.facets},...e.narrow!==void 0?{narrow:{...e.narrow}}:{},...e.status!==void 0?{status:e.status}:{}}}}function at(t,s,e){const o=t.related;(!m(o)||!s[o])&&n(`${e}.related must name a set declared in x-lt-related`),t.aggregate!==void 0&&t.aggregate!==E.COUNT&&!b(t.aggregate)&&n(`${e}.aggregate must be "count", "min" or "max"`);const i=s[o].source;if(b(t.aggregate)?(O(i,t.value)||n(i===f.ITEMS?`${e}.value must be "{{item.payload.<path>}}" on an items set`:`${e}.value must be "{{metadata.<key>}}" on a query set`),t.splitBy!==void 0&&n(`${e}: a ${t.aggregate} column takes no splitBy`),t.display!==void 0&&n(`${e}: display applies to a count column`)):t.value!==void 0&&n(`${e}.value applies to a min or max column`),t.format!==void 0&&typeof t.format!="string"&&n(`${e}.format must be a format name`),t.display!==void 0&&(!c(t.display)||Object.keys(t.display).length===0||!Object.entries(t.display).every(([r,a])=>(r===M||V.test(r))&&typeof a=="string"))&&n(`${e}.display must map counts (or "default") to display text`),t.splitBy!==void 0){m(t.splitBy)||n(`${e}.splitBy must be a path`);const r=st(s[o].source,t.splitBy);r&&n(`${e}: ${r}`)}return t.labels!==void 0&&(!c(t.labels)||!Object.values(t.labels).every(r=>typeof r=="string"))&&n(`${e}.labels must map values to display text`),t}function nt(t,s){return t===void 0?[]:((!Array.isArray(t)||t.length===0||t.length>d.MAX_ROW_DETAIL_SECTIONS)&&n(`x-lt-row-detail must be 1..${d.MAX_ROW_DETAIL_SECTIONS} sections`),t.map((e,o)=>{const i=`x-lt-row-detail[${o}]`;c(e)||n(`${i} must be an object`),(!m(e.related)||!s[e.related])&&n(`${i}.related must name a set declared in x-lt-related`),(!Array.isArray(e.columns)||e.columns.length===0)&&n(`${i}.columns must list at least one column`);for(const[r,a]of e.columns.entries())(!c(a)||!m(a.label)||typeof a.value!="string")&&n(`${i}.columns[${r}] needs a label and a value template`);return e.limit!==void 0&&(!Number.isInteger(e.limit)||e.limit<1||e.limit>d.ROWS_MAX)&&n(`${i}.limit must be 1..${d.ROWS_MAX}`),e}))}function ot(t){const s=t[g.GROUP_BY];if(s===void 0||t[g.LAYOUT]!==G)return null;const e=typeof s=="string"&&s.startsWith(u.METADATA)?s.slice(u.METADATA.length):"";return y.test(e)||n('x-lt-group-by on a facet-table must be "metadata.<key>"'),e}const S=new Set(Object.values(z));function xt(t){const s={sets:{},columns:[],rowDetail:[],groupKey:null};if(!c(t))return s;const e=t[g.RELATED],o={};if(e!==void 0){c(e)||n("x-lt-related must map set names to declarations");const a=Object.keys(e);(a.length===0||a.length>d.MAX_SETS)&&n(`x-lt-related must declare 1..${d.MAX_SETS} sets`);for(const l of a)o[l]=rt(l,e[l])}const i=[],r=t[g.COLUMNS];return Array.isArray(r)&&r.forEach((a,l)=>{c(a)&&(a.related!==void 0&&i.push(at(a,o,`x-lt-columns[${l}]`)),a.group!==void 0&&(typeof a.group!="string"||!S.has(a.group))&&n(`x-lt-columns[${l}].group must be one of ${[...S].join(", ")}`))}),{sets:o,columns:i,rowDetail:nt(t[g.ROW_DETAIL],o),groupKey:ot(t)}}export{z as G,pt as I,Z as M,bt as R,u as S,W as a,xt as b,b as c,ht as d,mt as e,$t as f,Et as g,yt as h,v as i,gt as j,Tt as k,ft as l,At as r};
2
+ //# sourceMappingURL=validate-CAin6WM_.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate-Bt5QGwSc.js","sources":["../../src/lib/escalation.ts","../../src/lib/identifier-label.ts","../../src/components/escalation/list-view/row-parts.tsx","../../../shared/list-schema/types.ts","../../../shared/list-schema/aggregate.ts","../../../shared/list-schema/validate.ts"],"sourcesContent":["import type { LTEscalationRecord } from '../api/types';\n\nexport function isEffectivelyClaimed(esc: LTEscalationRecord): boolean {\n return !!(\n esc.assigned_to &&\n esc.assigned_until &&\n new Date(esc.assigned_until) > new Date()\n );\n}\n\n/** An ACK escalation has no associated workflow — it's a notification, not a task. */\nexport function isAckEscalation(esc: LTEscalationRecord): boolean {\n return !esc.workflow_type;\n}\n\nexport function isAvailable(esc: LTEscalationRecord): boolean {\n return (\n esc.status === 'pending' &&\n (!esc.assigned_to ||\n !esc.assigned_until ||\n new Date(esc.assigned_until) <= new Date())\n );\n}\n","/**\n * A human label for a code identifier: camelCase, snake_case, kebab-case, and\n * digit runs become Title Case words. `fleetTools` → `Fleet Tools`,\n * `print_order2` → `Print Order 2`. Acronyms keep their capitals: `mcpQuery`\n * → `Mcp Query` is avoided by treating an all-caps run as one word.\n */\nexport function identifierToTitle(id: string): string {\n const words = id\n .replace(/[_\\-.]+/g, ' ')\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/([a-zA-Z])(\\d)/g, '$1 $2')\n .trim()\n .split(/\\s+/)\n .filter(Boolean);\n return words\n .map((w) => (w === w.toUpperCase() && w.length > 1 ? w : w.charAt(0).toUpperCase() + w.slice(1)))\n .join(' ');\n}\n","import { useState } from 'react';\nimport { useNavigate, useLocation } from 'react-router-dom';\nimport { Search } from 'lucide-react';\nimport type { HelpTokenContext } from '../../../lib/x-lt-help';\nimport { STATUS_DOT_STYLES } from '../../common/display/StatusBadge';\nimport { useClaimEscalation } from '../../../api/escalations';\nimport { isEffectivelyClaimed } from '../../../lib/escalation';\nimport { identifierToTitle } from '../../../lib/identifier-label';\nimport type { RefinePair } from '../RefineDialog';\nimport type { LTEscalationRecord } from '../../../api/types';\n\n/** The row-level pieces every list layout shares: column and action\n * declarations, the row's token context, the row action, and refine. */\n\n/** Dot colour matches the standard table view: blue = pending unclaimed,\n * orange = under a live claim; other statuses follow the shared map. */\nexport function escalationDotClass(e: LTEscalationRecord): string {\n if (e.status === 'pending') {\n return isEffectivelyClaimed(e) ? 'bg-status-claimed-graphic' : 'bg-status-active';\n }\n return STATUS_DOT_STYLES[e.status] ?? 'bg-status-active';\n}\n\nexport interface ColumnDef {\n label: string;\n value: string;\n /** \"age\" renders an ISO timestamp as a compact age with an absolute tooltip. */\n format?: string;\n /**\n * Card-fold behavior when the table folds at narrow widths (same contract\n * as the engineer table): 1 = identity — always visible, forms the card's\n * title line; 2 = folds into the card body as a label/value pair; 3 =\n * dropped in card mode. Undeclared, the first column is the identity and\n * the rest fold.\n */\n priority?: 1 | 2 | 3;\n /** CSS column width (\"40%\", \"12rem\"). Unset columns share the remainder;\n * when no column declares one, the first column holds a fixed 200px so\n * the identity stays legible and every other value keeps its room. */\n width?: string;\n}\n\n/**\n * The per-row action button — the queue-working gesture, always available on\n * every layout. Template-driven: the schema author sets the action, its text,\n * and (for claim) the hold time.\n */\nexport interface RowActionDef {\n /** \"claim\" fires a one-click claim then opens the detail page already\n * claimed; \"view\" just opens it. Default \"claim\". */\n action?: 'claim' | 'view';\n /** Button text. Defaults \"Claim\" / \"View\" by action. */\n label?: string;\n /** Claim hold time in minutes. Default 30 (the platform claim default). */\n durationMinutes?: number;\n /**\n * Launch the detail page's claim-and-submit flow instead of a plain claim:\n * the row is claimed, the form's seeded defaults are resolved, and — when the\n * form declares `x-lt-transition` — the wait screen bridges to the born-assigned\n * follow-on. One list gesture (\"Start Harvesting\") starts the work and lands\n * the person on the next step. The behavior lives on the detail page (form\n * defaults, validation, transition); the list only points there with intent.\n */\n submitOnClaim?: boolean;\n}\n\n/** Build the token context for one escalation row (payloads are JSON strings). */\nexport function rowContext(e: LTEscalationRecord): HelpTokenContext {\n const parse = (s: string | null | undefined): Record<string, unknown> | null => {\n if (!s) return null;\n try {\n const v = JSON.parse(s);\n return v && typeof v === 'object' ? v : null;\n } catch {\n return null;\n }\n };\n return {\n escalation: e as unknown as Record<string, unknown>,\n metadata: e.metadata ?? null,\n envelope: parse(e.envelope),\n payload: parse(e.escalation_payload),\n resolver: parse(e.resolver_payload),\n };\n}\n\n/** The identity column's width when no column declares one: room for a label, no more. */\nexport const IDENTITY_COLUMN_WIDTH = '200px';\n\n/** The action column sizes to its label so the button never wraps or truncates. */\nexport function actionColumnWidth(label: string): string {\n return `${Math.max(6, Math.round(label.length * 0.55 + 3.5))}rem`;\n}\n\nconst DEFAULT_CLAIM_MINUTES = 30;\n\n/** Claim targets pending rows without a live claim window. */\nfunction isClaimable(row: LTEscalationRecord): boolean {\n return row.status === 'pending' && !isEffectivelyClaimed(row);\n}\n\n/**\n * The x-lt-row-action button. `claim` is one click: claim for the template's\n * duration, then open the detail page already claimed — the fast path for\n * working a queue. `view` opens the detail page. Persistent (light accent at\n * rest, saturating on hover); a rejected claim surfaces its message inline.\n */\nexport function RowActionButton({ row, def, onView, prominent, forceView }: {\n row: LTEscalationRecord;\n def?: RowActionDef;\n onView?: () => void;\n /** Hero treatment for the active-card CTA; default is the compact row button. */\n prominent?: boolean;\n /** Render claim templates as view actions (see EscalationListView). */\n forceView?: boolean;\n}) {\n const authored = def?.action ?? 'claim';\n const action = forceView ? 'view' : authored;\n // The authored label describes the authored gesture. When view is forced\n // over a claim template, claim wording would mislead — use the view default.\n const label = authored === action && def?.label\n ? def.label\n : action === 'claim' ? 'Claim' : 'View';\n const claim = useClaimEscalation();\n const navigate = useNavigate();\n const location = useLocation();\n const [error, setError] = useState('');\n\n // A spent gesture stays visible — the disabled button keeps every row's\n // layout uniform instead of leaving a hole on resolved/held rows.\n const spent = action === 'claim' && !isClaimable(row);\n\n const fire = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (action === 'view') {\n onView?.();\n return;\n }\n // Launch the detail page's claim → submit → transition flow. The detail\n // page owns the heavy lifting (seed defaults, validate, resolve, hand-off);\n // the list points there with the intent and the authored claim duration.\n if (def?.submitOnClaim) {\n navigate(`/escalations/detail/${row.id}`, {\n state: { autoStart: true, durationMinutes: def?.durationMinutes, from: location.pathname },\n });\n return;\n }\n setError('');\n claim.mutate(\n { id: row.id, durationMinutes: def?.durationMinutes ?? DEFAULT_CLAIM_MINUTES },\n {\n onSuccess: () => onView?.(),\n onError: (err) => setError((err as Error).message),\n },\n );\n };\n\n const classes = prominent\n ? 'btn-primary text-xs shrink-0 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-accent'\n : 'px-2 py-0.5 rounded text-2xs font-medium text-accent/70 border border-accent/30 enabled:hover:text-accent enabled:hover:border-accent/60 enabled:hover:bg-accent/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap';\n\n return (\n <span className=\"inline-flex flex-col items-end gap-0.5\">\n <button\n type=\"button\"\n onClick={fire}\n disabled={claim.isPending || spent}\n title={spent ? (row.status === 'pending' ? 'claimed' : row.status) : undefined}\n className={classes}\n data-testid=\"row-action-button\"\n >\n {claim.isPending ? 'Claiming…' : label}\n </button>\n {error && <span className=\"text-2xs text-status-error\" data-testid=\"row-action-error\">{error}</span>}\n </span>\n );\n}\n\n/** A field value token that is a pure metadata binding — facet-linkable. */\nexport const METADATA_TOKEN = /^\\{\\{\\s*metadata\\.([a-zA-Z0-9_]+)\\s*\\}\\}$/;\n\n/** A metadata value the faceted query can match on: a scalar with something in it. */\nfunction isFacetValue(raw: unknown): raw is string | number | boolean {\n return (typeof raw === 'string' && raw !== '') || typeof raw === 'number' || typeof raw === 'boolean';\n}\n\n/**\n * The refinable facts one row offers: every metadata facet the row carries.\n * Columns the author bound to a metadata value lead, under their authored\n * labels; every other scalar facet follows under a label derived from its\n * key, so the dialog reaches the whole record, not only what the columns\n * show. Feeds the row's RefineDialog.\n */\nexport function rowRefinePairs(row: LTEscalationRecord, columnDefs: ColumnDef[]): RefinePair[] {\n const pairs: RefinePair[] = [];\n const seen = new Set<string>();\n const metadata = row.metadata ?? {};\n for (const col of columnDefs) {\n const bound = typeof col.value === 'string' ? col.value.match(METADATA_TOKEN)?.[1] : undefined;\n if (!bound || seen.has(bound)) continue;\n const raw = metadata[bound];\n if (!isFacetValue(raw)) continue;\n seen.add(bound);\n pairs.push({ key: bound, label: col.label, value: raw, bound: true });\n }\n for (const [key, raw] of Object.entries(metadata)) {\n if (seen.has(key) || !isFacetValue(raw)) continue;\n seen.add(key);\n pairs.push({ key, label: identifierToTitle(key), value: raw });\n }\n return pairs;\n}\n\n/** The always-tappable row/card refine trigger — one magnifier, dialog behind it. */\nexport function RefineTrigger({ onOpen, className = '' }: { onOpen: () => void; className?: string }) {\n return (\n <button\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); onOpen(); }}\n className={`p-1.5 rounded text-text-quaternary/70 hover:text-accent hover:bg-surface-hover transition-colors ${className}`}\n title=\"Refine — filter or search by this row's values\"\n aria-label=\"Refine — filter or search by this row's values\"\n data-testid=\"row-refine\"\n >\n <Search className=\"w-3.5 h-3.5\" strokeWidth={1.5} />\n </button>\n );\n}\n","/**\n * Related sets on a role's list schema. A set is named once under\n * `x-lt-related`; columns (`related`) and row details (`x-lt-row-detail`)\n * reference it by name. The server reads the declaration from the stored\n * list schema, never from the caller.\n *\n * items the host row's accumulated or batch items, each read through its\n * payload or its reciprocal row\n * query rows in other roles that share facets with the host row; facet\n * values are `{{domain.path}}` templates over the host row\n */\n\nexport const LIST_SCHEMA_KEYS = {\n RELATED: 'x-lt-related',\n COLUMNS: 'x-lt-columns',\n ROW_DETAIL: 'x-lt-row-detail',\n GROUP_BY: 'x-lt-group-by',\n LAYOUT: 'x-lt-layout',\n} as const;\n\nexport const RELATED_SOURCES = {\n ITEMS: 'items',\n QUERY: 'query',\n} as const;\nexport type RelatedSource = (typeof RELATED_SOURCES)[keyof typeof RELATED_SOURCES];\n\nexport const RELATED_AGGREGATES = {\n COUNT: 'count',\n /** The least item or row value: numbers as numbers, everything else as text. */\n MIN: 'min',\n MAX: 'max',\n} as const;\nexport type RelatedAggregate = (typeof RELATED_AGGREGATES)[keyof typeof RELATED_AGGREGATES];\n\n/** How a grouped table folds a plain column across a group's rows. */\nexport const GROUP_FOLDS = {\n FIRST: 'first',\n MIN: 'min',\n MAX: 'max',\n SUM: 'sum',\n COUNT: 'count',\n /** The distinct values, in row order, joined: \"standard, express\". */\n DISTINCT: 'distinct',\n} as const;\nexport type GroupFold = (typeof GROUP_FOLDS)[keyof typeof GROUP_FOLDS];\n\n/** Split prefixes. `role` splits a query set by the related row's role. */\nexport const SPLIT_PATHS = {\n ROLE: 'role',\n METADATA: 'metadata.',\n PAYLOAD: 'payload.',\n RECIPROCAL_METADATA: 'reciprocal.metadata.',\n} as const;\n\nexport const RELATED_LIMITS = {\n MAX_SETS: 4,\n MAX_QUERY_ROLES: 12,\n MAX_ROW_DETAIL_SECTIONS: 4,\n MAX_HOSTS: 100,\n ROWS_DEFAULT: 25,\n ROWS_MAX: 100,\n} as const;\n\n/** The table layout that renders related columns, row details, and groups. */\nexport const FACET_TABLE_LAYOUT = 'facet-table';\n\nexport interface RelatedQueryDecl {\n /** Related roles, in display order. Exclusive with `segment`. */\n roles?: string[];\n /** A Pace Board sequence by its first role; resolves to the ordered chain. */\n segment?: string;\n /** Facet containment; string values may be `{{domain.path}}` templates. */\n facets?: Record<string, unknown>;\n /**\n * Facets that narrow the match when the host row carries a value, and\n * drop away when it does not: a lane narrows its tub's look-ahead to its\n * own service level, a tub without lanes keeps the whole destination.\n */\n narrow?: Record<string, unknown>;\n /** Default `pending`. */\n status?: string;\n}\n\nexport interface RelatedSetDecl {\n source: RelatedSource;\n query?: RelatedQueryDecl;\n}\n\n/** A count column's text keyed by count; `default` covers the rest, `{n}` reads the count. */\nexport const RELATED_DISPLAY_DEFAULT = 'default';\n\nexport interface RelatedColumnDecl {\n label: string;\n related: string;\n aggregate?: RelatedAggregate;\n /** min/max: `{{item.payload.<path>}}` on an items set, `{{metadata.<key>}}` on a query set. */\n value?: string;\n /** min/max: how the value renders, as on any facet-table column. */\n format?: string;\n /** count: text by count, e.g. `{ \"0\": \"Ready\", \"default\": \"Waiting on {n}\" }`. */\n display?: Record<string, string>;\n splitBy?: string;\n labels?: Record<string, string>;\n priority?: 1 | 2 | 3;\n /** CSS width, as on any facet-table column. */\n width?: string;\n}\n\nexport interface RowDetailColumnDecl {\n label: string;\n value: string;\n format?: string;\n priority?: 1 | 2 | 3;\n}\n\nexport interface RowDetailSectionDecl {\n related: string;\n label?: string;\n columns: RowDetailColumnDecl[];\n limit?: number;\n}\n\n/** The validated, normalized related declaration of one list schema. */\nexport interface ListSchemaRelations {\n sets: Record<string, RelatedSetDecl>;\n columns: RelatedColumnDecl[];\n rowDetail: RowDetailSectionDecl[];\n /** The metadata key a facet-table groups by, when declared. */\n groupKey: string | null;\n}\n\n/** Per-host aggregate for one (set, splitBy) pair, or one (set, min/max, value) triple. */\nexport interface RelatedHostAggregate {\n count: number;\n /** min/max: the extreme value among `count` values; absent when none carries one. */\n value?: string | number;\n /** Split value to count; a null value is keyed by the empty string. */\n splits?: Record<string, number>;\n /** Items whose reciprocal row the viewer cannot read. */\n hidden?: number;\n /** A host whose facet templates resolved to nothing; the set did not run. */\n unresolved?: boolean;\n}\n\nexport interface RelatedSetResult {\n source: RelatedSource;\n /**\n * The roles whose rows the set reads, which a list follows for live\n * changes: a query set's resolved roles in order, or the roles of an item\n * set's readable reciprocal rows when a column splits by them.\n */\n roles?: string[];\n /** Query sets: role titles, keyed by role. */\n roleLabels?: Record<string, string>;\n /** Query sets: declared roles outside the viewer's full read scope. */\n restricted?: string[];\n /** Keyed by relatedAggregateKey (the splitBy, '' when unsplit, or `min:<path>`), then host id. */\n aggregates: Record<string, Record<string, RelatedHostAggregate>>;\n}\n\nexport interface RelatedAggregatesResponse {\n version: number | null;\n sets: Record<string, RelatedSetResult>;\n}\n\nexport interface RelatedItemEntry {\n itemKey: string;\n payload?: unknown;\n at?: string;\n actor?: string;\n reciprocalId?: string;\n}\n\nexport interface RelatedRow {\n /** Items sets only. */\n item?: RelatedItemEntry;\n /** The reciprocal row (items) or the related row (query); null when unreadable. */\n escalation: Record<string, unknown> | null;\n}\n\nexport interface RelatedRowsResponse {\n source: RelatedSource;\n rows: RelatedRow[];\n total: number;\n restricted?: string[];\n roleLabels?: Record<string, string>;\n}\n","import {\n RELATED_AGGREGATES,\n RELATED_DISPLAY_DEFAULT,\n RELATED_SOURCES,\n SPLIT_PATHS,\n type RelatedAggregate,\n type RelatedColumnDecl,\n} from './types';\n\nconst VALUE_TOKEN = /^\\{\\{\\s*([^{}]+?)\\s*\\}\\}$/;\nconst ITEM_PREFIX = 'item.';\nconst PATH_SEGMENT = /^[a-zA-Z0-9_]+$/;\nconst METADATA_KEY = /^[a-zA-Z0-9_]+$/;\nconst COUNT_TOKEN = /\\{n\\}/g;\n\nexport type RelatedExtreme = typeof RELATED_AGGREGATES.MIN | typeof RELATED_AGGREGATES.MAX;\n\n/** True for the aggregates that pick one value rather than count. */\nexport function isExtremeAggregate(aggregate: unknown): aggregate is RelatedExtreme {\n return aggregate === RELATED_AGGREGATES.MIN || aggregate === RELATED_AGGREGATES.MAX;\n}\n\n/**\n * The stored path a min/max `value` template reads: `payload.<path>` for an\n * items set, `metadata.<key>` for a query set. Null when the template does\n * not fit the set's source.\n */\nexport function relatedValuePath(source: string, value: unknown): string | null {\n if (typeof value !== 'string') return null;\n const token = value.match(VALUE_TOKEN)?.[1];\n if (!token) return null;\n if (source === RELATED_SOURCES.ITEMS) {\n if (!token.startsWith(`${ITEM_PREFIX}${SPLIT_PATHS.PAYLOAD}`)) return null;\n const path = token.slice(ITEM_PREFIX.length + SPLIT_PATHS.PAYLOAD.length);\n return path && path.split('.').every((s) => PATH_SEGMENT.test(s)) ? `${SPLIT_PATHS.PAYLOAD}${path}` : null;\n }\n if (!token.startsWith(SPLIT_PATHS.METADATA)) return null;\n const key = token.slice(SPLIT_PATHS.METADATA.length);\n return METADATA_KEY.test(key) ? token : null;\n}\n\n/** The key a column's per-host aggregates are stored under in its set's result. */\nexport function relatedAggregateKey(col: Pick<RelatedColumnDecl, 'aggregate' | 'splitBy' | 'value'>, source: string): string {\n if (isExtremeAggregate(col.aggregate)) return `${col.aggregate}:${relatedValuePath(source, col.value) ?? ''}`;\n return col.splitBy ?? '';\n}\n\n/** A count column's display text, or null when the column declares none for this count. */\nexport function relatedCountText(display: Record<string, string> | undefined, count: number): string | null {\n if (!display) return null;\n const text = display[String(count)] ?? display[RELATED_DISPLAY_DEFAULT];\n return text === undefined ? null : text.replace(COUNT_TOKEN, String(count));\n}\n\n/**\n * The least or greatest of several values: numbers when every value is a\n * number, otherwise text in code-unit order (ISO instants order as text).\n */\nexport function foldExtreme(fold: RelatedAggregate, values: Array<string | number>): string | number | undefined {\n if (!values.length) return undefined;\n const pickMin = fold === RELATED_AGGREGATES.MIN;\n if (values.every((v) => typeof v === 'number')) {\n return pickMin ? Math.min(...(values as number[])) : Math.max(...(values as number[]));\n }\n const texts = values.map(String).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n return pickMin ? texts[0] : texts[texts.length - 1];\n}\n","import {\n FACET_TABLE_LAYOUT,\n GROUP_FOLDS,\n LIST_SCHEMA_KEYS,\n RELATED_AGGREGATES,\n RELATED_DISPLAY_DEFAULT,\n RELATED_LIMITS,\n RELATED_SOURCES,\n SPLIT_PATHS,\n type ListSchemaRelations,\n type RelatedColumnDecl,\n type RelatedSetDecl,\n type RowDetailSectionDecl,\n} from './types';\nimport { isExtremeAggregate, relatedValuePath } from './aggregate';\n\n/** A metadata key: interpolated as a JSON path, so strictly validated. */\nexport const METADATA_KEY = /^[a-zA-Z0-9_]+$/;\nconst SET_NAME = /^[a-zA-Z][a-zA-Z0-9_-]{0,47}$/;\nconst PATH_SEGMENT = /^[a-zA-Z0-9_]+$/;\nconst COUNT_KEY = /^(0|[1-9][0-9]*)$/;\n\ntype Obj = Record<string, unknown>;\n\nclass ListSchemaError extends Error {}\n\nfunction fail(message: string): never {\n throw new ListSchemaError(message);\n}\n\nfunction isObj(value: unknown): value is Obj {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\n/** True when a dotted path has only plain segments. */\nfunction isPlainPath(path: string): boolean {\n return path.length > 0 && path.split('.').every((s) => PATH_SEGMENT.test(s));\n}\n\n/** The split paths a set's source accepts. */\nexport function splitPathError(source: string, splitBy: string): string | null {\n if (source === RELATED_SOURCES.QUERY) {\n if (splitBy === SPLIT_PATHS.ROLE) return null;\n if (splitBy.startsWith(SPLIT_PATHS.METADATA) && METADATA_KEY.test(splitBy.slice(SPLIT_PATHS.METADATA.length))) return null;\n return `splitBy \"${splitBy}\" on a query set must be \"role\" or \"metadata.<key>\"`;\n }\n if (splitBy.startsWith(SPLIT_PATHS.PAYLOAD) && isPlainPath(splitBy.slice(SPLIT_PATHS.PAYLOAD.length))) return null;\n if (splitBy.startsWith(SPLIT_PATHS.RECIPROCAL_METADATA)\n && METADATA_KEY.test(splitBy.slice(SPLIT_PATHS.RECIPROCAL_METADATA.length))) return null;\n return `splitBy \"${splitBy}\" on an items set must be \"payload.<path>\" or \"reciprocal.metadata.<key>\"`;\n}\n\nfunction readSet(name: string, raw: unknown): RelatedSetDecl {\n if (!SET_NAME.test(name)) fail(`x-lt-related name \"${name}\" must start with a letter (letters, digits, _ or -)`);\n if (!isObj(raw)) fail(`x-lt-related.${name} must be an object`);\n if (raw.source === RELATED_SOURCES.ITEMS) {\n if (raw.query !== undefined) fail(`x-lt-related.${name}: an items set takes no query`);\n return { source: RELATED_SOURCES.ITEMS };\n }\n if (raw.source !== RELATED_SOURCES.QUERY) fail(`x-lt-related.${name}.source must be \"items\" or \"query\"`);\n const q = raw.query;\n if (!isObj(q)) fail(`x-lt-related.${name}.query is required for a query set`);\n const hasRoles = q.roles !== undefined;\n const hasSegment = q.segment !== undefined;\n if (hasRoles === hasSegment) fail(`x-lt-related.${name}.query takes exactly one of roles or segment`);\n if (hasRoles) {\n const roles = q.roles;\n if (!Array.isArray(roles) || roles.length === 0 || roles.length > RELATED_LIMITS.MAX_QUERY_ROLES\n || !roles.every(isNonEmptyString)) {\n fail(`x-lt-related.${name}.query.roles must be 1..${RELATED_LIMITS.MAX_QUERY_ROLES} role names`);\n }\n } else if (!isNonEmptyString(q.segment)) {\n fail(`x-lt-related.${name}.query.segment must be a role name`);\n }\n if (!isObj(q.facets) || Object.keys(q.facets).length === 0) {\n fail(`x-lt-related.${name}.query.facets must name at least one facet`);\n }\n for (const [key, value] of Object.entries(q.facets)) {\n if (!METADATA_KEY.test(key)) fail(`x-lt-related.${name}.query.facets key \"${key}\" must be letters, digits or _`);\n if (value === null || typeof value === 'object') fail(`x-lt-related.${name}.query.facets.${key} must be a scalar or template`);\n }\n if (q.narrow !== undefined) {\n if (!isObj(q.narrow) || Object.keys(q.narrow).length === 0) fail(`x-lt-related.${name}.query.narrow must name at least one facet`);\n for (const [key, value] of Object.entries(q.narrow)) {\n if (!METADATA_KEY.test(key)) fail(`x-lt-related.${name}.query.narrow key \"${key}\" must be letters, digits or _`);\n if (key in q.facets) fail(`x-lt-related.${name}.query.narrow.${key} is already a required facet`);\n if (value === null || typeof value === 'object') fail(`x-lt-related.${name}.query.narrow.${key} must be a scalar or template`);\n }\n }\n if (q.status !== undefined && !isNonEmptyString(q.status)) fail(`x-lt-related.${name}.query.status must be a status`);\n return {\n source: RELATED_SOURCES.QUERY,\n query: {\n ...(hasRoles ? { roles: [...(q.roles as string[])] } : { segment: q.segment as string }),\n facets: { ...q.facets },\n ...(q.narrow !== undefined ? { narrow: { ...(q.narrow as Obj) } } : {}),\n ...(q.status !== undefined ? { status: q.status as string } : {}),\n },\n };\n}\n\nfunction readRelatedColumn(raw: Obj, sets: Record<string, RelatedSetDecl>, at: string): RelatedColumnDecl {\n const name = raw.related;\n if (!isNonEmptyString(name) || !sets[name]) fail(`${at}.related must name a set declared in x-lt-related`);\n if (raw.aggregate !== undefined && raw.aggregate !== RELATED_AGGREGATES.COUNT && !isExtremeAggregate(raw.aggregate)) {\n fail(`${at}.aggregate must be \"count\", \"min\" or \"max\"`);\n }\n const source = sets[name].source;\n if (isExtremeAggregate(raw.aggregate)) {\n if (!relatedValuePath(source, raw.value)) {\n fail(source === RELATED_SOURCES.ITEMS\n ? `${at}.value must be \"{{item.payload.<path>}}\" on an items set`\n : `${at}.value must be \"{{metadata.<key>}}\" on a query set`);\n }\n if (raw.splitBy !== undefined) fail(`${at}: a ${raw.aggregate} column takes no splitBy`);\n if (raw.display !== undefined) fail(`${at}: display applies to a count column`);\n } else if (raw.value !== undefined) {\n fail(`${at}.value applies to a min or max column`);\n }\n if (raw.format !== undefined && typeof raw.format !== 'string') fail(`${at}.format must be a format name`);\n if (raw.display !== undefined) {\n if (!isObj(raw.display) || Object.keys(raw.display).length === 0\n || !Object.entries(raw.display).every(([k, v]) => (k === RELATED_DISPLAY_DEFAULT || COUNT_KEY.test(k)) && typeof v === 'string')) {\n fail(`${at}.display must map counts (or \"default\") to display text`);\n }\n }\n if (raw.splitBy !== undefined) {\n if (!isNonEmptyString(raw.splitBy)) fail(`${at}.splitBy must be a path`);\n const err = splitPathError(sets[name].source, raw.splitBy);\n if (err) fail(`${at}: ${err}`);\n }\n if (raw.labels !== undefined && (!isObj(raw.labels) || !Object.values(raw.labels).every((v) => typeof v === 'string'))) {\n fail(`${at}.labels must map values to display text`);\n }\n return raw as unknown as RelatedColumnDecl;\n}\n\nfunction readRowDetail(raw: unknown, sets: Record<string, RelatedSetDecl>): RowDetailSectionDecl[] {\n if (raw === undefined) return [];\n if (!Array.isArray(raw) || raw.length === 0 || raw.length > RELATED_LIMITS.MAX_ROW_DETAIL_SECTIONS) {\n fail(`x-lt-row-detail must be 1..${RELATED_LIMITS.MAX_ROW_DETAIL_SECTIONS} sections`);\n }\n return raw.map((section, i) => {\n const at = `x-lt-row-detail[${i}]`;\n if (!isObj(section)) fail(`${at} must be an object`);\n if (!isNonEmptyString(section.related) || !sets[section.related]) fail(`${at}.related must name a set declared in x-lt-related`);\n if (!Array.isArray(section.columns) || section.columns.length === 0) fail(`${at}.columns must list at least one column`);\n for (const [j, col] of section.columns.entries()) {\n if (!isObj(col) || !isNonEmptyString(col.label) || typeof col.value !== 'string') {\n fail(`${at}.columns[${j}] needs a label and a value template`);\n }\n }\n if (section.limit !== undefined && (!Number.isInteger(section.limit) || (section.limit as number) < 1\n || (section.limit as number) > RELATED_LIMITS.ROWS_MAX)) {\n fail(`${at}.limit must be 1..${RELATED_LIMITS.ROWS_MAX}`);\n }\n return section as unknown as RowDetailSectionDecl;\n });\n}\n\nfunction readGroupKey(schema: Obj): string | null {\n const raw = schema[LIST_SCHEMA_KEYS.GROUP_BY];\n if (raw === undefined || schema[LIST_SCHEMA_KEYS.LAYOUT] !== FACET_TABLE_LAYOUT) return null;\n const key = typeof raw === 'string' && raw.startsWith(SPLIT_PATHS.METADATA) ? raw.slice(SPLIT_PATHS.METADATA.length) : '';\n if (!METADATA_KEY.test(key)) fail('x-lt-group-by on a facet-table must be \"metadata.<key>\"');\n return key;\n}\n\nconst FOLDS = new Set<string>(Object.values(GROUP_FOLDS));\n\n/**\n * Validate and normalize the related declaration of a list schema. Throws on\n * an invalid declaration; keys outside this vocabulary stay opaque.\n */\nexport function readListSchemaRelations(schema: unknown): ListSchemaRelations {\n const empty: ListSchemaRelations = { sets: {}, columns: [], rowDetail: [], groupKey: null };\n if (!isObj(schema)) return empty;\n const rawSets = schema[LIST_SCHEMA_KEYS.RELATED];\n const sets: Record<string, RelatedSetDecl> = {};\n if (rawSets !== undefined) {\n if (!isObj(rawSets)) fail('x-lt-related must map set names to declarations');\n const names = Object.keys(rawSets);\n if (names.length === 0 || names.length > RELATED_LIMITS.MAX_SETS) fail(`x-lt-related must declare 1..${RELATED_LIMITS.MAX_SETS} sets`);\n for (const name of names) sets[name] = readSet(name, rawSets[name]);\n }\n const columns: RelatedColumnDecl[] = [];\n const rawColumns = schema[LIST_SCHEMA_KEYS.COLUMNS];\n if (Array.isArray(rawColumns)) {\n rawColumns.forEach((col, i) => {\n if (!isObj(col)) return;\n if (col.related !== undefined) columns.push(readRelatedColumn(col, sets, `x-lt-columns[${i}]`));\n if (col.group !== undefined && (typeof col.group !== 'string' || !FOLDS.has(col.group))) {\n fail(`x-lt-columns[${i}].group must be one of ${[...FOLDS].join(', ')}`);\n }\n });\n }\n return { sets, columns, rowDetail: readRowDetail(schema[LIST_SCHEMA_KEYS.ROW_DETAIL], sets), groupKey: readGroupKey(schema) };\n}\n\n/** The declaration's first error, or null when valid. */\nexport function listSchemaRelationsError(schema: unknown): string | null {\n try {\n readListSchemaRelations(schema);\n return null;\n } catch (err) {\n if (err instanceof ListSchemaError) return err.message;\n throw err;\n }\n}\n"],"names":["isEffectivelyClaimed","esc","isAckEscalation","identifierToTitle","id","w","escalationDotClass","e","STATUS_DOT_STYLES","rowContext","parse","s","v","IDENTITY_COLUMN_WIDTH","actionColumnWidth","label","DEFAULT_CLAIM_MINUTES","isClaimable","row","RowActionButton","def","onView","prominent","forceView","authored","action","claim","useClaimEscalation","navigate","useNavigate","location","useLocation","error","setError","useState","spent","fire","err","classes","jsxs","jsx","METADATA_TOKEN","isFacetValue","raw","rowRefinePairs","columnDefs","pairs","seen","metadata","col","bound","_a","key","RefineTrigger","onOpen","className","Search","LIST_SCHEMA_KEYS","RELATED_SOURCES","RELATED_AGGREGATES","GROUP_FOLDS","SPLIT_PATHS","RELATED_LIMITS","FACET_TABLE_LAYOUT","RELATED_DISPLAY_DEFAULT","VALUE_TOKEN","ITEM_PREFIX","PATH_SEGMENT","METADATA_KEY","COUNT_TOKEN","isExtremeAggregate","aggregate","relatedValuePath","source","value","token","path","relatedAggregateKey","relatedCountText","display","count","text","foldExtreme","fold","values","pickMin","texts","a","b","SET_NAME","COUNT_KEY","ListSchemaError","fail","message","isObj","isNonEmptyString","isPlainPath","splitPathError","splitBy","readSet","name","q","hasRoles","hasSegment","roles","readRelatedColumn","sets","at","k","readRowDetail","section","i","j","readGroupKey","schema","FOLDS","readListSchemaRelations","empty","rawSets","names","columns","rawColumns"],"mappings":"iPAEO,SAASA,EAAqBC,EAAkC,CACrE,MAAO,CAAC,EACNA,EAAI,aACJA,EAAI,gBACJ,IAAI,KAAKA,EAAI,cAAc,EAAI,IAAI,KAEvC,CAGO,SAASC,GAAgBD,EAAkC,CAChE,MAAO,CAACA,EAAI,aACd,CCPO,SAASE,EAAkBC,EAAoB,CASpD,OARcA,EACX,QAAQ,WAAY,GAAG,EACvB,QAAQ,oBAAqB,OAAO,EACpC,QAAQ,wBAAyB,OAAO,EACxC,QAAQ,kBAAmB,OAAO,EAClC,OACA,MAAM,KAAK,EACX,OAAO,OAAO,EAEd,IAAKC,GAAOA,IAAMA,EAAE,eAAiBA,EAAE,OAAS,EAAIA,EAAIA,EAAE,OAAO,CAAC,EAAE,cAAgBA,EAAE,MAAM,CAAC,CAAE,EAC/F,KAAK,GAAG,CACb,CCFO,SAASC,GAAmBC,EAA+B,CAChE,OAAIA,EAAE,SAAW,UACRP,EAAqBO,CAAC,EAAI,4BAA8B,mBAE1DC,EAAkBD,EAAE,MAAM,GAAK,kBACxC,CA8CO,SAASE,GAAWF,EAAyC,CAClE,MAAMG,EAASC,GAAiE,CAC9E,GAAI,CAACA,EAAG,OAAO,KACf,GAAI,CACF,MAAMC,EAAI,KAAK,MAAMD,CAAC,EACtB,OAAOC,GAAK,OAAOA,GAAM,SAAWA,EAAI,IAC1C,MAAQ,CACN,OAAO,IACT,CACF,EACA,MAAO,CACL,WAAYL,EACZ,SAAUA,EAAE,UAAY,KACxB,SAAUG,EAAMH,EAAE,QAAQ,EAC1B,QAASG,EAAMH,EAAE,kBAAkB,EACnC,SAAUG,EAAMH,EAAE,gBAAgB,CAAA,CAEtC,CAGO,MAAMM,GAAwB,QAG9B,SAASC,GAAkBC,EAAuB,CACvD,MAAO,GAAG,KAAK,IAAI,EAAG,KAAK,MAAMA,EAAM,OAAS,IAAO,GAAG,CAAC,CAAC,KAC9D,CAEA,MAAMC,EAAwB,GAG9B,SAASC,EAAYC,EAAkC,CACrD,OAAOA,EAAI,SAAW,WAAa,CAAClB,EAAqBkB,CAAG,CAC9D,CAQO,SAASC,GAAgB,CAAE,IAAAD,EAAK,IAAAE,EAAK,OAAAC,EAAQ,UAAAC,EAAW,UAAAC,GAQ5D,CACD,MAAMC,GAAWJ,GAAA,YAAAA,EAAK,SAAU,QAC1BK,EAASF,EAAY,OAASC,EAG9BT,EAAQS,IAAaC,IAAUL,GAAA,MAAAA,EAAK,OACtCA,EAAI,MACJK,IAAW,QAAU,QAAU,OAC7BC,EAAQC,EAAA,EACRC,EAAWC,EAAA,EACXC,EAAWC,EAAA,EACX,CAACC,EAAOC,CAAQ,EAAIC,EAAAA,SAAS,EAAE,EAI/BC,EAAQV,IAAW,SAAW,CAACR,EAAYC,CAAG,EAE9CkB,EAAQ7B,GAAwB,CAEpC,GADAA,EAAE,gBAAA,EACEkB,IAAW,OAAQ,CACrBJ,GAAA,MAAAA,IACA,MACF,CAIA,GAAID,GAAA,MAAAA,EAAK,cAAe,CACtBQ,EAAS,uBAAuBV,EAAI,EAAE,GAAI,CACxC,MAAO,CAAE,UAAW,GAAM,gBAAiBE,GAAA,YAAAA,EAAK,gBAAiB,KAAMU,EAAS,QAAA,CAAS,CAC1F,EACD,MACF,CACAG,EAAS,EAAE,EACXP,EAAM,OACJ,CAAE,GAAIR,EAAI,GAAI,iBAAiBE,GAAA,YAAAA,EAAK,kBAAmBJ,CAAA,EACvD,CACE,UAAW,IAAMK,GAAA,YAAAA,IACjB,QAAUgB,GAAQJ,EAAUI,EAAc,OAAO,CAAA,CACnD,CAEJ,EAEMC,EAAUhB,EACZ,wGACA,yPAEJ,OACEiB,EAAAA,KAAC,OAAA,CAAK,UAAU,yCACd,SAAA,CAAAC,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASJ,EACT,SAAUV,EAAM,WAAaS,EAC7B,MAAOA,EAASjB,EAAI,SAAW,UAAY,UAAYA,EAAI,OAAU,OACrE,UAAWoB,EACX,cAAY,oBAEX,SAAAZ,EAAM,UAAY,YAAcX,CAAA,CAAA,EAElCiB,GAASQ,EAAAA,IAAC,OAAA,CAAK,UAAU,6BAA6B,cAAY,mBAAoB,SAAAR,CAAA,CAAM,CAAA,EAC/F,CAEJ,CAGO,MAAMS,EAAiB,4CAG9B,SAASC,EAAaC,EAAgD,CACpE,OAAQ,OAAOA,GAAQ,UAAYA,IAAQ,IAAO,OAAOA,GAAQ,UAAY,OAAOA,GAAQ,SAC9F,CASO,SAASC,GAAe1B,EAAyB2B,EAAuC,OAC7F,MAAMC,EAAsB,CAAA,EACtBC,MAAW,IACXC,EAAW9B,EAAI,UAAY,CAAA,EACjC,UAAW+B,KAAOJ,EAAY,CAC5B,MAAMK,EAAQ,OAAOD,EAAI,OAAU,UAAWE,EAAAF,EAAI,MAAM,MAAMR,CAAc,IAA9B,YAAAU,EAAkC,GAAK,OACrF,GAAI,CAACD,GAASH,EAAK,IAAIG,CAAK,EAAG,SAC/B,MAAMP,EAAMK,EAASE,CAAK,EACrBR,EAAaC,CAAG,IACrBI,EAAK,IAAIG,CAAK,EACdJ,EAAM,KAAK,CAAE,IAAKI,EAAO,MAAOD,EAAI,MAAO,MAAON,EAAK,MAAO,EAAA,CAAM,EACtE,CACA,SAAW,CAACS,EAAKT,CAAG,IAAK,OAAO,QAAQK,CAAQ,EAC1CD,EAAK,IAAIK,CAAG,GAAK,CAACV,EAAaC,CAAG,IACtCI,EAAK,IAAIK,CAAG,EACZN,EAAM,KAAK,CAAE,IAAAM,EAAK,MAAOjD,EAAkBiD,CAAG,EAAG,MAAOT,EAAK,GAE/D,OAAOG,CACT,CAGO,SAASO,GAAc,CAAE,OAAAC,EAAQ,UAAAC,EAAY,IAAkD,CACpG,OACEf,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAAU,GAAM,CAAE,EAAE,gBAAA,EAAmBc,EAAA,CAAU,EACjD,UAAW,oGAAoGC,CAAS,GACxH,MAAM,iDACN,aAAW,iDACX,cAAY,aAEZ,SAAAf,EAAAA,IAACgB,EAAA,CAAO,UAAU,cAAc,YAAa,GAAA,CAAK,CAAA,CAAA,CAGxD,CCvNO,MAAMC,EAAmB,CAC9B,QAAS,eACT,QAAS,eACT,WAAY,kBACZ,SAAU,gBACV,OAAQ,aACV,EAEaC,EAAkB,CAC7B,MAAO,QACP,MAAO,OACT,EAGaC,EAAqB,CAChC,MAAO,QAEP,IAAK,MACL,IAAK,KACP,EAIaC,EAAc,CACzB,MAAO,QACP,IAAK,MACL,IAAK,MACL,IAAK,MACL,MAAO,QAEP,SAAU,UACZ,EAIaC,EAAc,CACzB,KAAM,OACN,SAAU,YACV,QAAS,WACT,oBAAqB,sBACvB,EAEaC,EAAiB,CAC5B,SAAU,EACV,gBAAiB,GACjB,wBAAyB,EAGzB,SAAU,GACZ,EAGaC,EAAqB,cAyBrBC,EAA0B,UChFjCC,EAAc,4BACdC,EAAc,QACdC,EAAe,kBACfC,EAAe,kBACfC,EAAc,SAKb,SAASC,EAAmBC,EAAiD,CAClF,OAAOA,IAAcZ,EAAmB,KAAOY,IAAcZ,EAAmB,GAClF,CAOO,SAASa,EAAiBC,EAAgBC,EAA+B,OAC9E,GAAI,OAAOA,GAAU,SAAU,OAAO,KACtC,MAAMC,GAAQxB,EAAAuB,EAAM,MAAMT,CAAW,IAAvB,YAAAd,EAA2B,GACzC,GAAI,CAACwB,EAAO,OAAO,KACnB,GAAIF,IAAWf,EAAgB,MAAO,CACpC,GAAI,CAACiB,EAAM,WAAW,GAAGT,CAAW,GAAGL,EAAY,OAAO,EAAE,EAAG,OAAO,KACtE,MAAMe,EAAOD,EAAM,MAAMT,EAAY,OAASL,EAAY,QAAQ,MAAM,EACxE,OAAOe,GAAQA,EAAK,MAAM,GAAG,EAAE,MAAOjE,GAAMwD,EAAa,KAAKxD,CAAC,CAAC,EAAI,GAAGkD,EAAY,OAAO,GAAGe,CAAI,GAAK,IACxG,CACA,GAAI,CAACD,EAAM,WAAWd,EAAY,QAAQ,EAAG,OAAO,KACpD,MAAMT,EAAMuB,EAAM,MAAMd,EAAY,SAAS,MAAM,EACnD,OAAOO,EAAa,KAAKhB,CAAG,EAAIuB,EAAQ,IAC1C,CAGO,SAASE,GAAoB5B,EAAiEwB,EAAwB,CAC3H,OAAIH,EAAmBrB,EAAI,SAAS,EAAU,GAAGA,EAAI,SAAS,IAAIuB,EAAiBC,EAAQxB,EAAI,KAAK,GAAK,EAAE,GACpGA,EAAI,SAAW,EACxB,CAGO,SAAS6B,GAAiBC,EAA6CC,EAA8B,CAC1G,GAAI,CAACD,EAAS,OAAO,KACrB,MAAME,EAAOF,EAAQ,OAAOC,CAAK,CAAC,GAAKD,EAAQf,CAAuB,EACtE,OAAOiB,IAAS,OAAY,KAAOA,EAAK,QAAQZ,EAAa,OAAOW,CAAK,CAAC,CAC5E,CAMO,SAASE,GAAYC,EAAwBC,EAA6D,CAC/G,GAAI,CAACA,EAAO,OAAQ,OACpB,MAAMC,EAAUF,IAASxB,EAAmB,IAC5C,GAAIyB,EAAO,MAAOxE,GAAM,OAAOA,GAAM,QAAQ,EAC3C,OAAOyE,EAAU,KAAK,IAAI,GAAID,CAAmB,EAAI,KAAK,IAAI,GAAIA,CAAmB,EAEvF,MAAME,EAAQF,EAAO,IAAI,MAAM,EAAE,KAAK,CAACG,EAAGC,IAAOD,EAAIC,EAAI,GAAKD,EAAIC,EAAI,EAAI,CAAE,EAC5E,OAAOH,EAAUC,EAAM,CAAC,EAAIA,EAAMA,EAAM,OAAS,CAAC,CACpD,CCjDO,MAAMlB,EAAe,kBACtBqB,EAAW,gCACXtB,EAAe,kBACfuB,EAAY,oBAIlB,MAAMC,WAAwB,KAAM,CAAC,CAErC,SAASC,EAAKC,EAAwB,CACpC,MAAM,IAAIF,GAAgBE,CAAO,CACnC,CAEA,SAASC,EAAMpB,EAA8B,CAC3C,MAAO,CAAC,CAACA,GAAS,OAAOA,GAAU,UAAY,CAAC,MAAM,QAAQA,CAAK,CACrE,CAEA,SAASqB,EAAiBrB,EAAiC,CACzD,OAAO,OAAOA,GAAU,UAAYA,EAAM,KAAA,EAAO,OAAS,CAC5D,CAGA,SAASsB,GAAYpB,EAAuB,CAC1C,OAAOA,EAAK,OAAS,GAAKA,EAAK,MAAM,GAAG,EAAE,MAAO,GAAMT,EAAa,KAAK,CAAC,CAAC,CAC7E,CAGO,SAAS8B,GAAexB,EAAgByB,EAAgC,CAC7E,OAAIzB,IAAWf,EAAgB,MACzBwC,IAAYrC,EAAY,MACxBqC,EAAQ,WAAWrC,EAAY,QAAQ,GAAKO,EAAa,KAAK8B,EAAQ,MAAMrC,EAAY,SAAS,MAAM,CAAC,EAAU,KAC/G,YAAYqC,CAAO,sDAExBA,EAAQ,WAAWrC,EAAY,OAAO,GAAKmC,GAAYE,EAAQ,MAAMrC,EAAY,QAAQ,MAAM,CAAC,GAChGqC,EAAQ,WAAWrC,EAAY,mBAAmB,GACjDO,EAAa,KAAK8B,EAAQ,MAAMrC,EAAY,oBAAoB,MAAM,CAAC,EAAU,KAC/E,YAAYqC,CAAO,2EAC5B,CAEA,SAASC,GAAQC,EAAczD,EAA8B,CAG3D,GAFK8C,EAAS,KAAKW,CAAI,GAAGR,EAAK,sBAAsBQ,CAAI,sDAAsD,EAC1GN,EAAMnD,CAAG,GAAGiD,EAAK,gBAAgBQ,CAAI,oBAAoB,EAC1DzD,EAAI,SAAWe,EAAgB,MACjC,OAAIf,EAAI,QAAU,QAAWiD,EAAK,gBAAgBQ,CAAI,+BAA+B,EAC9E,CAAE,OAAQ1C,EAAgB,KAAA,EAE/Bf,EAAI,SAAWe,EAAgB,OAAOkC,EAAK,gBAAgBQ,CAAI,oCAAoC,EACvG,MAAMC,EAAI1D,EAAI,MACTmD,EAAMO,CAAC,GAAGT,EAAK,gBAAgBQ,CAAI,oCAAoC,EAC5E,MAAME,EAAWD,EAAE,QAAU,OACvBE,EAAaF,EAAE,UAAY,OAEjC,GADIC,IAAaC,GAAYX,EAAK,gBAAgBQ,CAAI,8CAA8C,EAChGE,EAAU,CACZ,MAAME,EAAQH,EAAE,OACZ,CAAC,MAAM,QAAQG,CAAK,GAAKA,EAAM,SAAW,GAAKA,EAAM,OAAS1C,EAAe,iBAC5E,CAAC0C,EAAM,MAAMT,CAAgB,IAChCH,EAAK,gBAAgBQ,CAAI,2BAA2BtC,EAAe,eAAe,aAAa,CAEnG,MAAYiC,EAAiBM,EAAE,OAAO,GACpCT,EAAK,gBAAgBQ,CAAI,oCAAoC,GAE3D,CAACN,EAAMO,EAAE,MAAM,GAAK,OAAO,KAAKA,EAAE,MAAM,EAAE,SAAW,IACvDT,EAAK,gBAAgBQ,CAAI,4CAA4C,EAEvE,SAAW,CAAChD,EAAKsB,CAAK,IAAK,OAAO,QAAQ2B,EAAE,MAAM,EAC3CjC,EAAa,KAAKhB,CAAG,KAAQ,gBAAgBgD,CAAI,sBAAsBhD,CAAG,gCAAgC,GAC3GsB,IAAU,MAAQ,OAAOA,GAAU,aAAe,gBAAgB0B,CAAI,iBAAiBhD,CAAG,+BAA+B,EAE/H,GAAIiD,EAAE,SAAW,OAAW,EACtB,CAACP,EAAMO,EAAE,MAAM,GAAK,OAAO,KAAKA,EAAE,MAAM,EAAE,SAAW,IAAGT,EAAK,gBAAgBQ,CAAI,4CAA4C,EACjI,SAAW,CAAChD,EAAKsB,CAAK,IAAK,OAAO,QAAQ2B,EAAE,MAAM,EAC3CjC,EAAa,KAAKhB,CAAG,KAAQ,gBAAgBgD,CAAI,sBAAsBhD,CAAG,gCAAgC,EAC3GA,KAAOiD,EAAE,QAAQT,EAAK,gBAAgBQ,CAAI,iBAAiBhD,CAAG,8BAA8B,GAC5FsB,IAAU,MAAQ,OAAOA,GAAU,aAAe,gBAAgB0B,CAAI,iBAAiBhD,CAAG,+BAA+B,CAEjI,CACA,OAAIiD,EAAE,SAAW,QAAa,CAACN,EAAiBM,EAAE,MAAM,GAAGT,EAAK,gBAAgBQ,CAAI,gCAAgC,EAC7G,CACL,OAAQ1C,EAAgB,MACxB,MAAO,CACL,GAAI4C,EAAW,CAAE,MAAO,CAAC,GAAID,EAAE,KAAkB,CAAA,EAAM,CAAE,QAASA,EAAE,OAAA,EACpE,OAAQ,CAAE,GAAGA,EAAE,MAAA,EACf,GAAIA,EAAE,SAAW,OAAY,CAAE,OAAQ,CAAE,GAAIA,EAAE,MAAA,CAAe,EAAM,CAAA,EACpE,GAAIA,EAAE,SAAW,OAAY,CAAE,OAAQA,EAAE,QAAqB,CAAA,CAAC,CACjE,CAEJ,CAEA,SAASI,GAAkB9D,EAAU+D,EAAsCC,EAA+B,CACxG,MAAMP,EAAOzD,EAAI,SACb,CAACoD,EAAiBK,CAAI,GAAK,CAACM,EAAKN,CAAI,IAAGR,EAAK,GAAGe,CAAE,mDAAmD,EACrGhE,EAAI,YAAc,QAAaA,EAAI,YAAcgB,EAAmB,OAAS,CAACW,EAAmB3B,EAAI,SAAS,GAChHiD,EAAK,GAAGe,CAAE,4CAA4C,EAExD,MAAMlC,EAASiC,EAAKN,CAAI,EAAE,OAmB1B,GAlBI9B,EAAmB3B,EAAI,SAAS,GAC7B6B,EAAiBC,EAAQ9B,EAAI,KAAK,GACrCiD,EAAKnB,IAAWf,EAAgB,MAC5B,GAAGiD,CAAE,2DACL,GAAGA,CAAE,oDAAoD,EAE3DhE,EAAI,UAAY,QAAWiD,EAAK,GAAGe,CAAE,OAAOhE,EAAI,SAAS,0BAA0B,EACnFA,EAAI,UAAY,QAAWiD,EAAK,GAAGe,CAAE,qCAAqC,GACrEhE,EAAI,QAAU,QACvBiD,EAAK,GAAGe,CAAE,uCAAuC,EAE/ChE,EAAI,SAAW,QAAa,OAAOA,EAAI,QAAW,UAAUiD,EAAK,GAAGe,CAAE,+BAA+B,EACrGhE,EAAI,UAAY,SACd,CAACmD,EAAMnD,EAAI,OAAO,GAAK,OAAO,KAAKA,EAAI,OAAO,EAAE,SAAW,GAC1D,CAAC,OAAO,QAAQA,EAAI,OAAO,EAAE,MAAM,CAAC,CAACiE,EAAGhG,CAAC,KAAOgG,IAAM5C,GAA2B0B,EAAU,KAAKkB,CAAC,IAAM,OAAOhG,GAAM,QAAQ,IAC/HgF,EAAK,GAAGe,CAAE,yDAAyD,EAGnEhE,EAAI,UAAY,OAAW,CACxBoD,EAAiBpD,EAAI,OAAO,GAAGiD,EAAK,GAAGe,CAAE,yBAAyB,EACvE,MAAMtE,EAAM4D,GAAeS,EAAKN,CAAI,EAAE,OAAQzD,EAAI,OAAO,EACrDN,GAAKuD,EAAK,GAAGe,CAAE,KAAKtE,CAAG,EAAE,CAC/B,CACA,OAAIM,EAAI,SAAW,SAAc,CAACmD,EAAMnD,EAAI,MAAM,GAAK,CAAC,OAAO,OAAOA,EAAI,MAAM,EAAE,MAAO/B,GAAM,OAAOA,GAAM,QAAQ,IAClHgF,EAAK,GAAGe,CAAE,yCAAyC,EAE9ChE,CACT,CAEA,SAASkE,GAAclE,EAAc+D,EAA8D,CACjG,OAAI/D,IAAQ,OAAkB,CAAA,IAC1B,CAAC,MAAM,QAAQA,CAAG,GAAKA,EAAI,SAAW,GAAKA,EAAI,OAASmB,EAAe,0BACzE8B,EAAK,8BAA8B9B,EAAe,uBAAuB,WAAW,EAE/EnB,EAAI,IAAI,CAACmE,EAASC,IAAM,CAC7B,MAAMJ,EAAK,mBAAmBI,CAAC,IAC1BjB,EAAMgB,CAAO,GAAGlB,EAAK,GAAGe,CAAE,oBAAoB,GAC/C,CAACZ,EAAiBe,EAAQ,OAAO,GAAK,CAACJ,EAAKI,EAAQ,OAAO,IAAGlB,EAAK,GAAGe,CAAE,mDAAmD,GAC3H,CAAC,MAAM,QAAQG,EAAQ,OAAO,GAAKA,EAAQ,QAAQ,SAAW,IAAGlB,EAAK,GAAGe,CAAE,wCAAwC,EACvH,SAAW,CAACK,EAAG/D,CAAG,IAAK6D,EAAQ,QAAQ,WACjC,CAAChB,EAAM7C,CAAG,GAAK,CAAC8C,EAAiB9C,EAAI,KAAK,GAAK,OAAOA,EAAI,OAAU,WACtE2C,EAAK,GAAGe,CAAE,YAAYK,CAAC,sCAAsC,EAGjE,OAAIF,EAAQ,QAAU,SAAc,CAAC,OAAO,UAAUA,EAAQ,KAAK,GAAMA,EAAQ,MAAmB,GAC9FA,EAAQ,MAAmBhD,EAAe,WAC9C8B,EAAK,GAAGe,CAAE,qBAAqB7C,EAAe,QAAQ,EAAE,EAEnDgD,CACT,CAAC,EACH,CAEA,SAASG,GAAaC,EAA4B,CAChD,MAAMvE,EAAMuE,EAAOzD,EAAiB,QAAQ,EAC5C,GAAId,IAAQ,QAAauE,EAAOzD,EAAiB,MAAM,IAAMM,EAAoB,OAAO,KACxF,MAAMX,EAAM,OAAOT,GAAQ,UAAYA,EAAI,WAAWkB,EAAY,QAAQ,EAAIlB,EAAI,MAAMkB,EAAY,SAAS,MAAM,EAAI,GACvH,OAAKO,EAAa,KAAKhB,CAAG,KAAQ,yDAAyD,EACpFA,CACT,CAEA,MAAM+D,EAAQ,IAAI,IAAY,OAAO,OAAOvD,CAAW,CAAC,EAMjD,SAASwD,GAAwBF,EAAsC,CAC5E,MAAMG,EAA6B,CAAE,KAAM,GAAI,QAAS,CAAA,EAAI,UAAW,CAAA,EAAI,SAAU,IAAA,EACrF,GAAI,CAACvB,EAAMoB,CAAM,EAAG,OAAOG,EAC3B,MAAMC,EAAUJ,EAAOzD,EAAiB,OAAO,EACzCiD,EAAuC,CAAA,EAC7C,GAAIY,IAAY,OAAW,CACpBxB,EAAMwB,CAAO,KAAQ,iDAAiD,EAC3E,MAAMC,EAAQ,OAAO,KAAKD,CAAO,GAC7BC,EAAM,SAAW,GAAKA,EAAM,OAASzD,EAAe,WAAU8B,EAAK,gCAAgC9B,EAAe,QAAQ,OAAO,EACrI,UAAWsC,KAAQmB,EAAOb,EAAKN,CAAI,EAAID,GAAQC,EAAMkB,EAAQlB,CAAI,CAAC,CACpE,CACA,MAAMoB,EAA+B,CAAA,EAC/BC,EAAaP,EAAOzD,EAAiB,OAAO,EAClD,OAAI,MAAM,QAAQgE,CAAU,GAC1BA,EAAW,QAAQ,CAACxE,EAAK8D,IAAM,CACxBjB,EAAM7C,CAAG,IACVA,EAAI,UAAY,QAAWuE,EAAQ,KAAKf,GAAkBxD,EAAKyD,EAAM,gBAAgBK,CAAC,GAAG,CAAC,EAC1F9D,EAAI,QAAU,SAAc,OAAOA,EAAI,OAAU,UAAY,CAACkE,EAAM,IAAIlE,EAAI,KAAK,IACnF2C,EAAK,gBAAgBmB,CAAC,0BAA0B,CAAC,GAAGI,CAAK,EAAE,KAAK,IAAI,CAAC,EAAE,EAE3E,CAAC,EAEI,CAAE,KAAAT,EAAM,QAAAc,EAAS,UAAWX,GAAcK,EAAOzD,EAAiB,UAAU,EAAGiD,CAAI,EAAG,SAAUO,GAAaC,CAAM,CAAA,CAC5H"}
1
+ {"version":3,"file":"validate-CAin6WM_.js","sources":["../../src/lib/escalation.ts","../../src/lib/identifier-label.ts","../../src/components/escalation/list-view/row-parts.tsx","../../../shared/list-schema/types.ts","../../../shared/list-schema/aggregate.ts","../../../shared/list-schema/validate.ts"],"sourcesContent":["import type { LTEscalationRecord } from '../api/types';\n\nexport function isEffectivelyClaimed(esc: LTEscalationRecord): boolean {\n return !!(\n esc.assigned_to &&\n esc.assigned_until &&\n new Date(esc.assigned_until) > new Date()\n );\n}\n\n/** An ACK escalation has no associated workflow — it's a notification, not a task. */\nexport function isAckEscalation(esc: LTEscalationRecord): boolean {\n return !esc.workflow_type;\n}\n\nexport function isAvailable(esc: LTEscalationRecord): boolean {\n return (\n esc.status === 'pending' &&\n (!esc.assigned_to ||\n !esc.assigned_until ||\n new Date(esc.assigned_until) <= new Date())\n );\n}\n","/**\n * A human label for a code identifier: camelCase, snake_case, kebab-case, and\n * digit runs become Title Case words. `fleetTools` → `Fleet Tools`,\n * `print_order2` → `Print Order 2`. Acronyms keep their capitals: `mcpQuery`\n * → `Mcp Query` is avoided by treating an all-caps run as one word.\n */\nexport function identifierToTitle(id: string): string {\n const words = id\n .replace(/[_\\-.]+/g, ' ')\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/([a-zA-Z])(\\d)/g, '$1 $2')\n .trim()\n .split(/\\s+/)\n .filter(Boolean);\n return words\n .map((w) => (w === w.toUpperCase() && w.length > 1 ? w : w.charAt(0).toUpperCase() + w.slice(1)))\n .join(' ');\n}\n","import { useState } from 'react';\nimport { useNavigate, useLocation } from 'react-router-dom';\nimport { Search } from 'lucide-react';\nimport type { HelpTokenContext } from '../../../lib/x-lt-help';\nimport { STATUS_DOT_STYLES } from '../../common/display/StatusBadge';\nimport { useClaimEscalation } from '../../../api/escalations';\nimport { isEffectivelyClaimed } from '../../../lib/escalation';\nimport { identifierToTitle } from '../../../lib/identifier-label';\nimport type { RefinePair } from '../RefineDialog';\nimport type { LTEscalationRecord } from '../../../api/types';\n\n/** The row-level pieces every list layout shares: column and action\n * declarations, the row's token context, the row action, and refine. */\n\n/** Dot colour matches the standard table view: blue = pending unclaimed,\n * orange = under a live claim; other statuses follow the shared map. */\nexport function escalationDotClass(e: LTEscalationRecord): string {\n if (e.status === 'pending') {\n return isEffectivelyClaimed(e) ? 'bg-status-claimed-graphic' : 'bg-status-active';\n }\n return STATUS_DOT_STYLES[e.status] ?? 'bg-status-active';\n}\n\nexport interface ColumnDef {\n label: string;\n value: string;\n /** \"age\" renders an ISO timestamp as a compact age with an absolute tooltip. */\n format?: string;\n /**\n * Card-fold behavior when the table folds at narrow widths (same contract\n * as the engineer table): 1 = identity — always visible, forms the card's\n * title line; 2 = folds into the card body as a label/value pair; 3 =\n * dropped in card mode. Undeclared, the first column is the identity and\n * the rest fold.\n */\n priority?: 1 | 2 | 3;\n /** CSS column width (\"40%\", \"12rem\"). Unset columns share the remainder;\n * when no column declares one, the first column holds a fixed 200px so\n * the identity stays legible and every other value keeps its room. */\n width?: string;\n}\n\n/**\n * The per-row action button — the queue-working gesture, always available on\n * every layout. Template-driven: the schema author sets the action, its text,\n * and (for claim) the hold time.\n */\nexport interface RowActionDef {\n /** \"claim\" fires a one-click claim then opens the detail page already\n * claimed; \"view\" just opens it. Default \"claim\". */\n action?: 'claim' | 'view';\n /** Button text. Defaults \"Claim\" / \"View\" by action. */\n label?: string;\n /** Claim hold time in minutes. Default 30 (the platform claim default). */\n durationMinutes?: number;\n /**\n * Launch the detail page's claim-and-submit flow instead of a plain claim:\n * the row is claimed, the form's seeded defaults are resolved, and — when the\n * form declares `x-lt-transition` — the wait screen bridges to the born-assigned\n * follow-on. One list gesture (\"Start Harvesting\") starts the work and lands\n * the person on the next step. The behavior lives on the detail page (form\n * defaults, validation, transition); the list only points there with intent.\n */\n submitOnClaim?: boolean;\n}\n\n/** Build the token context for one escalation row (payloads are JSON strings). */\nexport function rowContext(e: LTEscalationRecord): HelpTokenContext {\n const parse = (s: string | null | undefined): Record<string, unknown> | null => {\n if (!s) return null;\n try {\n const v = JSON.parse(s);\n return v && typeof v === 'object' ? v : null;\n } catch {\n return null;\n }\n };\n return {\n escalation: e as unknown as Record<string, unknown>,\n metadata: e.metadata ?? null,\n envelope: parse(e.envelope),\n payload: parse(e.escalation_payload),\n resolver: parse(e.resolver_payload),\n };\n}\n\n/** The identity column's width when no column declares one: room for a label, no more. */\nexport const IDENTITY_COLUMN_WIDTH = '200px';\n\n/** The action column sizes to its label so the button never wraps or truncates. */\nexport function actionColumnWidth(label: string): string {\n return `${Math.max(6, Math.round(label.length * 0.55 + 3.5))}rem`;\n}\n\nconst DEFAULT_CLAIM_MINUTES = 30;\n\n/** Claim targets pending rows without a live claim window. */\nfunction isClaimable(row: LTEscalationRecord): boolean {\n return row.status === 'pending' && !isEffectivelyClaimed(row);\n}\n\n/**\n * The x-lt-row-action button. `claim` is one click: claim for the template's\n * duration, then open the detail page already claimed — the fast path for\n * working a queue. `view` opens the detail page. Persistent (light accent at\n * rest, saturating on hover); a rejected claim surfaces its message inline.\n */\nexport function RowActionButton({ row, def, onView, prominent, forceView }: {\n row: LTEscalationRecord;\n def?: RowActionDef;\n onView?: () => void;\n /** Hero treatment for the active-card CTA; default is the compact row button. */\n prominent?: boolean;\n /** Render claim templates as view actions (see EscalationListView). */\n forceView?: boolean;\n}) {\n const authored = def?.action ?? 'claim';\n const action = forceView ? 'view' : authored;\n // The authored label describes the authored gesture. When view is forced\n // over a claim template, claim wording would mislead — use the view default.\n const label = authored === action && def?.label\n ? def.label\n : action === 'claim' ? 'Claim' : 'View';\n const claim = useClaimEscalation();\n const navigate = useNavigate();\n const location = useLocation();\n const [error, setError] = useState('');\n\n // A spent gesture stays visible — the disabled button keeps every row's\n // layout uniform instead of leaving a hole on resolved/held rows.\n const spent = action === 'claim' && !isClaimable(row);\n\n const fire = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (action === 'view') {\n onView?.();\n return;\n }\n // Launch the detail page's claim → submit → transition flow. The detail\n // page owns the heavy lifting (seed defaults, validate, resolve, hand-off);\n // the list points there with the intent and the authored claim duration.\n if (def?.submitOnClaim) {\n navigate(`/escalations/detail/${row.id}`, {\n state: { autoStart: true, durationMinutes: def?.durationMinutes, from: location.pathname },\n });\n return;\n }\n setError('');\n claim.mutate(\n { id: row.id, durationMinutes: def?.durationMinutes ?? DEFAULT_CLAIM_MINUTES },\n {\n onSuccess: () => onView?.(),\n onError: (err) => setError((err as Error).message),\n },\n );\n };\n\n const classes = prominent\n ? 'btn-primary text-xs shrink-0 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-accent'\n : 'px-2 py-0.5 rounded text-2xs font-medium text-accent/70 border border-accent/30 enabled:hover:text-accent enabled:hover:border-accent/60 enabled:hover:bg-accent/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap';\n\n return (\n <span className=\"inline-flex flex-col items-end gap-0.5\">\n <button\n type=\"button\"\n onClick={fire}\n disabled={claim.isPending || spent}\n title={spent ? (row.status === 'pending' ? 'claimed' : row.status) : undefined}\n className={classes}\n data-testid=\"row-action-button\"\n >\n {claim.isPending ? 'Claiming…' : label}\n </button>\n {error && <span className=\"text-2xs text-status-error\" data-testid=\"row-action-error\">{error}</span>}\n </span>\n );\n}\n\n/** A field value token that is a pure metadata binding — facet-linkable. */\nexport const METADATA_TOKEN = /^\\{\\{\\s*metadata\\.([a-zA-Z0-9_]+)\\s*\\}\\}$/;\n\n/** A metadata value the faceted query can match on: a scalar with something in it. */\nfunction isFacetValue(raw: unknown): raw is string | number | boolean {\n return (typeof raw === 'string' && raw !== '') || typeof raw === 'number' || typeof raw === 'boolean';\n}\n\n/**\n * The refinable facts one row offers: every metadata facet the row carries.\n * Columns the author bound to a metadata value lead, under their authored\n * labels; every other scalar facet follows under a label derived from its\n * key, so the dialog reaches the whole record, not only what the columns\n * show. Feeds the row's RefineDialog.\n */\nexport function rowRefinePairs(row: LTEscalationRecord, columnDefs: ColumnDef[]): RefinePair[] {\n const pairs: RefinePair[] = [];\n const seen = new Set<string>();\n const metadata = row.metadata ?? {};\n for (const col of columnDefs) {\n const bound = typeof col.value === 'string' ? col.value.match(METADATA_TOKEN)?.[1] : undefined;\n if (!bound || seen.has(bound)) continue;\n const raw = metadata[bound];\n if (!isFacetValue(raw)) continue;\n seen.add(bound);\n pairs.push({ key: bound, label: col.label, value: raw, bound: true });\n }\n for (const [key, raw] of Object.entries(metadata)) {\n if (seen.has(key) || !isFacetValue(raw)) continue;\n seen.add(key);\n pairs.push({ key, label: identifierToTitle(key), value: raw });\n }\n return pairs;\n}\n\n/** The always-tappable row/card refine trigger — one magnifier, dialog behind it. */\nexport function RefineTrigger({ onOpen, className = '' }: { onOpen: () => void; className?: string }) {\n return (\n <button\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); onOpen(); }}\n className={`p-1.5 rounded text-text-quaternary/70 hover:text-accent hover:bg-surface-hover transition-colors ${className}`}\n title=\"Refine — filter or search by this row's values\"\n aria-label=\"Refine — filter or search by this row's values\"\n data-testid=\"row-refine\"\n >\n <Search className=\"w-3.5 h-3.5\" strokeWidth={1.5} />\n </button>\n );\n}\n","/**\n * Related sets on a role's list schema. A set is named once under\n * `x-lt-related`; columns (`related`) and row details (`x-lt-row-detail`)\n * reference it by name. The server reads the declaration from the stored\n * list schema, never from the caller.\n *\n * items the host row's accumulated or batch items, each read through its\n * payload or its reciprocal row\n * query rows in other roles that share facets with the host row; facet\n * values are `{{domain.path}}` templates over the host row\n */\n\nexport const LIST_SCHEMA_KEYS = {\n RELATED: 'x-lt-related',\n COLUMNS: 'x-lt-columns',\n ROW_DETAIL: 'x-lt-row-detail',\n GROUP_BY: 'x-lt-group-by',\n LAYOUT: 'x-lt-layout',\n} as const;\n\nexport const RELATED_SOURCES = {\n ITEMS: 'items',\n QUERY: 'query',\n} as const;\nexport type RelatedSource = (typeof RELATED_SOURCES)[keyof typeof RELATED_SOURCES];\n\nexport const RELATED_AGGREGATES = {\n COUNT: 'count',\n /** The least item or row value: numbers as numbers, everything else as text. */\n MIN: 'min',\n MAX: 'max',\n} as const;\nexport type RelatedAggregate = (typeof RELATED_AGGREGATES)[keyof typeof RELATED_AGGREGATES];\n\n/** How a grouped table folds a plain column across a group's rows. */\nexport const GROUP_FOLDS = {\n FIRST: 'first',\n MIN: 'min',\n MAX: 'max',\n SUM: 'sum',\n COUNT: 'count',\n /** The distinct values, in row order, joined: \"standard, express\". */\n DISTINCT: 'distinct',\n} as const;\nexport type GroupFold = (typeof GROUP_FOLDS)[keyof typeof GROUP_FOLDS];\n\n/** Split prefixes. `role` splits a query set by the related row's role. */\nexport const SPLIT_PATHS = {\n ROLE: 'role',\n METADATA: 'metadata.',\n PAYLOAD: 'payload.',\n RECIPROCAL_METADATA: 'reciprocal.metadata.',\n} as const;\n\nexport const RELATED_LIMITS = {\n MAX_SETS: 4,\n MAX_QUERY_ROLES: 12,\n MAX_ROW_DETAIL_SECTIONS: 4,\n MAX_HOSTS: 100,\n ROWS_DEFAULT: 25,\n ROWS_MAX: 100,\n} as const;\n\n/** The table layout that renders related columns, row details, and groups. */\nexport const FACET_TABLE_LAYOUT = 'facet-table';\n\nexport interface RelatedQueryDecl {\n /** Related roles, in display order. Exclusive with `segment`. */\n roles?: string[];\n /** A Pace Board sequence by its first role; resolves to the ordered chain. */\n segment?: string;\n /** Facet containment; string values may be `{{domain.path}}` templates. */\n facets?: Record<string, unknown>;\n /**\n * Facets that narrow the match when the host row carries a value, and\n * drop away when it does not: a lane narrows its tub's look-ahead to its\n * own service level, a tub without lanes keeps the whole destination.\n */\n narrow?: Record<string, unknown>;\n /** Default `pending`. */\n status?: string;\n}\n\nexport interface RelatedSetDecl {\n source: RelatedSource;\n query?: RelatedQueryDecl;\n}\n\n/** A count column's text keyed by count; `default` covers the rest, `{n}` reads the count. */\nexport const RELATED_DISPLAY_DEFAULT = 'default';\n\nexport interface RelatedColumnDecl {\n label: string;\n related: string;\n aggregate?: RelatedAggregate;\n /** min/max: `{{item.payload.<path>}}` on an items set, `{{metadata.<key>}}` on a query set. */\n value?: string;\n /** min/max: how the value renders, as on any facet-table column. */\n format?: string;\n /** count: text by count, e.g. `{ \"0\": \"Ready\", \"default\": \"Waiting on {n}\" }`. */\n display?: Record<string, string>;\n splitBy?: string;\n labels?: Record<string, string>;\n priority?: 1 | 2 | 3;\n /** CSS width, as on any facet-table column. */\n width?: string;\n}\n\nexport interface RowDetailColumnDecl {\n label: string;\n value: string;\n format?: string;\n priority?: 1 | 2 | 3;\n}\n\nexport interface RowDetailSectionDecl {\n related: string;\n label?: string;\n columns: RowDetailColumnDecl[];\n limit?: number;\n}\n\n/** The validated, normalized related declaration of one list schema. */\nexport interface ListSchemaRelations {\n sets: Record<string, RelatedSetDecl>;\n columns: RelatedColumnDecl[];\n rowDetail: RowDetailSectionDecl[];\n /** The metadata key a facet-table groups by, when declared. */\n groupKey: string | null;\n}\n\n/** Per-host aggregate for one (set, splitBy) pair, or one (set, min/max, value) triple. */\nexport interface RelatedHostAggregate {\n count: number;\n /** min/max: the extreme value among `count` values; absent when none carries one. */\n value?: string | number;\n /** Split value to count; a null value is keyed by the empty string. */\n splits?: Record<string, number>;\n /** Items whose reciprocal row the viewer cannot read. */\n hidden?: number;\n /** A host whose facet templates resolved to nothing; the set did not run. */\n unresolved?: boolean;\n}\n\nexport interface RelatedSetResult {\n source: RelatedSource;\n /**\n * The roles whose rows the set reads, which a list follows for live\n * changes: a query set's resolved roles in order, or the roles of an item\n * set's readable reciprocal rows when a column splits by them.\n */\n roles?: string[];\n /** Query sets: role titles, keyed by role. */\n roleLabels?: Record<string, string>;\n /** Query sets: declared roles outside the viewer's full read scope. */\n restricted?: string[];\n /** Keyed by relatedAggregateKey (the splitBy, '' when unsplit, or `min:<path>`), then host id. */\n aggregates: Record<string, Record<string, RelatedHostAggregate>>;\n}\n\nexport interface RelatedAggregatesResponse {\n version: number | null;\n sets: Record<string, RelatedSetResult>;\n}\n\nexport interface RelatedItemEntry {\n itemKey: string;\n payload?: unknown;\n at?: string;\n actor?: string;\n reciprocalId?: string;\n}\n\nexport interface RelatedRow {\n /** Items sets only. */\n item?: RelatedItemEntry;\n /** The reciprocal row (items) or the related row (query); null when unreadable. */\n escalation: Record<string, unknown> | null;\n}\n\nexport interface RelatedRowsResponse {\n source: RelatedSource;\n rows: RelatedRow[];\n total: number;\n restricted?: string[];\n roleLabels?: Record<string, string>;\n}\n","import {\n RELATED_AGGREGATES,\n RELATED_DISPLAY_DEFAULT,\n RELATED_SOURCES,\n SPLIT_PATHS,\n type RelatedAggregate,\n type RelatedColumnDecl,\n} from './types';\n\nconst VALUE_TOKEN = /^\\{\\{\\s*([^{}]+?)\\s*\\}\\}$/;\nconst ITEM_PREFIX = 'item.';\nconst PATH_SEGMENT = /^[a-zA-Z0-9_]+$/;\nconst METADATA_KEY = /^[a-zA-Z0-9_]+$/;\nconst COUNT_TOKEN = /\\{n\\}/g;\n\nexport type RelatedExtreme = typeof RELATED_AGGREGATES.MIN | typeof RELATED_AGGREGATES.MAX;\n\n/** True for the aggregates that pick one value rather than count. */\nexport function isExtremeAggregate(aggregate: unknown): aggregate is RelatedExtreme {\n return aggregate === RELATED_AGGREGATES.MIN || aggregate === RELATED_AGGREGATES.MAX;\n}\n\n/**\n * The stored path a min/max `value` template reads: `payload.<path>` for an\n * items set, `metadata.<key>` for a query set. Null when the template does\n * not fit the set's source.\n */\nexport function relatedValuePath(source: string, value: unknown): string | null {\n if (typeof value !== 'string') return null;\n const token = value.match(VALUE_TOKEN)?.[1];\n if (!token) return null;\n if (source === RELATED_SOURCES.ITEMS) {\n if (!token.startsWith(`${ITEM_PREFIX}${SPLIT_PATHS.PAYLOAD}`)) return null;\n const path = token.slice(ITEM_PREFIX.length + SPLIT_PATHS.PAYLOAD.length);\n return path && path.split('.').every((s) => PATH_SEGMENT.test(s)) ? `${SPLIT_PATHS.PAYLOAD}${path}` : null;\n }\n if (!token.startsWith(SPLIT_PATHS.METADATA)) return null;\n const key = token.slice(SPLIT_PATHS.METADATA.length);\n return METADATA_KEY.test(key) ? token : null;\n}\n\n/** The key a column's per-host aggregates are stored under in its set's result. */\nexport function relatedAggregateKey(col: Pick<RelatedColumnDecl, 'aggregate' | 'splitBy' | 'value'>, source: string): string {\n if (isExtremeAggregate(col.aggregate)) return `${col.aggregate}:${relatedValuePath(source, col.value) ?? ''}`;\n return col.splitBy ?? '';\n}\n\n/** A count column's display text, or null when the column declares none for this count. */\nexport function relatedCountText(display: Record<string, string> | undefined, count: number): string | null {\n if (!display) return null;\n const text = display[String(count)] ?? display[RELATED_DISPLAY_DEFAULT];\n return text === undefined ? null : text.replace(COUNT_TOKEN, String(count));\n}\n\n/**\n * The least or greatest of several values: numbers when every value is a\n * number, otherwise text in code-unit order (ISO instants order as text).\n */\nexport function foldExtreme(fold: RelatedAggregate, values: Array<string | number>): string | number | undefined {\n if (!values.length) return undefined;\n const pickMin = fold === RELATED_AGGREGATES.MIN;\n if (values.every((v) => typeof v === 'number')) {\n return pickMin ? Math.min(...(values as number[])) : Math.max(...(values as number[]));\n }\n const texts = values.map(String).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n return pickMin ? texts[0] : texts[texts.length - 1];\n}\n","import {\n FACET_TABLE_LAYOUT,\n GROUP_FOLDS,\n LIST_SCHEMA_KEYS,\n RELATED_AGGREGATES,\n RELATED_DISPLAY_DEFAULT,\n RELATED_LIMITS,\n RELATED_SOURCES,\n SPLIT_PATHS,\n type ListSchemaRelations,\n type RelatedColumnDecl,\n type RelatedSetDecl,\n type RowDetailSectionDecl,\n} from './types';\nimport { isExtremeAggregate, relatedValuePath } from './aggregate';\n\n/** A metadata key: interpolated as a JSON path, so strictly validated. */\nexport const METADATA_KEY = /^[a-zA-Z0-9_]+$/;\nconst SET_NAME = /^[a-zA-Z][a-zA-Z0-9_-]{0,47}$/;\nconst PATH_SEGMENT = /^[a-zA-Z0-9_]+$/;\nconst COUNT_KEY = /^(0|[1-9][0-9]*)$/;\n\ntype Obj = Record<string, unknown>;\n\nclass ListSchemaError extends Error {}\n\nfunction fail(message: string): never {\n throw new ListSchemaError(message);\n}\n\nfunction isObj(value: unknown): value is Obj {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\n/** True when a dotted path has only plain segments. */\nfunction isPlainPath(path: string): boolean {\n return path.length > 0 && path.split('.').every((s) => PATH_SEGMENT.test(s));\n}\n\n/** The split paths a set's source accepts. */\nexport function splitPathError(source: string, splitBy: string): string | null {\n if (source === RELATED_SOURCES.QUERY) {\n if (splitBy === SPLIT_PATHS.ROLE) return null;\n if (splitBy.startsWith(SPLIT_PATHS.METADATA) && METADATA_KEY.test(splitBy.slice(SPLIT_PATHS.METADATA.length))) return null;\n return `splitBy \"${splitBy}\" on a query set must be \"role\" or \"metadata.<key>\"`;\n }\n if (splitBy.startsWith(SPLIT_PATHS.PAYLOAD) && isPlainPath(splitBy.slice(SPLIT_PATHS.PAYLOAD.length))) return null;\n if (splitBy.startsWith(SPLIT_PATHS.RECIPROCAL_METADATA)\n && METADATA_KEY.test(splitBy.slice(SPLIT_PATHS.RECIPROCAL_METADATA.length))) return null;\n return `splitBy \"${splitBy}\" on an items set must be \"payload.<path>\" or \"reciprocal.metadata.<key>\"`;\n}\n\nfunction readSet(name: string, raw: unknown): RelatedSetDecl {\n if (!SET_NAME.test(name)) fail(`x-lt-related name \"${name}\" must start with a letter (letters, digits, _ or -)`);\n if (!isObj(raw)) fail(`x-lt-related.${name} must be an object`);\n if (raw.source === RELATED_SOURCES.ITEMS) {\n if (raw.query !== undefined) fail(`x-lt-related.${name}: an items set takes no query`);\n return { source: RELATED_SOURCES.ITEMS };\n }\n if (raw.source !== RELATED_SOURCES.QUERY) fail(`x-lt-related.${name}.source must be \"items\" or \"query\"`);\n const q = raw.query;\n if (!isObj(q)) fail(`x-lt-related.${name}.query is required for a query set`);\n const hasRoles = q.roles !== undefined;\n const hasSegment = q.segment !== undefined;\n if (hasRoles === hasSegment) fail(`x-lt-related.${name}.query takes exactly one of roles or segment`);\n if (hasRoles) {\n const roles = q.roles;\n if (!Array.isArray(roles) || roles.length === 0 || roles.length > RELATED_LIMITS.MAX_QUERY_ROLES\n || !roles.every(isNonEmptyString)) {\n fail(`x-lt-related.${name}.query.roles must be 1..${RELATED_LIMITS.MAX_QUERY_ROLES} role names`);\n }\n } else if (!isNonEmptyString(q.segment)) {\n fail(`x-lt-related.${name}.query.segment must be a role name`);\n }\n if (!isObj(q.facets) || Object.keys(q.facets).length === 0) {\n fail(`x-lt-related.${name}.query.facets must name at least one facet`);\n }\n for (const [key, value] of Object.entries(q.facets)) {\n if (!METADATA_KEY.test(key)) fail(`x-lt-related.${name}.query.facets key \"${key}\" must be letters, digits or _`);\n if (value === null || typeof value === 'object') fail(`x-lt-related.${name}.query.facets.${key} must be a scalar or template`);\n }\n if (q.narrow !== undefined) {\n if (!isObj(q.narrow) || Object.keys(q.narrow).length === 0) fail(`x-lt-related.${name}.query.narrow must name at least one facet`);\n for (const [key, value] of Object.entries(q.narrow)) {\n if (!METADATA_KEY.test(key)) fail(`x-lt-related.${name}.query.narrow key \"${key}\" must be letters, digits or _`);\n if (key in q.facets) fail(`x-lt-related.${name}.query.narrow.${key} is already a required facet`);\n if (value === null || typeof value === 'object') fail(`x-lt-related.${name}.query.narrow.${key} must be a scalar or template`);\n }\n }\n if (q.status !== undefined && !isNonEmptyString(q.status)) fail(`x-lt-related.${name}.query.status must be a status`);\n return {\n source: RELATED_SOURCES.QUERY,\n query: {\n ...(hasRoles ? { roles: [...(q.roles as string[])] } : { segment: q.segment as string }),\n facets: { ...q.facets },\n ...(q.narrow !== undefined ? { narrow: { ...(q.narrow as Obj) } } : {}),\n ...(q.status !== undefined ? { status: q.status as string } : {}),\n },\n };\n}\n\nfunction readRelatedColumn(raw: Obj, sets: Record<string, RelatedSetDecl>, at: string): RelatedColumnDecl {\n const name = raw.related;\n if (!isNonEmptyString(name) || !sets[name]) fail(`${at}.related must name a set declared in x-lt-related`);\n if (raw.aggregate !== undefined && raw.aggregate !== RELATED_AGGREGATES.COUNT && !isExtremeAggregate(raw.aggregate)) {\n fail(`${at}.aggregate must be \"count\", \"min\" or \"max\"`);\n }\n const source = sets[name].source;\n if (isExtremeAggregate(raw.aggregate)) {\n if (!relatedValuePath(source, raw.value)) {\n fail(source === RELATED_SOURCES.ITEMS\n ? `${at}.value must be \"{{item.payload.<path>}}\" on an items set`\n : `${at}.value must be \"{{metadata.<key>}}\" on a query set`);\n }\n if (raw.splitBy !== undefined) fail(`${at}: a ${raw.aggregate} column takes no splitBy`);\n if (raw.display !== undefined) fail(`${at}: display applies to a count column`);\n } else if (raw.value !== undefined) {\n fail(`${at}.value applies to a min or max column`);\n }\n if (raw.format !== undefined && typeof raw.format !== 'string') fail(`${at}.format must be a format name`);\n if (raw.display !== undefined) {\n if (!isObj(raw.display) || Object.keys(raw.display).length === 0\n || !Object.entries(raw.display).every(([k, v]) => (k === RELATED_DISPLAY_DEFAULT || COUNT_KEY.test(k)) && typeof v === 'string')) {\n fail(`${at}.display must map counts (or \"default\") to display text`);\n }\n }\n if (raw.splitBy !== undefined) {\n if (!isNonEmptyString(raw.splitBy)) fail(`${at}.splitBy must be a path`);\n const err = splitPathError(sets[name].source, raw.splitBy);\n if (err) fail(`${at}: ${err}`);\n }\n if (raw.labels !== undefined && (!isObj(raw.labels) || !Object.values(raw.labels).every((v) => typeof v === 'string'))) {\n fail(`${at}.labels must map values to display text`);\n }\n return raw as unknown as RelatedColumnDecl;\n}\n\nfunction readRowDetail(raw: unknown, sets: Record<string, RelatedSetDecl>): RowDetailSectionDecl[] {\n if (raw === undefined) return [];\n if (!Array.isArray(raw) || raw.length === 0 || raw.length > RELATED_LIMITS.MAX_ROW_DETAIL_SECTIONS) {\n fail(`x-lt-row-detail must be 1..${RELATED_LIMITS.MAX_ROW_DETAIL_SECTIONS} sections`);\n }\n return raw.map((section, i) => {\n const at = `x-lt-row-detail[${i}]`;\n if (!isObj(section)) fail(`${at} must be an object`);\n if (!isNonEmptyString(section.related) || !sets[section.related]) fail(`${at}.related must name a set declared in x-lt-related`);\n if (!Array.isArray(section.columns) || section.columns.length === 0) fail(`${at}.columns must list at least one column`);\n for (const [j, col] of section.columns.entries()) {\n if (!isObj(col) || !isNonEmptyString(col.label) || typeof col.value !== 'string') {\n fail(`${at}.columns[${j}] needs a label and a value template`);\n }\n }\n if (section.limit !== undefined && (!Number.isInteger(section.limit) || (section.limit as number) < 1\n || (section.limit as number) > RELATED_LIMITS.ROWS_MAX)) {\n fail(`${at}.limit must be 1..${RELATED_LIMITS.ROWS_MAX}`);\n }\n return section as unknown as RowDetailSectionDecl;\n });\n}\n\nfunction readGroupKey(schema: Obj): string | null {\n const raw = schema[LIST_SCHEMA_KEYS.GROUP_BY];\n if (raw === undefined || schema[LIST_SCHEMA_KEYS.LAYOUT] !== FACET_TABLE_LAYOUT) return null;\n const key = typeof raw === 'string' && raw.startsWith(SPLIT_PATHS.METADATA) ? raw.slice(SPLIT_PATHS.METADATA.length) : '';\n if (!METADATA_KEY.test(key)) fail('x-lt-group-by on a facet-table must be \"metadata.<key>\"');\n return key;\n}\n\nconst FOLDS = new Set<string>(Object.values(GROUP_FOLDS));\n\n/**\n * Validate and normalize the related declaration of a list schema. Throws on\n * an invalid declaration; keys outside this vocabulary stay opaque.\n */\nexport function readListSchemaRelations(schema: unknown): ListSchemaRelations {\n const empty: ListSchemaRelations = { sets: {}, columns: [], rowDetail: [], groupKey: null };\n if (!isObj(schema)) return empty;\n const rawSets = schema[LIST_SCHEMA_KEYS.RELATED];\n const sets: Record<string, RelatedSetDecl> = {};\n if (rawSets !== undefined) {\n if (!isObj(rawSets)) fail('x-lt-related must map set names to declarations');\n const names = Object.keys(rawSets);\n if (names.length === 0 || names.length > RELATED_LIMITS.MAX_SETS) fail(`x-lt-related must declare 1..${RELATED_LIMITS.MAX_SETS} sets`);\n for (const name of names) sets[name] = readSet(name, rawSets[name]);\n }\n const columns: RelatedColumnDecl[] = [];\n const rawColumns = schema[LIST_SCHEMA_KEYS.COLUMNS];\n if (Array.isArray(rawColumns)) {\n rawColumns.forEach((col, i) => {\n if (!isObj(col)) return;\n if (col.related !== undefined) columns.push(readRelatedColumn(col, sets, `x-lt-columns[${i}]`));\n if (col.group !== undefined && (typeof col.group !== 'string' || !FOLDS.has(col.group))) {\n fail(`x-lt-columns[${i}].group must be one of ${[...FOLDS].join(', ')}`);\n }\n });\n }\n return { sets, columns, rowDetail: readRowDetail(schema[LIST_SCHEMA_KEYS.ROW_DETAIL], sets), groupKey: readGroupKey(schema) };\n}\n\n/** The declaration's first error, or null when valid. */\nexport function listSchemaRelationsError(schema: unknown): string | null {\n try {\n readListSchemaRelations(schema);\n return null;\n } catch (err) {\n if (err instanceof ListSchemaError) return err.message;\n throw err;\n }\n}\n"],"names":["isEffectivelyClaimed","esc","isAckEscalation","identifierToTitle","id","w","escalationDotClass","e","STATUS_DOT_STYLES","rowContext","parse","s","v","IDENTITY_COLUMN_WIDTH","actionColumnWidth","label","DEFAULT_CLAIM_MINUTES","isClaimable","row","RowActionButton","def","onView","prominent","forceView","authored","action","claim","useClaimEscalation","navigate","useNavigate","location","useLocation","error","setError","useState","spent","fire","err","classes","jsxs","jsx","METADATA_TOKEN","isFacetValue","raw","rowRefinePairs","columnDefs","pairs","seen","metadata","col","bound","_a","key","RefineTrigger","onOpen","className","Search","LIST_SCHEMA_KEYS","RELATED_SOURCES","RELATED_AGGREGATES","GROUP_FOLDS","SPLIT_PATHS","RELATED_LIMITS","FACET_TABLE_LAYOUT","RELATED_DISPLAY_DEFAULT","VALUE_TOKEN","ITEM_PREFIX","PATH_SEGMENT","METADATA_KEY","COUNT_TOKEN","isExtremeAggregate","aggregate","relatedValuePath","source","value","token","path","relatedAggregateKey","relatedCountText","display","count","text","foldExtreme","fold","values","pickMin","texts","a","b","SET_NAME","COUNT_KEY","ListSchemaError","fail","message","isObj","isNonEmptyString","isPlainPath","splitPathError","splitBy","readSet","name","q","hasRoles","hasSegment","roles","readRelatedColumn","sets","at","k","readRowDetail","section","i","j","readGroupKey","schema","FOLDS","readListSchemaRelations","empty","rawSets","names","columns","rawColumns"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{u as l,b as a,c as s}from"./vendor-query-DvWWuNIB.js";import{m as r}from"./index-CXNh7LuG.js";function f(e={}){const o=new URLSearchParams;return e.status&&o.set("status",e.status),e.graph_topic&&o.set("graph_topic",e.graph_topic),e.app_id&&o.set("app_id",e.app_id),e.search&&o.set("search",e.search),e.set_id&&o.set("set_id",e.set_id),e.limit&&o.set("limit",String(e.limit)),e.offset!==void 0&&o.set("offset",String(e.offset)),l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows?${o}`)})}function m(){return l({queryKey:["yamlWorkflowAppIds"],queryFn:()=>r("/yaml-workflows/app-ids")})}function c(e){return l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows/${e}`),enabled:!!e})}function w(){const e=a();return s({mutationFn:o=>r("/yaml-workflows",{method:"POST",body:JSON.stringify(o)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function k(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/deploy`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function p(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/activate`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function d(){const e=a();return s({mutationFn:({id:o,data:t,sync:n,execute_as:u})=>r(`/yaml-workflows/${o}/invoke`,{method:"POST",body:JSON.stringify({data:t,sync:n,...u?{execute_as:u}:{}})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function h(){const e=a();return s({mutationFn:({id:o,task_queue:t,compilation_feedback:n})=>r(`/yaml-workflows/${o}/regenerate`,{method:"POST",body:JSON.stringify({task_queue:t,compilation_feedback:n})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function q(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/archive`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function W(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/restore`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"}),e.invalidateQueries({queryKey:["yamlWorkflow"],refetchType:"all"})}})}function S(){const e=a();return s({mutationFn:({id:o,...t})=>r(`/yaml-workflows/${o}`,{method:"PUT",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function v(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function T(e){return l({queryKey:["yamlWorkflows",e,"versions"],queryFn:()=>r(`/yaml-workflows/${e}/versions`),enabled:!!e})}function F(e,o){return l({queryKey:["yamlWorkflows",e,"versions",o],queryFn:()=>r(`/yaml-workflows/${e}/versions/${o}`),enabled:!!e&&o!==null})}export{m as a,S as b,c,T as d,k as e,p as f,q as g,W as h,v as i,h as j,F as k,d as l,w as m,f as u};
2
- //# sourceMappingURL=yaml-workflows-DgrmL_Kt.js.map
1
+ import{u as l,b as a,c as s}from"./vendor-query-DvWWuNIB.js";import{m as r}from"./index-ygxyAKcc.js";function f(e={}){const o=new URLSearchParams;return e.status&&o.set("status",e.status),e.graph_topic&&o.set("graph_topic",e.graph_topic),e.app_id&&o.set("app_id",e.app_id),e.search&&o.set("search",e.search),e.set_id&&o.set("set_id",e.set_id),e.limit&&o.set("limit",String(e.limit)),e.offset!==void 0&&o.set("offset",String(e.offset)),l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows?${o}`)})}function m(){return l({queryKey:["yamlWorkflowAppIds"],queryFn:()=>r("/yaml-workflows/app-ids")})}function c(e){return l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows/${e}`),enabled:!!e})}function w(){const e=a();return s({mutationFn:o=>r("/yaml-workflows",{method:"POST",body:JSON.stringify(o)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function k(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/deploy`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function p(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/activate`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function d(){const e=a();return s({mutationFn:({id:o,data:t,sync:n,execute_as:u})=>r(`/yaml-workflows/${o}/invoke`,{method:"POST",body:JSON.stringify({data:t,sync:n,...u?{execute_as:u}:{}})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function h(){const e=a();return s({mutationFn:({id:o,task_queue:t,compilation_feedback:n})=>r(`/yaml-workflows/${o}/regenerate`,{method:"POST",body:JSON.stringify({task_queue:t,compilation_feedback:n})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function q(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/archive`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function W(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/restore`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"}),e.invalidateQueries({queryKey:["yamlWorkflow"],refetchType:"all"})}})}function S(){const e=a();return s({mutationFn:({id:o,...t})=>r(`/yaml-workflows/${o}`,{method:"PUT",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function v(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function T(e){return l({queryKey:["yamlWorkflows",e,"versions"],queryFn:()=>r(`/yaml-workflows/${e}/versions`),enabled:!!e})}function F(e,o){return l({queryKey:["yamlWorkflows",e,"versions",o],queryFn:()=>r(`/yaml-workflows/${e}/versions/${o}`),enabled:!!e&&o!==null})}export{m as a,S as b,c,T as d,k as e,p as f,q as g,W as h,v as i,h as j,F as k,d as l,w as m,f as u};
2
+ //# sourceMappingURL=yaml-workflows-Dyln3od-.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"yaml-workflows-DgrmL_Kt.js","sources":["../../src/api/yaml-workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { LTYamlWorkflowRecord, LTYamlWorkflowStatus, LTYamlWorkflowVersion } from './types';\n\ninterface YamlWorkflowListResponse {\n workflows: LTYamlWorkflowRecord[];\n total: number;\n}\n\ninterface YamlWorkflowFilters {\n status?: LTYamlWorkflowStatus;\n graph_topic?: string;\n app_id?: string;\n search?: string;\n set_id?: string;\n limit?: number;\n offset?: number;\n}\n\nexport function useYamlWorkflows(filters: YamlWorkflowFilters = {}) {\n const params = new URLSearchParams();\n if (filters.status) params.set('status', filters.status);\n if (filters.graph_topic) params.set('graph_topic', filters.graph_topic);\n if (filters.app_id) params.set('app_id', filters.app_id);\n if (filters.search) params.set('search', filters.search);\n if (filters.set_id) params.set('set_id', filters.set_id);\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', filters],\n queryFn: () => apiFetch(`/yaml-workflows?${params}`),\n });\n}\n\nexport function useYamlWorkflowAppIds() {\n return useQuery<{ app_ids: string[] }>({\n queryKey: ['yamlWorkflowAppIds'],\n queryFn: () => apiFetch('/yaml-workflows/app-ids'),\n });\n}\n\nexport function useYamlWorkflowByTopic(graphTopic: string | undefined, appId?: string) {\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', 'byTopic', graphTopic, appId],\n queryFn: () => {\n const params = new URLSearchParams({ graph_topic: graphTopic!, limit: '1' });\n if (appId) params.set('app_id', appId);\n return apiFetch(`/yaml-workflows?${params}`);\n },\n enabled: !!graphTopic,\n });\n}\n\nexport function useYamlWorkflow(id: string) {\n return useQuery<LTYamlWorkflowRecord>({\n queryKey: ['yamlWorkflows', id],\n queryFn: () => apiFetch(`/yaml-workflows/${id}`),\n enabled: !!id,\n });\n}\n\nexport function useCreateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (input: {\n workflow_id: string;\n task_queue: string;\n workflow_name: string;\n name: string;\n description?: string;\n app_id?: string;\n subscribes?: string;\n tags?: string[];\n compilation_feedback?: string;\n }) =>\n apiFetch<LTYamlWorkflowRecord>('/yaml-workflows', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeployYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/deploy`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useActivateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/activate`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, data, sync, execute_as }: { id: string; data: Record<string, unknown>; sync?: boolean; execute_as?: string }) =>\n apiFetch<{ result?: unknown; job_id?: string }>(`/yaml-workflows/${id}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, sync, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRegenerateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, task_queue, compilation_feedback }: { id: string; task_queue?: string; compilation_feedback?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/regenerate`, {\n method: 'POST',\n body: JSON.stringify({ task_queue, compilation_feedback }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useArchiveYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/archive`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRestoreYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/restore`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflow'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpdateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, ...updates }: { id: string; yaml_content?: string; name?: string; description?: string; input_schema?: Record<string, unknown>; output_schema?: Record<string, unknown>; tags?: string[]; app_id?: string; graph_topic?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}`, {\n method: 'PUT',\n body: JSON.stringify(updates),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<{ deleted: boolean }>(`/yaml-workflows/${id}`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Cron scheduling ─────────────────────────────────────────────\n\nexport function useSetYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, cron_schedule, cron_envelope, execute_as }: {\n id: string;\n cron_schedule: string;\n cron_envelope?: Record<string, unknown> | null;\n execute_as?: string | null;\n }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'PUT',\n body: JSON.stringify({ cron_schedule, cron_envelope, execute_as }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useClearYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Version history ─────────────────────────────────────────────\n\nexport function useYamlWorkflowVersions(id: string) {\n return useQuery<{ versions: LTYamlWorkflowVersion[]; total: number }>({\n queryKey: ['yamlWorkflows', id, 'versions'],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions`),\n enabled: !!id,\n });\n}\n\nexport function useYamlWorkflowVersion(id: string, version: number | null) {\n return useQuery<LTYamlWorkflowVersion>({\n queryKey: ['yamlWorkflows', id, 'versions', version],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions/${version}`),\n enabled: !!id && version !== null,\n });\n}\n"],"names":["useYamlWorkflows","filters","params","useQuery","apiFetch","useYamlWorkflowAppIds","useYamlWorkflow","id","useCreateYamlWorkflow","queryClient","useQueryClient","useMutation","input","useDeployYamlWorkflow","useActivateYamlWorkflow","useInvokeYamlWorkflow","data","sync","execute_as","useRegenerateYamlWorkflow","task_queue","compilation_feedback","useArchiveYamlWorkflow","useRestoreYamlWorkflow","useUpdateYamlWorkflow","updates","useDeleteYamlWorkflow","useYamlWorkflowVersions","useYamlWorkflowVersion","version"],"mappings":"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"}
1
+ {"version":3,"file":"yaml-workflows-Dyln3od-.js","sources":["../../src/api/yaml-workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { LTYamlWorkflowRecord, LTYamlWorkflowStatus, LTYamlWorkflowVersion } from './types';\n\ninterface YamlWorkflowListResponse {\n workflows: LTYamlWorkflowRecord[];\n total: number;\n}\n\ninterface YamlWorkflowFilters {\n status?: LTYamlWorkflowStatus;\n graph_topic?: string;\n app_id?: string;\n search?: string;\n set_id?: string;\n limit?: number;\n offset?: number;\n}\n\nexport function useYamlWorkflows(filters: YamlWorkflowFilters = {}) {\n const params = new URLSearchParams();\n if (filters.status) params.set('status', filters.status);\n if (filters.graph_topic) params.set('graph_topic', filters.graph_topic);\n if (filters.app_id) params.set('app_id', filters.app_id);\n if (filters.search) params.set('search', filters.search);\n if (filters.set_id) params.set('set_id', filters.set_id);\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', filters],\n queryFn: () => apiFetch(`/yaml-workflows?${params}`),\n });\n}\n\nexport function useYamlWorkflowAppIds() {\n return useQuery<{ app_ids: string[] }>({\n queryKey: ['yamlWorkflowAppIds'],\n queryFn: () => apiFetch('/yaml-workflows/app-ids'),\n });\n}\n\nexport function useYamlWorkflowByTopic(graphTopic: string | undefined, appId?: string) {\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', 'byTopic', graphTopic, appId],\n queryFn: () => {\n const params = new URLSearchParams({ graph_topic: graphTopic!, limit: '1' });\n if (appId) params.set('app_id', appId);\n return apiFetch(`/yaml-workflows?${params}`);\n },\n enabled: !!graphTopic,\n });\n}\n\nexport function useYamlWorkflow(id: string) {\n return useQuery<LTYamlWorkflowRecord>({\n queryKey: ['yamlWorkflows', id],\n queryFn: () => apiFetch(`/yaml-workflows/${id}`),\n enabled: !!id,\n });\n}\n\nexport function useCreateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (input: {\n workflow_id: string;\n task_queue: string;\n workflow_name: string;\n name: string;\n description?: string;\n app_id?: string;\n subscribes?: string;\n tags?: string[];\n compilation_feedback?: string;\n }) =>\n apiFetch<LTYamlWorkflowRecord>('/yaml-workflows', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeployYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/deploy`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useActivateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/activate`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, data, sync, execute_as }: { id: string; data: Record<string, unknown>; sync?: boolean; execute_as?: string }) =>\n apiFetch<{ result?: unknown; job_id?: string }>(`/yaml-workflows/${id}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, sync, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRegenerateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, task_queue, compilation_feedback }: { id: string; task_queue?: string; compilation_feedback?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/regenerate`, {\n method: 'POST',\n body: JSON.stringify({ task_queue, compilation_feedback }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useArchiveYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/archive`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRestoreYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/restore`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflow'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpdateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, ...updates }: { id: string; yaml_content?: string; name?: string; description?: string; input_schema?: Record<string, unknown>; output_schema?: Record<string, unknown>; tags?: string[]; app_id?: string; graph_topic?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}`, {\n method: 'PUT',\n body: JSON.stringify(updates),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<{ deleted: boolean }>(`/yaml-workflows/${id}`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Cron scheduling ─────────────────────────────────────────────\n\nexport function useSetYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, cron_schedule, cron_envelope, execute_as }: {\n id: string;\n cron_schedule: string;\n cron_envelope?: Record<string, unknown> | null;\n execute_as?: string | null;\n }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'PUT',\n body: JSON.stringify({ cron_schedule, cron_envelope, execute_as }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useClearYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Version history ─────────────────────────────────────────────\n\nexport function useYamlWorkflowVersions(id: string) {\n return useQuery<{ versions: LTYamlWorkflowVersion[]; total: number }>({\n queryKey: ['yamlWorkflows', id, 'versions'],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions`),\n enabled: !!id,\n });\n}\n\nexport function useYamlWorkflowVersion(id: string, version: number | null) {\n return useQuery<LTYamlWorkflowVersion>({\n queryKey: ['yamlWorkflows', id, 'versions', version],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions/${version}`),\n enabled: !!id && version !== null,\n });\n}\n"],"names":["useYamlWorkflows","filters","params","useQuery","apiFetch","useYamlWorkflowAppIds","useYamlWorkflow","id","useCreateYamlWorkflow","queryClient","useQueryClient","useMutation","input","useDeployYamlWorkflow","useActivateYamlWorkflow","useInvokeYamlWorkflow","data","sync","execute_as","useRegenerateYamlWorkflow","task_queue","compilation_feedback","useArchiveYamlWorkflow","useRestoreYamlWorkflow","useUpdateYamlWorkflow","updates","useDeleteYamlWorkflow","useYamlWorkflowVersions","useYamlWorkflowVersion","version"],"mappings":"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"}
@@ -8,11 +8,11 @@
8
8
  <link rel="preconnect" href="https://fonts.googleapis.com" />
9
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
10
  <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
11
- <script type="module" crossorigin src="./assets/index-CXNh7LuG.js"></script>
11
+ <script type="module" crossorigin src="./assets/index-ygxyAKcc.js"></script>
12
12
  <link rel="modulepreload" crossorigin href="./assets/vendor-query-DvWWuNIB.js">
13
13
  <link rel="modulepreload" crossorigin href="./assets/vendor-react-_9U4mKFr.js">
14
14
  <link rel="modulepreload" crossorigin href="./assets/vendor-icons-en0_uSRD.js">
15
- <link rel="stylesheet" crossorigin href="./assets/index-C_dp4WgY.css">
15
+ <link rel="stylesheet" crossorigin href="./assets/index-BmzscsXK.css">
16
16
  </head>
17
17
  <body>
18
18
  <div id="root"></div>
@@ -53,7 +53,7 @@ Written by the fold at creation, inside the row's Leg1 commit, and maintained by
53
53
  | `envelope` | `accumulate_items` | `Record<itemKey, { payload?, at, actor?, reciprocalId? }>` |
54
54
  | `envelope` | `accumulate_config` | the folded `{ unique, resolveAtMax }` |
55
55
 
56
- A batch row records each fill's time and actor under `envelope.batch_filled_at` and `envelope.batch_filled_by`, and may start with entries already satisfied through `filled` (see [Creating Escalations](hitl/escalation.md)). A batch wait may add `partialOnTimeout: true`; it stores `envelope.batch_partial_on_timeout` and its timer delivers `{ ...filledItems, $trigger: 'timeout' }` instead of `false`. A pending key may carry a flag in `envelope.batch_flags` (it stays pending and still fills); a wait that adds `wakeOnFlag: true` ends on the first flag and delivers `{ ...filledItems, $flags, $trigger: 'flag' }`.
56
+ A batch row records each fill's time and actor under `envelope.batch_filled_at` and `envelope.batch_filled_by`, and may start with entries already satisfied through `filled` (see [Creating Escalations](hitl/escalation.md)). A batch wait may add `partialOnTimeout: true`; it stores `envelope.batch_partial_on_timeout` and its timer delivers `{ ...filledItems, $trigger: 'timeout' }` instead of `false`. A pending key may carry a flag in `envelope.batch_flags` (it stays pending and still fills); a wait that adds `wakeOnFlag: true` ends on the first flag and delivers `{ ...filledItems, $flags, $trigger: 'flag' }`. A wait that adds `wakeOnFill: true` (or a list of keys) ends on a fill and delivers `{ ...filledItems, $filled: [itemKey], $filledAt, $filledBy, $trigger: 'fill' }`; the fill answers `woke`, and the workflow parks its next round with the fills carried forward in `filled`.
57
57
 
58
58
  ## Operations
59
59
 
@@ -1131,7 +1131,7 @@ POST /api/escalations/resolve-batch-item-by-signal-key
1131
1131
  POST /api/escalations/resolve-batch-item-by-metadata
1132
1132
  ```
1133
1133
 
1134
- Submit ONE declared item of a batch escalation (a `conditional` wait created with `batch: [...]`). Interim items answer `{ outcome: 'accepted', remaining }`; the LAST item answers `{ outcome: 'completed', remaining: 0, signaled, escalationId, workflowId }` and the waiting workflow resumes with the full collection, in the same statement. Each item validates against the row's versioned role form (canonical 422). Duplicates answer 409 (`Batch item already submitted`), undeclared keys 400, a non-batch row 400.
1134
+ Submit ONE declared item of a batch escalation (a `conditional` wait created with `batch: [...]`). Interim items answer `{ outcome: 'accepted', remaining }`; the LAST item answers `{ outcome: 'completed', remaining: 0, signaled, escalationId, workflowId }` and the waiting workflow resumes with the full collection, in the same statement. On a wait declared with `wakeOnFill` for the key, a fill with items remaining answers `{ outcome: 'woke', remaining, signaled, escalationId, workflowId }`: the row resolves and the workflow resumes with the items so far and `$trigger: 'fill'`. Each item validates against the row's versioned role form (canonical 422). Duplicates answer 409 (`Batch item already submitted`), undeclared keys 400, a non-batch row 400.
1135
1135
 
1136
1136
  **Body (by id):** `{ itemKey, resolverPayload, metadata?, assertClaim? }`. **By signal key:** `{ signalKey, itemKey, resolverPayload, metadata? }`. **By metadata:** `{ key, value, itemKey, resolverPayload, metadata?, restrictRoles? }`.
1137
1137
 
@@ -453,7 +453,7 @@ if (bin === null) return cancelled();
453
453
  ship(bin.$accumulated.map((item) => item.itemKey), bin.$trigger);
454
454
  ```
455
455
 
456
- Requires hotmesh 0.29.0+. `conditional` accepts the same `accumulate` field and returns `T | false | null`; `partialOnTimeout: true` on a `batch` wait likewise makes the timer deliver the filled items with `$trigger: 'timeout'`, and `wakeOnFlag: true` makes a flag on a pending key deliver them with `$flags` and `$trigger: 'flag'` (hotmesh 0.31.3+). See [Creating Escalations](../../hitl/escalation.md#open-accumulation--items-arrive-over-time).
456
+ Requires hotmesh 0.29.0+. `conditional` accepts the same `accumulate` field and returns `T | false | null`; `partialOnTimeout: true` on a `batch` wait likewise makes the timer deliver the filled items with `$trigger: 'timeout'`, `wakeOnFlag: true` makes a flag on a pending key deliver them with `$flags` and `$trigger: 'flag'` (hotmesh 0.31.3+), and `wakeOnFill: true` (or a list of keys) makes a fill deliver them with `$filled`, `$filledAt`, `$filledBy` and `$trigger: 'fill'` (hotmesh 0.32.0+). See [Creating Escalations](../../hitl/escalation.md#open-accumulation--items-arrive-over-time).
457
457
 
458
458
  ### Two-step form
459
459
 
package/docs/dashboard.md CHANGED
@@ -329,7 +329,7 @@ A code encodes **`version:category:target`** (e.g. `10:1:SN-12345`):
329
329
 
330
330
  **Admin config** lives at `/admin/scan-codes` (scheme list) and `/admin/scan-codes/:version` (a scheme with its rules) — role-manager gated (admin, engineer, superadmin). A scheme carries a name, its target facet, encoding, and — for identity schemes — a grant policy.
331
331
 
332
- **Station surface.** `/scan/station` is a full-screen scan surface with an idle prompt, an info/choice screen (the current reality plus labeled choices when a rule presents options), a badge prompt when identity is required, the hold card while an item is held, and a done screen once an act completes its row (a step's or a choice's `done` copy). A role's `scan_done` returns the station to its home or a route after the done screen; a step's `follow` keeps the station on the item and holds its next row when it appears. In **kiosk mode** — a login holding exactly one role whose `properties.kiosk` is set — the chrome falls away and only the role's list, escalation detail, and this scan screen are reachable. The header **scan** panel offers the same manual entry and capture settings on any page.
332
+ **Station surface.** `/scan/station` is a full-screen scan surface with an idle prompt, an info/choice screen (the current reality plus labeled choices when a rule presents options), a badge prompt when identity is required, the hold card while an item is held, and a done screen once an act completes its row (a step's or a choice's `done` copy). A role's `scan_done` returns the station to its home or a route after the done screen, read from the chosen station queue or else from the completed row's role; a step's `follow` keeps the station on the item and holds its next row when it appears. In **kiosk mode** — a login holding exactly one role whose `properties.kiosk` is set, or a read-only station whose Station queue is chosen — the chrome falls away and only the role's list, escalation detail, and this scan screen are reachable. The header **scan** panel offers the same manual entry and capture settings on any page.
333
333
 
334
334
  **Badge scanning grants acting identity.** A scheme of kind `identity` binds a badge value to a person (via a facet on `lt_users.metadata`). Scanning a badge primes an **ephemeral acting grant** minted through the internal keystore; it rides subsequent scans as the `X-LT-Acting-Token` header, and verbs then run **as the badged person under their own RBAC** — attribution, never privilege escalation. A badge on a work form belongs to the submission: the form names who will submit, holds if the wrong badge scans, and consumes the single-use grant on the write. A dead grant (expired, exhausted, revoked) fails loudly rather than executing silently.
335
335
 
@@ -607,7 +607,9 @@ in the placeholder. Type the target and press Enter: the bar composes
607
607
  the outcome navigates, confirms, or answers exactly as a physical scan would.
608
608
  An outcome that answers in place (a fallback, a conflict, a closed row) is
609
609
  narrated right under the bar. A whole code pasted into a Run mode executes
610
- as-is; fixed-encoding rules accept digits only and say so inline. The menu
610
+ as-is; fixed-encoding rules accept digits only and say so inline. A gtin or
611
+ pattern rule runs the typed code itself, and a pattern rule names a code that
612
+ matches none of its patterns inline. The menu
611
613
  footer opens the scan panel for scanner settings and the barcode preview.
612
614
  See [Scan codes](scan-codes.md).
613
615
 
@@ -115,6 +115,22 @@ const result = await conditional<Record<string, unknown>>(signalId, {
115
115
  if (result && result.$trigger === 'flag') return sendToManager(orderId, result.$flags);
116
116
  ```
117
117
 
118
+ Add `wakeOnFill: true` (hotmesh 0.32.0+), or a list of keys, and a fill ends the wait so the workflow acts on each item as it lands: the fill resolves the row and the wait resumes with the items so far, `$filled: [itemKey]`, `$filledAt` and `$filledBy` (every filled key's time and actor) and `$trigger: 'fill'`. The workflow parks the next round with every fill carried forward through `filled`, built from `$filledAt` and `$filledBy`; the last key completes as on any batch. The fill answers `woke` with the remaining count.
119
+
120
+ ```typescript
121
+ let filled: Record<string, BatchFilledEntry> | undefined;
122
+ for (let round = 1; ; round++) {
123
+ const out = await conditional<Record<string, any>>(`receive-${orderId}-${round}`, {
124
+ role: 'receiving', metadata: { orderId, trackingNumbers }, batch: boxKeys, wakeOnFill: true,
125
+ ...(filled ? { filled } : {}),
126
+ });
127
+ if (!out || out.$trigger !== 'fill') return out; // complete, expired, or cancelled
128
+ await recordReceipt(orderId, out.$filled[0]); // a proxied activity
129
+ filled = Object.fromEntries(Object.keys(out.$filledAt).map((key) =>
130
+ [key, { payload: out[key], at: out.$filledAt[key], actor: out.$filledBy?.[key] }]));
131
+ }
132
+ ```
133
+
118
134
  Entries already satisfied before the wait begins go in `filled` (hotmesh 0.31.0+), keyed by item key with their `payload`, the `at` they were satisfied (from the source of record, never a clock read in the workflow), and an optional `actor`. The row starts with that progress: those keys are left out of `batch_pending`, their payloads, times, and actors are written beside the rest, and the completing wake delivers them with the collection. Every key in `filled` must be declared in `batch`, and at least one must stay open; a `filled` that covers every key throws, so skip the wait instead.
119
135
 
120
136
  ```typescript
@@ -56,6 +56,12 @@ A scheme (`lt_config_scan_schemes`, indexed 10–99) declares:
56
56
  - **`target_facet`** — the escalation metadata key the target resolves
57
57
  against (`serialNumber`, `assetTag`, `batchId`…). The physical label and
58
58
  the digital twin share this value; the scan is the join.
59
+ - **`target_match`** — `value` (default): the facet holds one value equal to
60
+ the target. `member`: the facet holds a list, such as every parcel still out
61
+ on an order (`trackingNumbers: ["1Z…B0", "1Z…B1"]`), and a row matches when
62
+ its list contains the target (`metadata @> { trackingNumbers: ["1Z…B1"] }`,
63
+ served by the GIN index). Every locate, claim, resolve, hold and add takes
64
+ the declared shape. Action schemes only.
59
65
  - **`encoding`** — how the code string parses:
60
66
  - `delimited` — text separated by a single character (default `:`), e.g.
61
67
  `10:1:SN-123`. Use with Code 128, QR, or DataMatrix labels; targets may
@@ -72,6 +78,17 @@ A scheme (`lt_config_scan_schemes`, indexed 10–99) declares:
72
78
  most one gtin scheme, and while it is enabled no enabled fixed scheme may
73
79
  accept an 8, 12, 13 or 14 digit code: the scheme write is refused, naming
74
80
  both schemes, so a digits-only code always has exactly one reading.
81
+ - `pattern` — codes another system prints with no version or category, such
82
+ as carrier tracking numbers. `patterns` lists 1 to 10 regular expressions,
83
+ each matched against the whole code (UPS `1Z[0-9A-Z]{16}`, FedEx
84
+ `[0-9]{12}`); the target is the code as scanned and the scheme's one rule
85
+ is category `0`. Patterns read codes of up to 64 characters, which bounds
86
+ the cost of any expression. A code a prefixed scheme reads parses there first, and
87
+ when two pattern schemes match, the lower version reads it. While a gtin
88
+ scheme is enabled, a pattern scheme declares `precedes_gtin`: `true` reads
89
+ a digits-only code with its patterns before the gtin scheme, `false`
90
+ leaves it to the gtin scheme. A write that leaves the order undeclared
91
+ while both are enabled is refused, naming both schemes.
75
92
 
76
93
  ## Rules and steps
77
94
 
@@ -390,7 +407,7 @@ done copy stands and the station returns as its role says.
390
407
  |---|---|
391
408
  | `accumulate` with `accumulate.from: "subject"` | The held item joins the accumulator the scan names (found by the scheme facet, narrowed by `accumulate.container`). The held row is written as the reciprocal in the same statement, so a held row parked as a one-slot accumulator completes and its workflow wakes. `params.itemKey` names the item, e.g. `{subject.itemId}`. |
392
409
  | `accumulate` with `accumulate.into: "subject"` | The held row collects the scanned code (`itemKey` defaults to `{scan.target}`). Use it when the container has no row yet: the first item for a container tells the workflow which container was scanned. With `accumulate.item`, the scanned code's own pending row is written as the reciprocal in the same statement (see below). On a bounded accumulator the answer carries `progress` and the subject stays held while slots remain. |
393
- | `fill` with `fill.into: "subject"` | One expected item is checked off: the held row is a batch whose keys are codes, and the scan fills the first open key for its code. A code expected twice is declared `<code>#1`, `<code>#2` and takes two scans; a third is refused. The answer carries `progress: { filled, total, remaining }`, the subject stays held while items remain, and the last fill completes the row. On a `gtin` scheme a refusal's `expected` lists codes as the package prints them (EAN-13, or EAN-8), not the stored 14-digit form. `fill.into: "scanned"` fills the row the scan itself names. |
410
+ | `fill` with `fill.into: "subject"` | One expected item is checked off: the held row is a batch whose keys are codes, and the scan fills the first open key for its code. A code expected twice is declared `<code>#1`, `<code>#2` and takes two scans; a third is refused. The answer carries `progress: { filled, total, remaining }`, the subject stays held while items remain, and the last fill completes the row. On a wait declared with `wakeOnFill`, a fill wakes the workflow while items remain and answers as an interim fill: the station stays on the hold card, and the next scan fills the workflow's next round, the pending row of the same workflow in the same role carrying the same target. On a `gtin` scheme a refusal's `expected` lists codes as the package prints them (EAN-13, or EAN-8), not the stored 14-digit form. `fill.into: "scanned"` fills the row the scan itself names. |
394
411
 
395
412
  **Naming what a fill still expects.** Codes alone do not tell a person which
396
413
  box to take. `fill.labels` names a per-key map on the batch row (the map a batch
@@ -597,10 +614,15 @@ portals, and the scan screens (choice, badge). The list with neither a
597
614
  `role` nor a `facets` filter is every queue at once, so it redirects home
598
615
  too, including right after sign-in; a scan's `show-list` (narrowed by
599
616
  facets) stays. A role that declares
600
- [portals](./hitl/portal.md) lands on its first one as home instead of the list. The header toolbar and event feed remain. A user
601
- holding more than one role, or an admin-type grant, always gets full chrome —
602
- kiosk is for the single-role floor login, never a way to hide the product from
603
- a real operator.
617
+ [portals](./hitl/portal.md) lands on its first one as home instead of the list. The header toolbar and event feed remain.
618
+
619
+ A read-only station login (every grant a plain member with `write_scope:
620
+ 'none'`) may hold several roles. With one kiosk role among them it locks to
621
+ that one. With several it keeps full chrome and offers a **Station queue**
622
+ picker in the user menu; choosing one locks the device to it, and the choice
623
+ persists per device. Any other login holding more than one role, or an
624
+ admin-type grant, always gets full chrome. Kiosk is for the floor station,
625
+ never a way to hide the product from a real operator.
604
626
 
605
627
  Pair kiosk with `x-lt-transition-done` on the role's form schema
606
628
  (`"/escalations/available?role={{escalation.role}}&status=available"`) so a
@@ -624,7 +646,14 @@ that clears the subject. A fill that leaves entries pending stays on the hold
624
646
  card, a refusal never returns, and a `follow` runs first. A station holding
625
647
  a row never returns: the hold a follow lands, by event or by its last look,
626
648
  keeps the station on it until the next scan. Without `scan_done` the done
627
- copy stays until the next scan. The value is validated
649
+ copy stays until the next scan.
650
+
651
+ The policy comes from the station's chosen queue when that queue declares
652
+ `scan_done`; otherwise from the role of the row the act completed, which an
653
+ executed bench or choice response names on `escalation.role`. A read-only station over several
654
+ benches with no queue chosen returns by each row's own role, and `home` then
655
+ resolves to that role's kiosk home. A station whose chosen queue declares a
656
+ return lands there, whichever bench's row it completed. The value is validated
628
657
  where the role is written, like `badge_grant`, and set on the role page under
629
658
  Identity.
630
659
 
@@ -737,13 +766,14 @@ with Enter; capture is **pattern-anchored**: a capture-phase window listener
737
766
  accumulates keystrokes freely, and when the terminator arrives it checks
738
767
  whether the recent keys end with a scan-code shape. The shapes come from the
739
768
  configured schemes: each delimited version's `VV:C:target`, each fixed
740
- scheme's exact digit lengths, and for a gtin scheme a whole 8, 12, 13 or 14
741
- digit run whose check digit holds (a leading zero is part of the code). A
742
- code never starts inside a longer run of digits.
743
-
744
- - **Digits-only codes fire only at scanner speed** (avg ≤ 50 ms/key). A
745
- typed PO number or count followed by Enter stays in its field, even when
746
- its digits happen to form a valid barcode.
769
+ scheme's exact digit lengths, for a gtin scheme a whole 8, 12, 13 or 14
770
+ digit run whose check digit holds (a leading zero is part of the code), and
771
+ for a pattern scheme a run matching one of its expressions. A code never
772
+ starts inside a longer run of digits.
773
+
774
+ - **Digits-only and pattern codes fire only at scanner speed** (avg ≤ 50
775
+ ms/key). A typed PO number, count or tracking number followed by Enter
776
+ stays in its field, even when it happens to form a valid code.
747
777
  - **An open form can take the scan first.** A field with
748
778
  [`x-lt-scan`](hitl/x-lt-scan.md) that accepts the scan's scheme is filled
749
779
  instead; every other scan, and every badge, runs globally.
@@ -776,7 +806,8 @@ camera provider plugs into the same dispatch pipeline.
776
806
  The **header bar** runs rules without hardware: its type chip lists every
777
807
  enabled rule as a Run mode, the bar shows the rule's code head (`10:1:`) ahead
778
808
  of the input, and Enter composes and executes `10:1:<target>` through the same
779
- pipeline a scanner uses. See [Search and run](dashboard.md#search-and-run).
809
+ pipeline a scanner uses. A gtin or pattern rule has no code head: the typed
810
+ code runs as entered. See [Search and run](dashboard.md#search-and-run).
780
811
 
781
812
  The **scan panel** (the bar's menu footer, or the user menu) carries a manual
782
813
  entry field — type or paste a whole code to execute it — the last scan's