@hotmeshio/long-tail 0.29.0 → 0.30.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/api/roles.js +4 -0
- package/build/api/scan-codes/choice.js +6 -3
- package/build/api/scan-codes/context.d.ts +7 -1
- package/build/api/scan-codes/context.js +24 -0
- package/build/api/scan-codes/execute.js +4 -2
- package/build/api/scan-codes/present.d.ts +3 -1
- package/build/api/scan-codes/present.js +25 -12
- package/build/routes/oauth.js +9 -6
- package/build/services/oauth/providers/github.js +2 -1
- package/build/services/oauth/providers/google.js +3 -3
- package/build/services/oauth/providers/microsoft.js +4 -1
- package/build/services/oauth/providers/mock.js +1 -1
- package/build/services/role/scan-done.d.ts +7 -0
- package/build/services/role/scan-done.js +36 -0
- package/build/services/role/seed.js +4 -0
- package/build/services/role/types.d.ts +11 -0
- package/build/services/role/types.js +4 -0
- package/build/services/scan-code/validate.js +50 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/index.d.ts +2 -2
- package/build/types/index.js +3 -1
- package/build/types/oauth.d.ts +1 -0
- package/build/types/scan-choice.d.ts +8 -0
- package/build/types/scan-code/constants.d.ts +3 -0
- package/build/types/scan-code/constants.js +4 -1
- package/build/types/scan-code/response.d.ts +14 -0
- package/build/types/scan-code/rule.d.ts +11 -0
- package/dashboard/dist/assets/{AdminDashboard-DRE0hSDS.js → AdminDashboard-CZIeiLe0.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-DRE0hSDS.js.map → AdminDashboard-CZIeiLe0.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-BuflQGgy.js → AgentConfigPage-DO3ATfCU.js} +6 -6
- package/dashboard/dist/assets/{AgentConfigPage-BuflQGgy.js.map → AgentConfigPage-DO3ATfCU.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-BiL9FB7i.js → AgentDetailPage-BWAlHQfB.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-BiL9FB7i.js.map → AgentDetailPage-BWAlHQfB.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-C4ZxCNxt.js → AgentsPage-Cs4IKeec.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-C4ZxCNxt.js.map → AgentsPage-Cs4IKeec.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-B5p8QJvI.js → AvailableEscalationsPage-CiRxaing.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-B5p8QJvI.js.map → AvailableEscalationsPage-CiRxaing.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-B7V77PnY.js → BotPicker-DGLkc9PQ.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-B7V77PnY.js.map → BotPicker-DGLkc9PQ.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-DcGVMQqm.js → BulkAssignModal-C4LV8s0y.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-DcGVMQqm.js.map → BulkAssignModal-C4LV8s0y.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-DmbC1pEs.js → CapabilitiesPage-BLMMV3-W.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-DmbC1pEs.js.map → CapabilitiesPage-BLMMV3-W.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-C81S1qic.js → CollapsibleSection-BAizcNCt.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-C81S1qic.js.map → CollapsibleSection-BAizcNCt.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-3RFyWN9Q.js → ConfirmDeleteModal-DlNWHVxi.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-3RFyWN9Q.js.map → ConfirmDeleteModal-DlNWHVxi.js.map} +1 -1
- package/dashboard/dist/assets/{ConnectedAppsPage-B0D2OvTD.js → ConnectedAppsPage-D94kx0v3.js} +2 -2
- package/dashboard/dist/assets/{ConnectedAppsPage-B0D2OvTD.js.map → ConnectedAppsPage-D94kx0v3.js.map} +1 -1
- package/dashboard/dist/assets/{CountdownTimer-iAG28fzG.js → CountdownTimer-CSdAwgwZ.js} +2 -2
- package/dashboard/dist/assets/{CountdownTimer-iAG28fzG.js.map → CountdownTimer-CSdAwgwZ.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-DoFwNvFv.js → CredentialsPage-pOyC1GfC.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-DoFwNvFv.js.map → CredentialsPage-pOyC1GfC.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-C1Bb2wo4.js → CronLabel-BVlOOcyo.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-C1Bb2wo4.js.map → CronLabel-BVlOOcyo.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-Cl_Flb16.js → DropZone-DefYTYQy.js} +2 -2
- package/dashboard/dist/assets/{DropZone-Cl_Flb16.js.map → DropZone-DefYTYQy.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-DZs1I1JW.js → ElapsedCell-Bnjp3onG.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-DZs1I1JW.js.map → ElapsedCell-Bnjp3onG.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-Du1O6Oly.js → EntityTimelinePanel-D6Z7YXuY.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-Du1O6Oly.js.map → EntityTimelinePanel-D6Z7YXuY.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-CrpBhC0e.js → EscalationListSchemaPage-D2aa_arC.js} +2 -2
- package/dashboard/dist/assets/{EscalationListSchemaPage-CrpBhC0e.js.map → EscalationListSchemaPage-D2aa_arC.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-Co59lcuD.js → EscalationSchemaPage-DuOje0Ke.js} +2 -2
- package/dashboard/dist/assets/{EscalationSchemaPage-Co59lcuD.js.map → EscalationSchemaPage-DuOje0Ke.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTimeline-B_fzNsX5.js → EscalationTimeline-DFkhU2Z2.js} +2 -2
- package/dashboard/dist/assets/{EscalationTimeline-B_fzNsX5.js.map → EscalationTimeline-DFkhU2Z2.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTitleSelect-C2Goebjo.js → EscalationTitleSelect-CgYnMM_O.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-C2Goebjo.js.map → EscalationTitleSelect-CgYnMM_O.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-Cgmrl8Zc.js → EscalationsOverview-BTkFoklS.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-Cgmrl8Zc.js.map → EscalationsOverview-BTkFoklS.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-BdEiu3Fv.js → EventTable-MJmAbu6N.js} +2 -2
- package/dashboard/dist/assets/{EventTable-BdEiu3Fv.js.map → EventTable-MJmAbu6N.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-CzKYBOMC.js → FilterBar-Blt7qcUc.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-CzKYBOMC.js.map → FilterBar-Blt7qcUc.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-CcDFhY53.js → GraphInvokePage-B4K3mT_c.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-CcDFhY53.js.map → GraphInvokePage-B4K3mT_c.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-Xahqcdu9.js → HomePage-BN5wXq6V.js} +2 -2
- package/dashboard/dist/assets/{HomePage-Xahqcdu9.js.map → HomePage-BN5wXq6V.js.map} +1 -1
- package/dashboard/dist/assets/{LinePage-DKwhGunp.js → LinePage-CuHHHwBy.js} +3 -3
- package/dashboard/dist/assets/{LinePage-DKwhGunp.js.map → LinePage-CuHHHwBy.js.map} +1 -1
- package/dashboard/dist/assets/{LinesPage-BXZVO4MC.js → LinesPage-D9TRHWyt.js} +2 -2
- package/dashboard/dist/assets/{LinesPage-BXZVO4MC.js.map → LinesPage-D9TRHWyt.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-orQsOdl_.js → ListToolbar-GGj6X36p.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-orQsOdl_.js.map → ListToolbar-GGj6X36p.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-pSnadtSM.js → McpOverview-Do31A1jL.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-pSnadtSM.js.map → McpOverview-Do31A1jL.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-BCAJ3rKO.js → McpQueryDetailPage-D6FSB1bS.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-BCAJ3rKO.js.map → McpQueryDetailPage-D6FSB1bS.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-CRyXeRp5.js → McpQueryPage-CyT2d0Y_.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-CRyXeRp5.js.map → McpQueryPage-CyT2d0Y_.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-BHppCztI.js → McpRunDetailPage-C3mmTl4Y.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-BHppCztI.js.map → McpRunDetailPage-C3mmTl4Y.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-Cd9yCT-_.js → McpRunsPage-CTeFFUE2.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-Cd9yCT-_.js.map → McpRunsPage-CTeFFUE2.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-OTZD2hzt.js → NamespacePill-CeSfHH-j.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-OTZD2hzt.js.map → NamespacePill-CeSfHH-j.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-BtnthZgj.js → OperationsPage-BUtQP5dm.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-BtnthZgj.js.map → OperationsPage-BUtQP5dm.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-B4_OBhYh.js → OperatorDashboard-BwYOXyUV.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-B4_OBhYh.js.map → OperatorDashboard-BwYOXyUV.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-Hx8APPwE.js → PageHeader-DiGWAQlR.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-Hx8APPwE.js.map → PageHeader-DiGWAQlR.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-BEQYYBJv.js → PageHeaderWithStats-DwnKQ06j.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-BEQYYBJv.js.map → PageHeaderWithStats-DwnKQ06j.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-BAYjM9qf.js → PersonaDetailPage-CkrKJLNv.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-BAYjM9qf.js.map → PersonaDetailPage-CkrKJLNv.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-6HsOp-1y.js → PersonasPage-BS8aBeOv.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-6HsOp-1y.js.map → PersonasPage-BS8aBeOv.js.map} +1 -1
- package/dashboard/dist/assets/{PortalPage-6OMr7KtJ.js → PortalPage-PEBk6VVu.js} +2 -2
- package/dashboard/dist/assets/{PortalPage-6OMr7KtJ.js.map → PortalPage-PEBk6VVu.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-AidH_h7z.js → ProcessDetailPage-CJ71bxDs.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-AidH_h7z.js.map → ProcessDetailPage-CJ71bxDs.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-BWKoKbXk.js → ProcessesListPage-ov_HLxz5.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-BWKoKbXk.js.map → ProcessesListPage-ov_HLxz5.js.map} +1 -1
- package/dashboard/dist/assets/{ResolverForm-BaSvhLoT.js → ResolverForm-BKiUY-lN.js} +2 -2
- package/dashboard/dist/assets/{ResolverForm-BaSvhLoT.js.map → ResolverForm-BKiUY-lN.js.map} +1 -1
- package/dashboard/dist/assets/RoleDetailPage-CmfWwjtG.js +8 -0
- package/dashboard/dist/assets/RoleDetailPage-CmfWwjtG.js.map +1 -0
- package/dashboard/dist/assets/{RolePill-R5_ctGFy.js → RolePill-D3hkAdKf.js} +2 -2
- package/dashboard/dist/assets/{RolePill-R5_ctGFy.js.map → RolePill-D3hkAdKf.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-T2hH_MV5.js → RolesPage-DvO5DJWY.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-T2hH_MV5.js.map → RolesPage-DvO5DJWY.js.map} +1 -1
- package/dashboard/dist/assets/{RosterWidget-DG6Rcx4P.js → RosterWidget-Cs6OTbST.js} +2 -2
- package/dashboard/dist/assets/{RosterWidget-DG6Rcx4P.js.map → RosterWidget-Cs6OTbST.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-M2h9U6PP.js → RunAsSelector-VNjUn9Zp.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-M2h9U6PP.js.map → RunAsSelector-VNjUn9Zp.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-lB_WxoZw.js → ScanCodesPage-Dbaud0fc.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-lB_WxoZw.js.map → ScanCodesPage-Dbaud0fc.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-C3VLg61H.js → ScanSchemeDetailPage-BfDw_Eke.js} +2 -2
- package/dashboard/dist/assets/{ScanSchemeDetailPage-C3VLg61H.js.map → ScanSchemeDetailPage-BfDw_Eke.js.map} +1 -1
- package/dashboard/dist/assets/ScanStationPage-DE-zJTiD.js +2 -0
- package/dashboard/dist/assets/ScanStationPage-DE-zJTiD.js.map +1 -0
- package/dashboard/dist/assets/{ScopeBadge-BXZ084nD.js → ScopeBadge-DGz79rmG.js} +2 -2
- package/dashboard/dist/assets/{ScopeBadge-BXZ084nD.js.map → ScopeBadge-DGz79rmG.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-BdjseWXr.js → StickyPagination-CJ3jjlDX.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-BdjseWXr.js.map → StickyPagination-CJ3jjlDX.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-DJCBxETh.js → StreamMessageDetail-yOdyJGHR.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-DJCBxETh.js.map → StreamMessageDetail-yOdyJGHR.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-DiXm9jIk.js → SwimlaneTimeline-DeFWNFrL.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-DiXm9jIk.js.map → SwimlaneTimeline-DeFWNFrL.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-DjPUDp2M.js → TagInput-DaIdhv3h.js} +2 -2
- package/dashboard/dist/assets/{TagInput-DjPUDp2M.js.map → TagInput-DaIdhv3h.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-m8CQFN4w.js → TaskDetailPage-BPL_Zx-L.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-m8CQFN4w.js.map → TaskDetailPage-BPL_Zx-L.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-D-4Ynf3K.js → TaskQueuePill-sUA1nZe-.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-D-4Ynf3K.js.map → TaskQueuePill-sUA1nZe-.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-DHBSUhZC.js → TasksListPage-Bc3S63_O.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-DHBSUhZC.js.map → TasksListPage-Bc3S63_O.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-Cq3bKUd-.js → TimeAgo-DAtnJQwU.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-Cq3bKUd-.js.map → TimeAgo-DAtnJQwU.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-e5gRR_FY.js → TimestampCell-CG0erHqq.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-e5gRR_FY.js.map → TimestampCell-CG0erHqq.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-GsKQ80CO.js → ToolPill-CpBAFdEX.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-GsKQ80CO.js.map → ToolPill-CpBAFdEX.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-Bg0ss9oN.js → ToolTestPanel-c71yqZv7.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-Bg0ss9oN.js.map → ToolTestPanel-c71yqZv7.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-DhPiCfOO.js → TopicDetailPage-BlUP0bb1.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-DhPiCfOO.js.map → TopicDetailPage-BlUP0bb1.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-BqZaVv3d.js → TopicsPage-lQ9HNzOq.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-BqZaVv3d.js.map → TopicsPage-lQ9HNzOq.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-C6ZNHHKN.js → UserName-Vf97ofcW.js} +2 -2
- package/dashboard/dist/assets/{UserName-C6ZNHHKN.js.map → UserName-Vf97ofcW.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-BUqIhtcr.js → WorkflowExecutionPage-B195cnHb.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-BUqIhtcr.js.map → WorkflowExecutionPage-B195cnHb.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-D7244fKp.js → WorkflowPill-CKHip3hH.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-D7244fKp.js.map → WorkflowPill-CKHip3hH.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-BKxhC_hT.js → WorkflowsDashboard-gH-PGsKq.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-BKxhC_hT.js.map → WorkflowsDashboard-gH-PGsKq.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-018s2q_p.js → WorkflowsOverview-D_wYDqw3.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-018s2q_p.js.map → WorkflowsOverview-D_wYDqw3.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-C2zcXDr1.js → YamlWorkflowDetailPage-Imob5F8H.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-C2zcXDr1.js.map → YamlWorkflowDetailPage-Imob5F8H.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-aVcNZNu6.js → YamlWorkflowsPage-DVEVSKKJ.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-aVcNZNu6.js.map → YamlWorkflowsPage-DVEVSKKJ.js.map} +1 -1
- package/dashboard/dist/assets/{agents-DRaaJUue.js → agents-B-8z_DV8.js} +2 -2
- package/dashboard/dist/assets/{agents-DRaaJUue.js.map → agents-B-8z_DV8.js.map} +1 -1
- package/dashboard/dist/assets/{bots-C4N90NCj.js → bots-Clm-wZeG.js} +2 -2
- package/dashboard/dist/assets/{bots-C4N90NCj.js.map → bots-Clm-wZeG.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-BoRWifSC.js → capabilities-CBwgv5tr.js} +2 -2
- package/dashboard/dist/assets/{capabilities-BoRWifSC.js.map → capabilities-CBwgv5tr.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-DGZAxi7J.js → controlplane-B96o1-zT.js} +2 -2
- package/dashboard/dist/assets/{controlplane-DGZAxi7J.js.map → controlplane-B96o1-zT.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-DJbfsH_m.js → escalation-columns-CFoFILF1.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-DJbfsH_m.js.map → escalation-columns-CFoFILF1.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-items-C8iJZEA8.js → escalation-items-BCUiPsfS.js} +2 -2
- package/dashboard/dist/assets/{escalation-items-C8iJZEA8.js.map → escalation-items-BCUiPsfS.js.map} +1 -1
- package/dashboard/dist/assets/{index-DhKGp4QK.js → index-BOuGMe78.js} +2 -2
- package/dashboard/dist/assets/{index-DhKGp4QK.js.map → index-BOuGMe78.js.map} +1 -1
- package/dashboard/dist/assets/{index-CeeSFnl-.js → index-BXKDpLk5.js} +2 -2
- package/dashboard/dist/assets/{index-CeeSFnl-.js.map → index-BXKDpLk5.js.map} +1 -1
- package/dashboard/dist/assets/{index-BuSUevzO.js → index-B_z-OFwk.js} +2 -2
- package/dashboard/dist/assets/{index-BuSUevzO.js.map → index-B_z-OFwk.js.map} +1 -1
- package/dashboard/dist/assets/{index-CyL-6CAa.js → index-C1WJs6IZ.js} +2 -2
- package/dashboard/dist/assets/{index-CyL-6CAa.js.map → index-C1WJs6IZ.js.map} +1 -1
- package/dashboard/dist/assets/{index-pzbGpihI.js → index-CXNh7LuG.js} +25 -25
- package/dashboard/dist/assets/index-CXNh7LuG.js.map +1 -0
- package/dashboard/dist/assets/index-C_dp4WgY.css +1 -0
- package/dashboard/dist/assets/{index-DMKLnxt8.js → index-CnhNCVPc.js} +2 -2
- package/dashboard/dist/assets/{index-DMKLnxt8.js.map → index-CnhNCVPc.js.map} +1 -1
- package/dashboard/dist/assets/{index-BFxHIfQ_.js → index-Czb9O4Ns.js} +2 -2
- package/dashboard/dist/assets/{index-BFxHIfQ_.js.map → index-Czb9O4Ns.js.map} +1 -1
- package/dashboard/dist/assets/{index-BhS9XSy8.js → index-DvgjLvvn.js} +2 -2
- package/dashboard/dist/assets/{index-BhS9XSy8.js.map → index-DvgjLvvn.js.map} +1 -1
- package/dashboard/dist/assets/{index-CjjRxpVe.js → index-EZkdUZwM.js} +2 -2
- package/dashboard/dist/assets/{index-CjjRxpVe.js.map → index-EZkdUZwM.js.map} +1 -1
- package/dashboard/dist/assets/{index-DeyA88jq.js → index-IedmSPp1.js} +2 -2
- package/dashboard/dist/assets/{index-DeyA88jq.js.map → index-IedmSPp1.js.map} +1 -1
- package/dashboard/dist/assets/{index-CXXc9sUr.js → index-MGquOb7J.js} +2 -2
- package/dashboard/dist/assets/{index-CXXc9sUr.js.map → index-MGquOb7J.js.map} +1 -1
- package/dashboard/dist/assets/{index-3HaFP00M.js → index-P22vmuEu.js} +2 -2
- package/dashboard/dist/assets/{index-3HaFP00M.js.map → index-P22vmuEu.js.map} +1 -1
- package/dashboard/dist/assets/{index-DIU89TX3.js → index-XS-6UjQd.js} +2 -2
- package/dashboard/dist/assets/{index-DIU89TX3.js.map → index-XS-6UjQd.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-BWo3OCJc.js → knowledge-d92ncKgf.js} +2 -2
- package/dashboard/dist/assets/{knowledge-BWo3OCJc.js.map → knowledge-d92ncKgf.js.map} +1 -1
- package/dashboard/dist/assets/{machines-LEYY_yar.js → machines-BG9laURp.js} +2 -2
- package/dashboard/dist/assets/{machines-LEYY_yar.js.map → machines-BG9laURp.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-_0kFRcyT.js → mcp-CsZdpCEf.js} +2 -2
- package/dashboard/dist/assets/{mcp-_0kFRcyT.js.map → mcp-CsZdpCEf.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-BzmN0lc5.js → mcp-query-o2xqrZJv.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-BzmN0lc5.js.map → mcp-query-o2xqrZJv.js.map} +1 -1
- package/dashboard/dist/assets/{personas-kE4PMrgo.js → personas-EYROtAxm.js} +2 -2
- package/dashboard/dist/assets/{personas-kE4PMrgo.js.map → personas-EYROtAxm.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-DYDNaypF.js → pipelines-C17xZZsa.js} +2 -2
- package/dashboard/dist/assets/{pipelines-DYDNaypF.js.map → pipelines-C17xZZsa.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-ClJ-mbj9.js → tasks-CUppIhu6.js} +2 -2
- package/dashboard/dist/assets/{tasks-ClJ-mbj9.js.map → tasks-CUppIhu6.js.map} +1 -1
- package/dashboard/dist/assets/{topics-oHX4vbqe.js → topics-B-lCJzVc.js} +2 -2
- package/dashboard/dist/assets/{topics-oHX4vbqe.js.map → topics-B-lCJzVc.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-C97KADrj.js → useDebouncedValue-C5mMbYoU.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-C97KADrj.js.map → useDebouncedValue-C5mMbYoU.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-Kje0Rn7j.js → useNamespace-Bu42ipvu.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-Kje0Rn7j.js.map → useNamespace-Bu42ipvu.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-DMz-HKFv.js → useYamlActivityEvents-C29uM9Qp.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-DMz-HKFv.js.map → useYamlActivityEvents-C29uM9Qp.js.map} +1 -1
- package/dashboard/dist/assets/{validate-hUqjWN63.js → validate-Bt5QGwSc.js} +2 -2
- package/dashboard/dist/assets/{validate-hUqjWN63.js.map → validate-Bt5QGwSc.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-fxBvvHBi.js → vendor-icons-en0_uSRD.js} +191 -186
- package/dashboard/dist/assets/vendor-icons-en0_uSRD.js.map +1 -0
- package/dashboard/dist/assets/{yaml-workflows-64vfmKJx.js → yaml-workflows-DgrmL_Kt.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-64vfmKJx.js.map → yaml-workflows-DgrmL_Kt.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/api/http/roles.md +1 -1
- package/docs/dashboard.md +2 -2
- package/docs/oauth-and-delegation.md +5 -1
- package/docs/scan-codes.md +59 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/RoleDetailPage-D_30TDVh.js +0 -8
- package/dashboard/dist/assets/RoleDetailPage-D_30TDVh.js.map +0 -1
- package/dashboard/dist/assets/ScanStationPage-CVET1_4r.js +0 -2
- package/dashboard/dist/assets/ScanStationPage-CVET1_4r.js.map +0 -1
- package/dashboard/dist/assets/index-B9uv-euR.css +0 -1
- package/dashboard/dist/assets/index-pzbGpihI.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-fxBvvHBi.js.map +0 -1
package/dashboard/dist/assets/{yaml-workflows-64vfmKJx.js.map → yaml-workflows-DgrmL_Kt.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml-workflows-64vfmKJx.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-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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"}
|
|
@@ -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-
|
|
11
|
+
<script type="module" crossorigin src="./assets/index-CXNh7LuG.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
|
-
<link rel="modulepreload" crossorigin href="./assets/vendor-icons-
|
|
15
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
14
|
+
<link rel="modulepreload" crossorigin href="./assets/vendor-icons-en0_uSRD.js">
|
|
15
|
+
<link rel="stylesheet" crossorigin href="./assets/index-C_dp4WgY.css">
|
|
16
16
|
</head>
|
|
17
17
|
<body>
|
|
18
18
|
<div id="root"></div>
|
package/docs/api/http/roles.md
CHANGED
|
@@ -271,7 +271,7 @@ Returns all roles with metadata and usage counts.
|
|
|
271
271
|
| `description` | `string \| null` | Human-readable summary |
|
|
272
272
|
| `form_schema` | `object \| null` | JSON Schema for the escalation resolve form (the JIT UI). Versioned per role; fields may carry `x-lt-bind` to map values into the payload. Takes precedence over the deprecated workflow-level `resolver_schema` |
|
|
273
273
|
| `metadata_schema` | `object \| null` | JSON Schema declaring the expected shape of `lt_escalations.metadata` for this role. Drives faceted-query key autocomplete and creation-time validation |
|
|
274
|
-
| `properties` | `object` | Free user-owned bag — icons, colors, tags, etc.
|
|
274
|
+
| `properties` | `object` | Free user-owned bag — icons, colors, tags, etc. Reserved keys: `kiosk`, `badge_grant`, `scan_done`, `link_variables`, `on_cancel`, `on_timeout`, `worked_by` (see [Scan codes — station deployments](../../scan-codes.md#station-deployments)); `badge_grant` and `scan_done` are validated on write |
|
|
275
275
|
| `ops_visible` | `boolean` | When `true`, the role appears as a station on the `/operations` view |
|
|
276
276
|
| `enforce_schema` | `boolean` | When `true`, every resolve surface validates submitted payloads against this role's form schema and rejects violations with `422` (`code: schema_validation`) — see [Schema Enforcement](../../schema-enforcement.md) |
|
|
277
277
|
| `parent_role` | `string \| null` | Parent role in the process dependency graph; `null` for root stations |
|
package/docs/dashboard.md
CHANGED
|
@@ -275,7 +275,7 @@ Accessible at `/admin/roles/:role`. One page per role — a quiet header carryin
|
|
|
275
275
|
- **Escalations List Schema** — shows the list-schema version in use and links to the [Escalations List Schema](#escalations-list-schema) editor page.
|
|
276
276
|
- **Metadata Schema** — JSON Schema that validates each escalation's `metadata` at creation time. Its keys appear in faceted search autocomplete.
|
|
277
277
|
|
|
278
|
-
**Members** — who holds the role: admins manage it; members work its queue according to their read/write work-surface scope (read = which items appear; write = which they can claim and resolve). A `member` grant carries a scope chosen from five named profiles: full worker (`all`/`all`, default), see-all-act-own (`all`/`self`), own-items-only (`self`/`self`), read-only auditor (`all`/`none`), and read-only own (`self`/`none`). The picker enforces **write ⊆ read**. `admin` and `superadmin` grants always work the whole queue. **Badge at this station** sets how a badge behaves on this role's devices (`properties.badge_grant`): how long a badge scan lasts and how many acts it covers, e.g. ten minutes and unlimited at a high-volume placing bench, one act per scan at a workstation. Empty fields keep the badge scheme's policy. See [Scan codes — identity schemes](scan-codes.md#identity-schemes-and-acting-identity).
|
|
278
|
+
**Members** — who holds the role: admins manage it; members work its queue according to their read/write work-surface scope (read = which items appear; write = which they can claim and resolve). A `member` grant carries a scope chosen from five named profiles: full worker (`all`/`all`, default), see-all-act-own (`all`/`self`), own-items-only (`self`/`self`), read-only auditor (`all`/`none`), and read-only own (`self`/`none`). The picker enforces **write ⊆ read**. `admin` and `superadmin` grants always work the whole queue. **Badge at this station** sets how a badge behaves on this role's devices (`properties.badge_grant`): how long a badge scan lasts and how many acts it covers, e.g. ten minutes and unlimited at a high-volume placing bench, one act per scan at a workstation. Empty fields keep the badge scheme's policy. See [Scan codes — identity schemes](scan-codes.md#identity-schemes-and-acting-identity). **After a scan completes** sets where a station locked to this role returns once a scan act completes its row (`properties.scan_done`): the role's home or a route, after a pause on the done copy. See [Scan codes — the return](scan-codes.md#after-a-scan-completes-the-return).
|
|
279
279
|
|
|
280
280
|
**Pins** — two live-save groups. **Link Variables** leads: the facet names members bind per device (`properties.link_variables` — name, optional label, optional default). A pin below may reference a variable as a facet value, `facets={"facility":"{lt:facility}"}`; each member device opens it scoped to its own binding (set from the user menu → Link variables), falling back to the declared default or, unbound, applying no filter. A caption under each templated pin previews the binding on the viewing device (`facility = 'soleful'` / `facility = <empty>`). **Default Pins** follows — the pinned-view seeds this role hands its members (`default_pins`): label, dashboard-relative URL, optional badge. A badge counts the list its URL opens, with every list filter it carries (role, type, subtype, priority, search, facets, status), so two pins that differ only by subtype count differently. Members see them in their Pinned nav section from first login (marked role-provided) and may promote, hide, or reorder them via preferences; promoting a templated pin copies the template, so it keeps following the device's bindings. See [Faceted Routing — Link variables](faceted-routing.md#link-variables).
|
|
281
281
|
|
|
@@ -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),
|
|
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.
|
|
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
|
|
|
@@ -101,11 +101,15 @@ await start({
|
|
|
101
101
|
3. Backend generates CSRF state + PKCE code verifier, redirects to Google's consent screen.
|
|
102
102
|
4. Google redirects back to `GET /api/auth/oauth/google/callback` with an authorization code.
|
|
103
103
|
5. Backend exchanges the code for tokens, fetches user info (email, name).
|
|
104
|
-
6. If the user exists (matched by
|
|
104
|
+
6. If the user exists (matched by OAuth provider ID, or by verified email the first time), they're logged in. If not and `autoProvision` is true and the email's domain is in `allowedDomains` (or no list is set), a new user is created. Accounts an administrator created by email sign in whatever their domain. Otherwise the browser is sent back to the login page with a generic refusal; the reason (no account, or a domain outside `allowedDomains`) is logged, never shown.
|
|
105
105
|
7. OAuth tokens are encrypted (AES-256-GCM) and stored in `lt_oauth_tokens`.
|
|
106
106
|
8. A JWT is issued and the browser redirects to `/?token=<jwt>`.
|
|
107
107
|
9. The dashboard's `useOAuthCallback` hook picks up the token and completes login.
|
|
108
108
|
|
|
109
|
+
### What the Email Claim Means
|
|
110
|
+
|
|
111
|
+
A provider's email reaches Long Tail only when the provider verified it. Google supplies `email_verified`, GitHub marks each address `verified`, and Microsoft vouches for an account only under a single-tenant authority (`OAUTH_MICROSOFT_TENANT_ID` set to the tenant id rather than `common`). Without a verified email a sign-in can neither self-provision nor match an invited account; it signs in only if its provider ID is already bound. The same rule sets the email shown on a credential connection.
|
|
112
|
+
|
|
109
113
|
### Token Storage
|
|
110
114
|
|
|
111
115
|
OAuth access and refresh tokens are encrypted at rest using AES-256-GCM. The encryption key comes from `OAUTH_ENCRYPTION_KEY` (environment variable) or `auth.oauth.encryptionKey` (startup config).
|
package/docs/scan-codes.md
CHANGED
|
@@ -291,6 +291,26 @@ choice runs as the manager.
|
|
|
291
291
|
"params": { "resolverPayload": { "outcome": "added-by-manager" } } }
|
|
292
292
|
```
|
|
293
293
|
|
|
294
|
+
**One obvious act.** A choice with `hidden: true` beside its `roles` is left
|
|
295
|
+
off the screen for a person without one of them, instead of shown withheld:
|
|
296
|
+
the associate sees the one thing to do, and the manager's alternatives appear
|
|
297
|
+
when the manager badges. A choice with `when: { <facet>: <value> }` is offered
|
|
298
|
+
only while the presented row carries those facet values, and a tap on a
|
|
299
|
+
choice the row no longer offers answers `conflict`.
|
|
300
|
+
|
|
301
|
+
**Done copy for a choice.** A choice that writes may carry `done: { markdown }`,
|
|
302
|
+
rendered over the row it acted on (`{item.<facet>}`) once the write lands. The
|
|
303
|
+
station shows it as the done screen whether the badge came before or after
|
|
304
|
+
the tap, then returns as the role says (see
|
|
305
|
+
[After a scan completes](#after-a-scan-completes-the-return)). A choice
|
|
306
|
+
without done copy ends on a short notice.
|
|
307
|
+
|
|
308
|
+
```jsonc
|
|
309
|
+
{ "label": "Arrived: move the orders", "verb": "resolve", "requireActingIdentity": true,
|
|
310
|
+
"params": { "resolverPayload": { "outcome": "arrived" } },
|
|
311
|
+
"done": { "markdown": "Moved **{item.memberCount}** orders to Matching." } }
|
|
312
|
+
```
|
|
313
|
+
|
|
294
314
|
## Holding an item: the bench motion
|
|
295
315
|
|
|
296
316
|
At a bench where items go into containers, every act is one item going into
|
|
@@ -348,6 +368,24 @@ answer is `subject_stale` with `clearSubject: true`.
|
|
|
348
368
|
held, and act on it. The `{subject.<facet>}` template bag reads the held
|
|
349
369
|
row.
|
|
350
370
|
|
|
371
|
+
**Following the subject.** A subject step may carry `follow: { roles,
|
|
372
|
+
waitSeconds? }`. When its write completes the held row, the station keeps the
|
|
373
|
+
done copy up and waits for the subject's next pending row in those roles: the
|
|
374
|
+
row's `created` event replays the held code, the rule's hold step for that
|
|
375
|
+
role answers, and the new row is held without scanning the item again. At
|
|
376
|
+
Matching the last shoe box completes the matching row and the station flips
|
|
377
|
+
to the order's binning hold a moment later. When no event arrives within
|
|
378
|
+
`waitSeconds` (default 10, at most 120), the station takes one last look: a
|
|
379
|
+
row found then is held, exactly as if its event had arrived. Otherwise the
|
|
380
|
+
done copy stands and the station returns as its role says.
|
|
381
|
+
|
|
382
|
+
```jsonc
|
|
383
|
+
{ "query": {}, "verb": "fill", "subject": { "schemes": [11] },
|
|
384
|
+
"params": { "fill": { "into": "subject" } },
|
|
385
|
+
"done": { "markdown": "All matched." },
|
|
386
|
+
"follow": { "roles": ["binning-associate"], "waitSeconds": 15 } }
|
|
387
|
+
```
|
|
388
|
+
|
|
351
389
|
| Step | What the container scan does |
|
|
352
390
|
|---|---|
|
|
353
391
|
| `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}`. |
|
|
@@ -569,6 +607,27 @@ Pair kiosk with `x-lt-transition-done` on the role's form schema
|
|
|
569
607
|
resolve lands back on the list rather than walking browser history — see
|
|
570
608
|
[x-lt-transition](./hitl/x-lt-transition.md).
|
|
571
609
|
|
|
610
|
+
### After a scan completes: the return
|
|
611
|
+
|
|
612
|
+
A station works in one rhythm: badge, item, destination, done, back to the
|
|
613
|
+
list. A role names the last step in `properties.scan_done`:
|
|
614
|
+
|
|
615
|
+
```jsonc
|
|
616
|
+
"properties": { "kiosk": true, "scan_done": { "return": "home", "after_seconds": 2 } }
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
`return` is `home` (the role's kiosk home: its first portal, else its list) or
|
|
620
|
+
a dashboard-relative route; `after_seconds` (0-60, default 2) is how long the
|
|
621
|
+
done copy stays up first. The station returns once a scan act completes its
|
|
622
|
+
row: the last fill of a batch, an executed choice with done copy, any write
|
|
623
|
+
that clears the subject. A fill that leaves entries pending stays on the hold
|
|
624
|
+
card, a refusal never returns, and a `follow` runs first. A station holding
|
|
625
|
+
a row never returns: the hold a follow lands, by event or by its last look,
|
|
626
|
+
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
|
|
628
|
+
where the role is written, like `badge_grant`, and set on the role page under
|
|
629
|
+
Identity.
|
|
630
|
+
|
|
572
631
|
### The work surface — edit freely, badge at submit
|
|
573
632
|
|
|
574
633
|
On the work form, the badge belongs to the submission, not the editing. Once
|
package/package.json
CHANGED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import{j as e,a as g}from"./vendor-query-DvWWuNIB.js";import{ay as oe,aT as ce,aU as U,J as de,aV as xe,w as Y,x as Z,I as me,aW as O,aX as ue,aY as he,aZ as pe,Z as fe}from"./index-pzbGpihI.js";import{A as be}from"./AutoGrowTextarea-7X3T9La8.js";import{C as ve}from"./ConfirmDeleteModal-3RFyWN9Q.js";import{aO as Q,H as ge,aP as ee,G as H,aQ as ye,a2 as te,aB as je,q as D,an as Ne,P as se,L as ae,aC as ke,au as we,I as X,z as _e,r as ne,ad as Se,aR as Ce}from"./vendor-icons-fxBvvHBi.js";import{u as $e,L as J,e as Pe,f as Le}from"./vendor-react-_9U4mKFr.js";function Ae({role:t}){const{data:s}=oe({role:t,limit:100}),a=(s==null?void 0:s.users)??[];return a.length===0?e.jsx("p",{className:"text-2xs text-text-tertiary",children:"Assign users to this role to staff its queue. Members see and resolve escalations here according to their read/write scope; admins manage the role itself."}):e.jsx("div",{className:"divide-y divide-surface-border/40",children:a.map(r=>{const c=r.roles.find(l=>l.role===t);return c?e.jsxs("div",{className:"flex items-center justify-between py-1.5 gap-2",children:[e.jsx("span",{className:"text-xs text-text-secondary truncate",children:r.display_name||r.external_id}),e.jsx("span",{className:"text-2xs text-text-quaternary font-mono shrink-0",children:Re(c)})]},r.id):null})})}function Re(t){return t.type==="superadmin"||t.type==="admin"?t.type:`member · read ${t.read_scope} · write ${t.write_scope}`}function z(t){return t==null?"":JSON.stringify(t,null,2)}function A(t){const s=t.trim();if(!s)return{ok:!0,value:void 0};try{const a=JSON.parse(s);return typeof a!="object"||Array.isArray(a)||a===null?{ok:!1}:{ok:!0,value:a}}catch{return{ok:!1}}}const W=/^[a-zA-Z0-9_]+$/;function Ee(t){var a;const s=A(t);return s.ok&&((a=s.value)==null?void 0:a.kiosk)===!0}function Oe(t){const s=A(t);if(!s.ok)return null;const a={...s.value??{}};return a.kiosk===!0?delete a.kiosk:a.kiosk=!0,JSON.stringify(a,null,2)}const qe={title:"",description:"",ops_visible:!1,ops_home_default:!1,enforce_schema:!1,parent_role:"",metadata_schema:"",properties:"{}",sla_minutes:"",target_per_hour:"",worker_count:"",priority_threshold_minutes:"",priority_facet:"",entity_facet:"",entity_state_source:"role",portals:[]};function Me(t){return{title:t.title??"",description:t.description??"",ops_visible:t.ops_visible,ops_home_default:t.ops_home_default,enforce_schema:t.enforce_schema,parent_role:t.parent_role??"",metadata_schema:z(t.metadata_schema),properties:z(t.properties)||"{}",sla_minutes:t.sla_minutes!=null?String(t.sla_minutes):"",target_per_hour:t.target_per_hour!=null?String(t.target_per_hour):"",worker_count:t.worker_count!=null?String(t.worker_count):"",priority_threshold_minutes:t.priority_threshold_minutes!=null?String(t.priority_threshold_minutes):"",priority_facet:t.priority_facet??"",entity_facet:t.entity_facet??"",entity_state_source:t.entity_state_source??"role",portals:t.portals??[]}}function k({icon:t,label:s,annotation:a,aside:r,accent:c=!1,children:l}){const i=c?"text-accent":"text-text-tertiary";return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-5",children:[e.jsxs("div",{className:"flex items-center gap-1.5 min-w-0",children:[e.jsx(t,{className:`w-3 h-3 ${i} shrink-0`,strokeWidth:1.5}),e.jsx("span",{className:`text-2xs font-semibold uppercase tracking-widest ${i}`,children:s}),a&&e.jsxs("span",{className:"text-2xs text-text-quaternary truncate",children:["— ",a]})]}),r]}),e.jsx("div",{className:`border-l-2 pl-5 ${c?"border-accent/15":"border-surface-border/60"}`,children:l})]})}function G(){return e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("span",{className:"w-2.5 h-2.5 rounded-full dot-ring bg-status-success"}),e.jsx("span",{className:"text-2xs font-semibold uppercase tracking-widest text-status-success",children:"Live"})]})}function I({checked:t,onChange:s,title:a}){return e.jsx("button",{onClick:s,title:a,className:`w-9 h-5 rounded-full transition-colors relative shrink-0 ${t?"bg-accent":"bg-surface-border"}`,children:e.jsx("span",{className:`absolute top-[3px] left-0 w-3.5 h-3.5 rounded-full bg-text-inverse transition-transform shadow ${t?"translate-x-[18px]":"translate-x-[3px]"}`})})}function Te({items:t,empty:s,onRemove:a}){return t.length===0?e.jsx("p",{className:"text-2xs text-text-tertiary leading-relaxed",children:s}):e.jsx("div",{className:"flex flex-wrap gap-1.5",children:t.map(r=>e.jsxs("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 text-2xs bg-accent/10 rounded-sm font-mono text-accent",children:[r,e.jsx("button",{onClick:()=>a(r),className:"text-accent/50 hover:text-status-error transition-colors leading-none ml-0.5",children:"×"})]},r))})}function Be({role:t,draft:s,update:a}){const r=$e(),c=ce(),[l,i]=g.useState(!1),u=t.user_count>0||t.chain_count>0||t.workflow_count>0;return e.jsxs("div",{className:"space-y-14",children:[e.jsx(k,{icon:Q,label:"Identity",annotation:"name and description",accent:!0,children:e.jsxs("div",{className:"space-y-8",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1.5",children:"Display Name"}),e.jsx("input",{type:"text",value:s.title,onChange:d=>a({title:d.target.value}),placeholder:`e.g., ${t.role.charAt(0).toUpperCase()+t.role.slice(1)}`,className:"input text-sm w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1.5",children:"Description"}),e.jsx(be,{value:s.description,onChange:d=>a({description:d}),placeholder:"A short description shown on role cards and in the operations view.",rows:2})]})]})}),e.jsx("div",{className:"border-t border-surface-border/40 pt-6",children:u?e.jsxs("p",{className:"text-2xs text-text-quaternary leading-relaxed",children:["This role is referenced by"," ",[t.user_count>0?`${t.user_count} member${t.user_count===1?"":"s"}`:null,t.workflow_count>0?`${t.workflow_count} workflow${t.workflow_count===1?"":"s"}`:null,t.chain_count>0?"routing config":null].filter(Boolean).join(", ")," ","and cannot be deleted."]}):e.jsxs("button",{onClick:()=>i(!0),className:"px-3 py-1.5 text-xs rounded-md text-status-error/60 hover:text-status-error hover:bg-status-error/10 transition-colors flex items-center gap-1",children:[e.jsx(ge,{className:"w-3 h-3"})," Delete this role"]})}),e.jsx(ve,{open:l,onClose:()=>i(!1),onConfirm:()=>c.mutate(t.role,{onSuccess:()=>r("/admin/roles")}),title:"Delete Role",description:e.jsxs(e.Fragment,{children:["Delete role ",e.jsx("span",{className:"font-medium font-mono text-text-primary",children:t.role}),"? This cannot be undone."]}),isPending:c.isPending,error:c.error})]})}function De({role:t,allRoles:s,draft:a,update:r,errors:c}){const l=parseFloat(a.sla_minutes),i=parseFloat(a.target_per_hour),u=parseFloat(a.worker_count),d=!isNaN(l)&&l>0,v=!isNaN(i)&&i>0,y=!isNaN(u)&&u>0,N=d&&y&&!v?`→ target ≈ ${(u/(l/60)).toFixed(1)}/h`:d&&v&&!y?`→ workers ≈ ${(i*(l/60)).toFixed(1)}`:v&&y&&!d?`→ SLA ≈ ${(u/i*60).toFixed(0)}m`:null,o=g.useMemo(()=>s.filter(n=>{if(n.role===t.role)return!1;let m=n;const b=new Set;for(;m!=null&&m.parent_role;){if(m.parent_role===t.role)return!1;if(b.has(m.parent_role))break;b.add(m.parent_role),m=s.find(w=>w.role===m.parent_role)}return!0}),[s,t]);return e.jsxs("div",{className:"space-y-14",children:[e.jsx(k,{icon:ee,label:"Pace Board",annotation:"this role on the Pace Board",accent:!0,children:e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-xs text-text-secondary",children:"Show this role on the Pace Board"}),e.jsx("p",{className:"text-2xs text-text-tertiary leading-relaxed mt-1",children:"Roles appear on the Operations chart and table with live counts, pace, and the time-in-state mix."})]}),e.jsx(I,{checked:a.ops_visible,onChange:()=>r({ops_visible:!a.ops_visible}),title:"Show this role on the Pace Board"})]})}),e.jsx(k,{icon:H,label:"Capacity",annotation:"throughput = workers / (sla / 60)",children:e.jsxs("div",{className:"flex items-end gap-6",children:[[{key:"sla_minutes",label:"SLA",unit:"min",placeholder:"30"},{key:"target_per_hour",label:"Target",unit:"/h",placeholder:"20"},{key:"worker_count",label:"Workers",unit:"",placeholder:"4"}].map(({key:n,label:m,unit:b,placeholder:w})=>e.jsxs("div",{children:[e.jsxs("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-quaternary mb-1",children:[m,b&&e.jsx("span",{className:"normal-case font-normal ml-1",children:b})]}),e.jsx("input",{type:"number",min:"0",step:"any",value:a[n],onChange:x=>r({[n]:x.target.value}),placeholder:w,className:"input text-xs w-20 font-mono"})]},n)),N&&e.jsx("span",{className:"text-2xs text-accent font-mono whitespace-nowrap pb-2",children:N})]})}),e.jsxs(k,{icon:H,label:"Priority",annotation:"when a pending item counts as overdue",children:[e.jsxs("div",{className:"flex items-end gap-6",children:[e.jsxs("div",{children:[e.jsxs("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-quaternary mb-1",children:["Threshold",e.jsx("span",{className:"normal-case font-normal ml-1",children:"min"})]}),e.jsx("input",{type:"number",min:"0",step:"any",value:a.priority_threshold_minutes,onChange:n=>r({priority_threshold_minutes:n.target.value}),placeholder:a.sla_minutes||"60",className:"input text-xs w-20 font-mono"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-quaternary mb-1",children:"Age Facet"}),e.jsx("input",{type:"text",value:a.priority_facet,onChange:n=>r({priority_facet:n.target.value}),placeholder:"created_at",className:"input text-xs w-36 font-mono"}),c.priority_facet&&e.jsx("p",{className:"text-2xs text-status-error mt-0.5",children:c.priority_facet})]})]}),e.jsxs("p",{className:"text-2xs text-text-tertiary leading-relaxed mt-3",children:["Pending unclaimed items older than the threshold count as priority. Age is measured from the metadata facet (an ISO 8601 UTC timestamp, e.g. ",e.jsx("code",{className:"font-mono",children:"authorized_at"}),") or from"," ",e.jsx("code",{className:"font-mono",children:"created_at"})," when blank; the threshold falls back to SLA when blank."]})]}),e.jsxs(k,{icon:ye,label:"Entity",annotation:"what moves through this role",accent:!0,children:[e.jsx("input",{type:"text",value:a.entity_facet,onChange:n=>r({entity_facet:n.target.value}),placeholder:"serialNumber",className:"input text-xs w-44 font-mono"}),c.entity_facet&&e.jsx("p",{className:"text-2xs text-status-error mt-0.5",children:c.entity_facet}),e.jsxs("p",{className:"text-2xs text-text-tertiary leading-relaxed mt-3",children:["The metadata key naming the entity that moves through this role —"," ",e.jsx("code",{className:"font-mono",children:"serialNumber"}),","," ",e.jsx("code",{className:"font-mono",children:"orderId"}),". Roles sharing a key form that entity's system: its state mix, per-entity dwell, and timelines all derive from it. Blank = the role has no entity notion."]}),a.entity_facet.trim()!==""&&e.jsxs("div",{className:"mt-5",children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-quaternary mb-1.5",children:"States from"}),e.jsx("div",{className:"flex items-center gap-1",children:[{value:"role",label:"Role"},{value:"subtype",label:"Subtypes"}].map(({value:n,label:m})=>e.jsx("button",{onClick:()=>r({entity_state_source:n}),className:`px-2.5 py-1 text-2xs rounded transition-colors ${a.entity_state_source===n?"bg-accent/10 text-accent font-semibold":"icon-link"}`,children:m},n))}),e.jsxs("p",{className:"text-2xs text-text-tertiary leading-relaxed mt-1.5",children:["How this role names the entity's state. ",e.jsx("strong",{children:"Role"}),": being here is one state (a servicing or harvesting queue)."," ",e.jsx("strong",{children:"Subtypes"}),": this one role holds several states, named by each escalation's subtype (a fleet role parking"," ",e.jsx("code",{className:"font-mono",children:"ready"})," /"," ",e.jsx("code",{className:"font-mono",children:"printing"}),")."]})]})]}),e.jsx("div",{className:`overflow-hidden transition-all duration-300 ease-out ${a.ops_visible?"opacity-100 max-h-[900px]":"opacity-0 max-h-0 pointer-events-none"}`,"aria-hidden":!a.ops_visible,children:e.jsx(k,{icon:te,label:"Sequence",annotation:"where this role sits in its segment",children:e.jsxs("div",{className:"space-y-8",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1.5",children:"Prior Step"}),e.jsxs("select",{value:a.parent_role,onChange:n=>r({parent_role:n.target.value}),className:"select text-sm w-full font-mono",children:[e.jsx("option",{value:"",children:"None — root process"}),o.map(n=>e.jsx("option",{value:n.role,children:n.title?`${n.role} — ${n.title}`:n.role},n.role))]}),e.jsx("p",{className:"text-2xs text-text-tertiary leading-relaxed mt-1.5",children:"Places this role in one Pace Board sequence. A role with no prior step starts its own sequence."})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-1.5",children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary",children:"Upstream Inputs"}),e.jsx(G,{})]}),e.jsx(Ie,{role:t,allRoles:s})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsx("label",{className:"block text-2xs font-semibold uppercase tracking-widest text-text-tertiary",children:"Home Segment"}),e.jsx(I,{checked:a.ops_home_default,onChange:()=>r({ops_home_default:!a.ops_home_default}),title:"Lead the home Pace Board with this role's sequence"})]}),e.jsx("p",{className:"text-2xs text-text-tertiary leading-relaxed mt-1.5",children:"Lead the home page's Pace Board with this role's sequence. One role holds this — saving it here releases the previous holder. Unset everywhere, the board opens on its first sequence."})]})]})})})]})}function Ie({role:t,allRoles:s}){const a=U(),[r,c]=g.useState(""),l=t.upstream_roles??[],i=g.useMemo(()=>s.map(d=>d.role).filter(d=>d!==t.role&&d!=="superadmin"&&!l.includes(d)),[s,t.role,l]),u=d=>a.mutate({role:t.role,upstream_roles:d},{onSuccess:()=>c("")});return e.jsxs("div",{className:"space-y-2",children:[i.length>0&&e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("select",{value:r,onChange:d=>c(d.target.value),className:"select text-xs font-mono flex-1",children:[e.jsx("option",{value:"",children:"Add upstream input…"}),i.map(d=>e.jsx("option",{value:d,children:d},d))]}),e.jsx("button",{onClick:()=>{r&&u([...l,r])},disabled:!r||a.isPending,className:"px-2.5 py-1 text-xs rounded bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed shrink-0",children:a.isPending?"…":"Add"})]}),e.jsx(Te,{items:l,empty:"Roles from other sequences this role draws input from. Add one above and it lands here.",onRemove:d=>u(l.filter(v=>v!==d))}),a.error&&e.jsx("p",{className:"text-2xs text-status-error",children:a.error.message})]})}function Ue({role:t,draft:s,update:a,errors:r,editingJson:c,startEditingJson:l,setMetadataSchemaError:i}){return e.jsxs("div",{className:"space-y-14",children:[e.jsx(k,{icon:je,label:"Enforcement",annotation:"server-side resolver validation",accent:!0,children:e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-xs text-text-secondary",children:"Enforce the escalation form schema"}),e.jsx("p",{className:"text-2xs text-text-tertiary leading-relaxed mt-1",children:"Every resolve surface — API, MCP, CLI — validates submitted payloads against this role's form schema and rejects violations with field-level errors before any state changes."})]}),e.jsx(I,{checked:s.enforce_schema,onChange:()=>a({enforce_schema:!s.enforce_schema}),title:"Validate every resolve payload against this role's form schema"})]})}),e.jsxs(k,{icon:D,label:"Escalation Schema",annotation:"the resolve form",accent:!0,aside:t.current_schema_version!=null?e.jsxs("span",{className:"text-2xs font-mono text-text-quaternary",children:["v",t.current_schema_version," in use"]}):void 0,children:[e.jsxs("p",{className:"text-2xs text-text-tertiary mb-3 leading-relaxed",children:["The form a person completes to resolve this role's escalations. Versioned — each save adds one; workflows pin any version via"," ",e.jsx("code",{className:"font-mono",children:"schemaVersion"}),"."]}),e.jsx(J,{to:`/admin/roles/${encodeURIComponent(t.role)}/schema`,className:"text-xs text-accent hover:underline",children:t.form_schema?`Open schema editor — v${t.current_schema_version??1} in use →`:"Define the escalation form →"})]}),e.jsxs(k,{icon:Ne,label:"Escalations List Schema",annotation:"rich list view",aside:t.current_list_schema_version!=null?e.jsxs("span",{className:"text-2xs font-mono text-text-quaternary",children:["v",t.current_list_schema_version," in use"]}):void 0,children:[e.jsx("p",{className:"text-2xs text-text-tertiary mb-3 leading-relaxed",children:"Richly formats the escalation list when it's scoped to just this role. Versioned on its own timeline — separate from the resolve form."}),e.jsx(J,{to:`/admin/roles/${encodeURIComponent(t.role)}/list-schema`,className:"text-xs text-accent hover:underline",children:t.list_schema?`Open list schema editor — v${t.current_list_schema_version??1} in use →`:"Define the list view →"})]}),e.jsxs(k,{icon:D,label:"Metadata Schema",annotation:"validates metadata at creation",aside:!c.has("metadata_schema")&&t.metadata_schema?e.jsx("button",{onClick:()=>l("metadata_schema"),className:"text-2xs text-accent hover:underline",children:"Edit"}):void 0,children:[e.jsxs("p",{className:"text-2xs text-text-tertiary mb-3 leading-relaxed",children:["Validates ",e.jsx("code",{className:"font-mono",children:"metadata"})," at creation time. Keys appear in faceted search autocomplete."]}),!c.has("metadata_schema")&&t.metadata_schema?e.jsx(de,{data:t.metadata_schema}):e.jsxs(e.Fragment,{children:[e.jsx("textarea",{value:s.metadata_schema,onChange:u=>{const d=u.target.value;a({metadata_schema:d}),i(A(d).ok?void 0:"Invalid JSON")},rows:10,spellCheck:!1,className:"input text-xs font-mono w-full resize-y",placeholder:`{
|
|
2
|
-
"type": "object",
|
|
3
|
-
"properties": {
|
|
4
|
-
"order_id": { "type": "string" }
|
|
5
|
-
},
|
|
6
|
-
"required": ["order_id"]
|
|
7
|
-
}`}),r.metadata_schema&&e.jsx("p",{className:"text-2xs text-status-error mt-1",children:r.metadata_schema})]})]})]})}function Fe({role:t}){return e.jsxs("div",{className:"space-y-14",children:[e.jsx(k,{icon:D,label:"Link Variables",annotation:"facet names members bind per device — pins reference them as {lt:name}",aside:e.jsx(G,{}),children:e.jsx(Ke,{role:t})}),e.jsx(k,{icon:se,label:"Default Pins",annotation:"pinned views every member starts with",aside:e.jsx(G,{}),accent:!0,children:e.jsx(Je,{role:t})})]})}function Ve(t){var a;const s=(a=t.properties)==null?void 0:a.link_variables;return Array.isArray(s)?s.filter(r=>typeof(r==null?void 0:r.name)=="string"):[]}function Ke({role:t}){const s=U(),[a,r]=g.useState(""),[c,l]=g.useState(""),[i,u]=g.useState(""),d=Ve(t),v=o=>s.mutate({role:t.role,properties:{...t.properties??{},link_variables:o.length?o:void 0}},{onSuccess:()=>{r(""),l(""),u("")}}),y=a.trim(),N=W.test(y)&&!d.some(o=>o.name===y);return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"text",value:a,onChange:o=>r(o.target.value),placeholder:"facet name — e.g. region",className:"input text-xs font-mono w-40 shrink-0"}),e.jsx("input",{type:"text",value:c,onChange:o=>l(o.target.value),placeholder:"label (optional)",className:"input text-xs flex-1"}),e.jsx("input",{type:"text",value:i,onChange:o=>u(o.target.value),placeholder:"default (optional)",className:"input text-xs font-mono w-36 shrink-0"}),e.jsx("button",{onClick:()=>{N&&v([...d,{name:y,...c.trim()?{label:c.trim()}:{},...i.trim()?{default:i.trim()}:{}}])},disabled:!N||s.isPending,className:"px-2.5 py-1 text-xs rounded bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed shrink-0",children:s.isPending?"…":"Add"})]}),d.length===0?e.jsxs("p",{className:"text-2xs text-text-tertiary leading-relaxed",children:["Facet names members bind per device. A pin below can then carry",e.jsxs("span",{className:"font-mono",children:[' facets={"region":"',"{lt:region}",'"} ']}),"and each device opens it scoped to its own value."]}):e.jsx("div",{className:"divide-y divide-surface-border/60",children:d.map(o=>e.jsxs("div",{className:"flex items-baseline gap-3 py-2.5 text-2xs","data-testid":"link-var-decl",children:[e.jsx("span",{className:"font-mono font-medium text-text-secondary shrink-0",children:o.name}),o.label&&e.jsx("span",{className:"text-text-quaternary truncate",children:o.label}),e.jsx("span",{className:"font-mono text-text-quaternary truncate flex-1",children:o.default?`default: ${o.default}`:"no default — unset drops the facet"}),e.jsx("span",{className:"font-mono text-text-quaternary shrink-0",title:"Reference in a pin URL",children:xe(o.name)}),e.jsx("button",{onClick:()=>v(d.filter(n=>n.name!==o.name)),className:"text-text-quaternary hover:text-status-error transition-colors leading-none shrink-0","aria-label":`Remove variable ${o.name}`,children:"×"})]},o.name))}),s.error&&e.jsx("p",{className:"text-2xs text-status-error",children:s.error.message})]})}function Je({role:t}){const s=U(),[a,r]=g.useState(""),[c,l]=g.useState(""),[i,u]=g.useState(!0),{values:d,defaults:v}=Y(),y=t.default_pins??[],N=n=>s.mutate({role:t.role,default_pins:n.length?n:null},{onSuccess:()=>{r(""),l(""),u(!0)}}),o=a.trim()!==""&&c.trim().startsWith("/");return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"text",value:a,onChange:n=>r(n.target.value),placeholder:"Label — e.g. Needs harvesting",className:"input text-xs w-40 shrink-0"}),e.jsx("input",{type:"text",value:c,onChange:n=>l(n.target.value),placeholder:'/escalations/available?role=… or …facets={"region":"{lt:region}"}',className:"input text-xs font-mono flex-1"}),e.jsxs("label",{className:"flex items-center gap-1 text-2xs text-text-tertiary shrink-0",title:"Show a live count beside the label",children:[e.jsx("input",{type:"checkbox",checked:i,onChange:n=>u(n.target.checked),className:"w-3 h-3 accent-accent"}),"count"]}),e.jsx("button",{onClick:()=>{o&&N([...y,{label:a.trim(),url:c.trim(),badge:i}])},disabled:!o||s.isPending,className:"px-2.5 py-1 text-xs rounded bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed shrink-0",children:s.isPending?"…":"Add"})]}),y.length===0?e.jsx("p",{className:"text-2xs text-text-tertiary leading-relaxed",children:"Pinned views every member starts with — the persona's exact queries. Add one above and it lands here."}):e.jsx("div",{className:"divide-y divide-surface-border/60",children:y.map(n=>{const m=Z(n.url);return e.jsxs("div",{className:"py-2.5",children:[e.jsxs("div",{className:"flex items-baseline gap-3 text-2xs",children:[e.jsx("span",{className:"font-medium text-text-secondary shrink-0",children:n.label}),n.badge&&e.jsx("span",{className:"text-2xs text-accent shrink-0",title:"Shows a live count",children:"count"}),e.jsx("span",{className:"font-mono text-text-quaternary truncate flex-1",title:n.url,children:n.url}),e.jsx("button",{onClick:()=>N(y.filter(b=>b.label!==n.label)),className:"text-text-quaternary hover:text-status-error transition-colors leading-none shrink-0","aria-label":`Remove pin ${n.label}`,children:"×"})]}),m.length>0&&e.jsxs("p",{className:"mt-1.5 font-mono text-2xs text-text-tertiary","data-testid":"pin-binding-caption",children:[m.map(b=>{const w=d[b]??v[b];return`${b} = ${w?`'${w}'`:"<empty>"}`}).join(", "),e.jsx("span",{className:"font-sans",children:" on this device"})]})]},n.label)})}),s.error&&e.jsx("p",{className:"text-2xs text-status-error",children:s.error.message})]})}const $={ROLE:"role",MINE:"mine",CUSTOM:"custom"},K="border border-surface-border bg-surface-sunken rounded-[var(--lt-radius-section)] overflow-hidden",We="flex items-center gap-3 px-4 py-2.5 border-b border-surface-border bg-surface-hover",Ge="flex items-center gap-2 px-3 py-2 border-b border-surface-border bg-surface-hover",T="border border-dashed border-surface-border rounded-[var(--lt-radius-section)] flex items-center justify-center p-3 min-w-0 overflow-hidden";function He(t){const s=pe(t);if(!s)return"page";const a=s.view??"default";return s.layout?`${a} · ${s.layout}`:a}function Xe({role:t,draft:s,update:a}){const{data:r}=me(),{values:c,defaults:l}=Y(),i=s.portals,[u,d]=g.useState(""),v=g.useMemo(()=>{var n;return[...(t.default_pins??[]).map((m,b)=>({key:`${$.ROLE}:${b}`,source:$.ROLE,pin:m})),...(((n=r==null?void 0:r.preferences)==null?void 0:n.pinnedViews)??[]).map(m=>({key:`${$.MINE}:${m.id}`,source:$.MINE,pin:{label:m.label,url:m.url,badge:m.badge}}))]},[t.default_pins,r]),y=n=>a({portals:n}),N=(n,m)=>y(i.flatMap((b,w)=>w===n?m?[m]:[]:[b])),o=n=>{const m=u.trim()||`Portal ${i.length+1}`;y([...i,{key:he(m,i.map(b=>b.key)),label:m,rows:[[n]]}]),d("")};return e.jsx(k,{icon:ae,label:"Portals",annotation:"named pages of pinned views, one row of panels per matrix row",accent:!0,children:e.jsxs("div",{className:"space-y-6",children:[i.length===0&&e.jsx("p",{className:"text-2xs text-text-tertiary leading-relaxed",children:"A portal lays pins out as one page: one row with one view fills the screen, a row with three views splits it into three columns. Give a role several: urgent items by facility for the floor screen, the day's focus for the team with a panel per person. Members choose one from the global menu; a kiosk role lands on the first. Save writes the portals with the rest of the role."}),i.map((n,m)=>e.jsx(ze,{role:t.role,portal:n,options:v,bindings:{values:c,defaults:l},onChange:b=>N(m,b)},n.key)),i.length<O.MAX_PORTALS&&e.jsxs("div",{className:`${T} flex-wrap gap-3 py-5`,"data-testid":"new-portal",children:[e.jsx("span",{className:"text-2xs font-semibold uppercase tracking-widest text-text-quaternary",children:"New portal"}),e.jsx("input",{type:"text",value:u,onChange:n=>d(n.target.value),placeholder:"Name, e.g. Focus of the day",className:"input text-xs w-52 shrink-0","aria-label":"New portal name"}),e.jsx(B,{options:v,label:"Start it with a view",onPick:o,testId:"add-portal"})]})]})})}function ze({role:t,portal:s,options:a,bindings:r,onChange:c}){const[l,i]=g.useState(s.label),u=s.rows,d=x=>{const p=x.filter(h=>h.length>0);c(p.length?{...s,rows:p}:null)},v=(x,p)=>{const h=u.map(f=>[...f]);x>=h.length?h.push([p]):h[x].push(p),d(h)},y=(x,p)=>{const h=u.map(f=>[...f]);h[x].splice(p,1),d(h)},N=(x,p,h)=>{if(!h.trim())return;const f=u.map(P=>P.map(S=>({...S})));f[x][p].label=h.trim(),c({...s,rows:f})},o=()=>{const x=l.trim();if(!x){i(s.label);return}x!==s.label&&c({...s,label:x})},n=s.counts??[],m=x=>c(x.length?{...s,counts:x}:(({counts:p,...h})=>h)(s)),b=x=>m([...n,{label:x.label,url:x.url}]),w=(x,p)=>m(n.map((h,f)=>f===x?{...h,...p}:h));return e.jsxs("section",{className:K,"data-testid":`portal-${s.key}`,children:[e.jsxs("div",{className:We,children:[e.jsx(Ye,{rows:u}),e.jsx("input",{type:"text",value:l,onChange:x=>i(x.target.value),onBlur:o,onKeyDown:x=>{x.key==="Enter"&&x.target.blur()},className:"input text-xs w-52","aria-label":`Portal name for ${s.key}`}),e.jsx("span",{className:"font-mono text-2xs text-text-quaternary truncate",title:"The portal's address segment",children:s.key}),e.jsxs(J,{to:ue(t,s.key),className:"ml-auto inline-flex items-center gap-1 text-2xs text-accent hover:underline shrink-0","data-testid":`open-portal-${s.key}`,children:["Open ",e.jsx(ke,{className:"w-3 h-3",strokeWidth:1.5})]}),e.jsx("button",{onClick:()=>c(null),className:"text-text-quaternary hover:text-status-error transition-colors leading-none shrink-0","aria-label":`Remove portal ${s.label}`,title:"Remove this portal",children:"×"})]}),e.jsxs("div",{className:"p-4 space-y-4",children:[e.jsxs("div",{className:"grid gap-3",style:{gridTemplateColumns:`repeat(${n.length}, minmax(0, 1fr))${n.length<O.MAX_COUNTS?" 12rem":""}`},"data-testid":`portal-${s.key}-counts`,children:[n.map((x,p)=>e.jsxs("div",{className:`${K} min-w-0 bg-surface-raised px-3 py-2 space-y-1.5`,"data-testid":`portal-${s.key}-count-${p}`,children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"text",defaultValue:x.label,onBlur:h=>{h.target.value.trim()&&w(p,{label:h.target.value.trim()})},onKeyDown:h=>{h.key==="Enter"&&h.target.blur()},className:"input text-2xs py-0.5 px-1.5 min-w-0 flex-1 uppercase tracking-widest","aria-label":`Count title ${p+1} of ${s.label}`}),e.jsx("button",{onClick:()=>m(n.filter((h,f)=>f!==p)),className:"text-text-quaternary hover:text-status-error transition-colors leading-none shrink-0","aria-label":`Remove count ${x.label} from ${s.label}`,title:"Remove this count",children:"×"})]}),e.jsx("input",{type:"text",defaultValue:x.blurb??"",onBlur:h=>w(p,{blurb:h.target.value.trim()||void 0}),onKeyDown:h=>{h.key==="Enter"&&h.target.blur()},placeholder:"One line under the number",className:"input text-xs py-0.5 px-1.5 w-full","aria-label":`Count blurb ${p+1} of ${s.label}`}),e.jsx("p",{className:"font-mono text-2xs text-text-quaternary truncate",title:x.url,children:x.url})]},`${x.url}-${p}`)),n.length<O.MAX_COUNTS&&e.jsx("div",{className:T,children:e.jsx(B,{options:a,label:n.length===0?"Add a count above the panels":"Add a count",onPick:b,testId:`add-count-${s.key}`})})]}),u.map((x,p)=>{const h=x.length<O.MAX_COLS;return e.jsxs("div",{className:"grid gap-3",style:{gridTemplateColumns:`repeat(${x.length}, minmax(0, 1fr))${h?" 12rem":""}`},"data-testid":`portal-${s.key}-row-${p}`,children:[x.map((f,P)=>{const S=Z(f.url);return e.jsxs("div",{className:`${K} min-w-0 bg-surface-raised`,"data-testid":`portal-${s.key}-cell-${p}-${P}`,children:[e.jsxs("div",{className:Ge,children:[e.jsx("input",{type:"text",defaultValue:f.label,onBlur:C=>N(p,P,C.target.value),onKeyDown:C=>{C.key==="Enter"&&C.target.blur()},className:"input text-xs py-0.5 px-1.5 min-w-0 flex-1 font-medium","aria-label":`Panel title for row ${p+1} cell ${P+1}`,title:"The panel's title; rename it for the person or place it serves"}),e.jsx("span",{className:"text-2xs text-accent shrink-0",title:"The view this pin asks for",children:He(f.url)}),e.jsx("button",{onClick:()=>y(p,P),className:"text-text-quaternary hover:text-status-error transition-colors leading-none shrink-0","aria-label":`Remove ${f.label} from row ${p+1} of ${s.label}`,title:"Remove this panel",children:"×"})]}),e.jsxs("div",{className:"px-3 py-2 space-y-0.5",children:[e.jsx("p",{className:"font-mono text-2xs text-text-quaternary truncate",title:f.url,children:f.url}),S.length>0&&e.jsxs("p",{className:"font-mono text-2xs text-text-quaternary",children:[S.map(C=>{const q=r.values[C]??r.defaults[C];return`${C} = ${q?`'${q}'`:"<empty>"}`}).join(", "),e.jsx("span",{className:"font-sans",children:" on this device"})]})]})]},`${p}-${P}`)}),h&&e.jsx("div",{className:T,children:e.jsx(B,{options:a,label:"Add a view to this row",onPick:f=>v(p,f),testId:`add-cell-${s.key}-${p}`})})]},p)}),u.length<O.MAX_ROWS&&e.jsx("div",{className:`${T} py-4`,children:e.jsx(B,{options:a,label:"Start a new row with a view",onPick:x=>v(u.length,x),testId:`add-row-${s.key}`})})]})]})}function Ye({rows:t}){return e.jsx("div",{className:"flex flex-col gap-0.5 w-14 shrink-0","aria-hidden":!0,"data-testid":"portal-sketch",children:t.map((s,a)=>e.jsx("div",{className:"flex gap-0.5",children:s.map((r,c)=>e.jsx("span",{className:"flex-1 h-1.5 rounded-sm bg-accent/40",title:r.label},c))},a))})}function B({options:t,label:s,onPick:a,testId:r}){const[c,l]=g.useState(!1),[i,u]=g.useState(""),[d,v]=g.useState(""),y=i.trim()!==""&&d.trim().startsWith("/"),N=o=>{if(o===$.CUSTOM){l(!0);return}const n=t.find(m=>m.key===o);n&&a(n.pin)};return e.jsxs("div",{className:"space-y-1.5 w-full min-w-0",children:[e.jsxs("select",{value:"",onChange:o=>N(o.target.value),className:"select text-xs w-full","aria-label":s,"data-testid":r,children:[e.jsxs("option",{value:"",disabled:!0,children:[s,"…"]}),t.some(o=>o.source===$.ROLE)&&e.jsx("optgroup",{label:"Role pins",children:t.filter(o=>o.source===$.ROLE).map(o=>e.jsx("option",{value:o.key,children:o.pin.label},o.key))}),t.some(o=>o.source===$.MINE)&&e.jsx("optgroup",{label:"My pins",children:t.filter(o=>o.source===$.MINE).map(o=>e.jsx("option",{value:o.key,children:o.pin.label},o.key))}),e.jsx("option",{value:$.CUSTOM,children:"Label and URL…"})]}),c&&e.jsxs("div",{className:"flex flex-col gap-1.5","data-testid":`${r}-custom`,children:[e.jsx("input",{type:"text",value:i,onChange:o=>u(o.target.value),placeholder:"Label",className:"input text-xs w-full","aria-label":"View label"}),e.jsx("input",{type:"text",value:d,onChange:o=>v(o.target.value),placeholder:"/escalations/available?role=…",className:"input text-xs font-mono w-full","aria-label":"View URL"}),e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx("button",{type:"button",onClick:()=>{l(!1),u(""),v("")},className:"px-2 py-1 text-xs text-text-tertiary hover:text-text-primary transition-colors",children:"Cancel"}),e.jsx("button",{type:"button",onClick:()=>{y&&(a({label:i.trim(),url:d.trim(),badge:!0}),l(!1),u(""),v(""))},disabled:!y,className:"px-2.5 py-1 text-xs rounded bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed shrink-0",children:"Add"})]})]})]})}function re(t){var r;const s=A(t),a=s.ok?(r=s.value)==null?void 0:r.badge_grant:void 0;return a&&typeof a=="object"&&!Array.isArray(a)?a:null}function Ze(t,s){const a=A(t);if(!a.ok)return null;const r={...a.value??{}},c={...re(t)??{},...s};for(const l of Object.keys(c))c[l]===void 0&&delete c[l];return Object.keys(c).length?r.badge_grant=c:delete r.badge_grant,JSON.stringify(r,null,2)}function Qe({draft:t,update:s}){const a=re(t.properties)??{},r=l=>{const i=Ze(t.properties,l);i!==null&&s({properties:i})},c=l=>l===""?void 0:Number(l);return e.jsxs(k,{icon:we,label:"Badge at this station",annotation:"how long a badge scan lasts here",children:[e.jsx("p",{className:"text-2xs text-text-tertiary leading-relaxed mb-3",children:"A badge scanned on a device signed in to this role mints under this policy. Leave a field empty to keep the badge scheme's own value."}),e.jsxs("div",{className:"flex flex-wrap gap-4",children:[e.jsxs("label",{className:"block",children:[e.jsx("span",{className:"block text-xs text-text-secondary mb-1",children:"Lasts (seconds)"}),e.jsx("span",{className:"block text-2xs text-text-tertiary mb-1",children:"1–86400; 600 is ten minutes."}),e.jsx("input",{type:"number",min:1,max:86400,value:a.ttl_seconds??"",onChange:l=>r({ttl_seconds:c(l.target.value)}),className:"input w-[12rem]","aria-label":"Badge lasts (seconds)"})]}),e.jsxs("label",{className:"block",children:[e.jsx("span",{className:"block text-xs text-text-secondary mb-1",children:"Acts per badge scan"}),e.jsx("span",{className:"block text-2xs text-text-tertiary mb-1",children:"0 = as many as fit in the time; 1 = one act per scan."}),e.jsx("input",{type:"number",min:0,value:a.max_uses??"",onChange:l=>r({max_uses:c(l.target.value)}),className:"input w-[12rem]","aria-label":"Acts per badge scan"})]})]})]})}const le=[{key:"identity",label:"Identity",icon:Q},{key:"pace-board",label:"Pace Board",icon:ee},{key:"schemas",label:"Schemas",icon:D},{key:"members",label:"Members",icon:ne},{key:"pins",label:"Pins",icon:se},{key:"portal",label:"Portal",icon:ae}],et=t=>le.some(s=>s.key===t);function it(){const{role:t}=Pe(),{data:s,isLoading:a}=fe(),r=U(),c=(s==null?void 0:s.roles)??[],l=c.find(j=>j.role===t),[i,u]=g.useState(qe),[d,v]=g.useState(!1),[y,N]=g.useState(!1),[o,n]=g.useState({}),[m,b]=g.useState(new Set),w=j=>b(_=>new Set([..._,j])),[x,p]=Le(),h=x.get("section"),f=et(h)?h:"identity",P=g.useCallback(j=>{p(_=>{const L=new URLSearchParams(_);return L.set("section",j),L},{replace:!0})},[p]);g.useEffect(()=>{l&&(u(Me(l)),v(!1),N(!1),n({}),b(new Set))},[t,l==null?void 0:l.role]);const S=j=>{u(_=>({..._,...j})),v(!0),N(!1)},C=()=>{if(!l)return;const j=A(i.metadata_schema),_=A(i.properties),L=i.priority_facet.trim(),F=i.entity_facet.trim(),R={};if(j.ok||(R.metadata_schema="Invalid JSON"),_.ok||(R.properties="Invalid JSON"),L&&!W.test(L)&&(R.priority_facet="Letters, numbers, underscores only"),F&&!W.test(F)&&(R.entity_facet="Letters, numbers, underscores only"),n(R),Object.keys(R).length)return;const M=V=>{const E=parseFloat(V);return isNaN(E)?null:E},ie=V=>{const E=M(V);return E==null?null:Math.round(E)};r.mutate({role:l.role,title:i.title.trim()||null,description:i.description.trim()||null,ops_visible:i.ops_visible,ops_home_default:i.ops_home_default,enforce_schema:i.enforce_schema,parent_role:i.parent_role||null,metadata_schema:j.value??null,properties:_.value??{},sla_minutes:M(i.sla_minutes),target_per_hour:M(i.target_per_hour),worker_count:ie(i.worker_count),priority_threshold_minutes:M(i.priority_threshold_minutes),priority_facet:L||null,entity_facet:F||null,entity_state_source:i.entity_state_source,portals:i.portals.length?i.portals:null},{onSuccess:()=>{v(!1),N(!0),b(new Set),window.setTimeout(()=>N(!1),2500)}})};if(a)return e.jsxs("div",{className:"animate-pulse space-y-4",children:[e.jsx("div",{className:"h-8 bg-surface-sunken rounded w-48"}),e.jsx("div",{className:"h-4 bg-surface-sunken rounded w-64"}),e.jsx("div",{className:"h-64 bg-surface-sunken rounded"})]});if(!l)return e.jsxs("div",{className:"flex flex-col items-center justify-center py-20 text-center",children:[e.jsx(X,{className:"w-12 h-12 text-text-quaternary mb-4",strokeWidth:1}),e.jsx("h2",{className:"heading-3 mb-2",children:"Role not found"})]});const q=d&&!Object.values(o).some(Boolean);return e.jsxs("div",{children:[e.jsxs("div",{className:"mb-10 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-1",children:[e.jsx(X,{className:"w-5 h-5 text-accent",strokeWidth:1.5}),e.jsx("h1",{className:"text-lg font-mono font-medium text-text-primary",children:l.role}),e.jsx("button",{onClick:()=>{window.location.hash="#docs:dashboard.md:role-detail"},className:"text-text-quaternary hover:text-accent transition-colors",title:"Open docs for this page",children:e.jsx(_e,{className:"w-4 h-4",strokeWidth:1.5})}),l.parent_role&&e.jsxs("span",{className:"flex items-center gap-1 text-2xs text-text-quaternary font-mono",children:[e.jsx(te,{className:"w-3 h-3"})," ",l.parent_role]})]}),l.title&&e.jsx("p",{className:"text-sm text-text-secondary pl-8",children:l.title})]}),e.jsxs("div",{className:"flex gap-10",children:[e.jsxs("nav",{className:"w-44 shrink-0 sticky top-0 self-start pt-2",children:[e.jsx("div",{className:"space-y-0.5",children:le.map(j=>{const _=j.icon,L=f===j.key;return e.jsxs("button",{onClick:()=>P(j.key),className:`w-full flex items-center gap-2.5 px-3 py-2 rounded-md text-left transition-colors ${L?"bg-accent/10 text-accent":"text-text-tertiary hover:text-text-primary hover:bg-surface-hover"}`,children:[e.jsx(_,{className:"w-3.5 h-3.5 shrink-0",strokeWidth:1.5}),e.jsx("span",{className:"text-xs font-medium",children:j.label})]},j.key)})}),e.jsxs("div",{className:"mt-8 pt-4 border-t border-surface-border space-y-2",children:[e.jsx("button",{onClick:C,disabled:!q||r.isPending,className:"w-full px-3 py-1.5 text-xs rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed",children:r.isPending?"Saving…":d?"Save changes":"Save"}),y&&e.jsxs("span",{className:"flex items-center justify-center gap-1 text-xs text-status-success animate-page-enter",children:[e.jsx(Se,{className:"w-3 h-3"})," Saved"]}),r.error&&e.jsx("p",{className:"text-2xs text-status-error leading-relaxed",children:r.error.message}),Object.values(o).some(Boolean)&&e.jsx("p",{className:"text-2xs text-status-error leading-relaxed",children:"Fix the highlighted fields before saving."})]})]}),e.jsxs("div",{className:`flex-1 min-w-0 pt-2 ${f==="portal"?"":"max-w-3xl"}`,children:[f==="identity"&&e.jsx(Be,{role:l,draft:i,update:S,errors:o}),f==="pace-board"&&e.jsx(De,{role:l,allRoles:c,draft:i,update:S,errors:o}),f==="schemas"&&e.jsx(Ue,{role:l,draft:i,update:S,errors:o,editingJson:m,startEditingJson:w,setMetadataSchemaError:j=>n(_=>({..._,metadata_schema:j}))}),f==="members"&&e.jsxs("div",{className:"space-y-14",children:[e.jsx(k,{icon:ne,label:"Members",annotation:"read = what appears · write = what they can act on",accent:!0,children:e.jsx(Ae,{role:l.role})}),e.jsx(k,{icon:Ce,label:"Kiosk",annotation:"the locked viewport for single-role logins",children:e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-xs text-text-secondary",children:"Lock single-role members to this queue"}),e.jsx("p",{className:"text-2xs text-text-tertiary leading-relaxed mt-1",children:"A member who holds only this role signs in to a locked viewport: no side navigation, this queue as home, held to the list, the item detail, and the scan screens. Members with other roles keep the full dashboard."})]}),e.jsx(I,{checked:Ee(i.properties),onChange:()=>{const j=Oe(i.properties);j!==null&&S({properties:j})},title:"Kiosk viewport"})]})}),e.jsx(Qe,{draft:i,update:S})]}),f==="pins"&&e.jsx(Fe,{role:l}),f==="portal"&&e.jsx(Xe,{role:l,draft:i,update:S})]})]})]})}export{it as RoleDetailPage};
|
|
8
|
-
//# sourceMappingURL=RoleDetailPage-D_30TDVh.js.map
|