@hotmeshio/long-tail 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -2
- package/build/api/settings.d.ts +4 -1
- package/build/api/settings.js +7 -1
- package/build/index.d.ts +4 -0
- package/build/index.js +35 -8
- package/build/lib/db/config-lock.d.ts +10 -0
- package/build/lib/db/config-lock.js +28 -0
- package/build/lib/db/schemas/041_machine_lines.sql +26 -0
- package/build/lib/events/browser-view.js +8 -2
- package/build/lib/events/nats.d.ts +11 -0
- package/build/lib/events/nats.js +33 -2
- package/build/lib/events/publish.d.ts +33 -0
- package/build/lib/events/publish.js +52 -1
- package/build/lib/machines/index.d.ts +1 -0
- package/build/lib/machines/index.js +1 -0
- package/build/lib/machines/line.d.ts +4 -1
- package/build/lib/machines/line.js +18 -1
- package/build/lib/machines/protocol/codec.d.ts +24 -0
- package/build/lib/machines/protocol/codec.js +10 -0
- package/build/lib/machines/protocol/constants.d.ts +1 -1
- package/build/lib/machines/protocol/constants.js +1 -1
- package/build/lib/machines/protocol/contract.js +12 -3
- package/build/lib/machines/site/edge-account.d.ts +11 -0
- package/build/lib/machines/site/edge-account.js +24 -0
- package/build/lib/machines/site/mosquitto-conf.d.ts +5 -4
- package/build/lib/machines/site/mosquitto-conf.js +31 -16
- package/build/lib/machines/site/site-conf.d.ts +16 -6
- package/build/lib/machines/site/site-conf.js +39 -13
- package/build/lib/machines/transport/callback-feed.d.ts +1 -0
- package/build/lib/machines/transport/callback-feed.js +4 -1
- package/build/lib/machines/transport/delivery.d.ts +3 -4
- package/build/lib/machines/transport/delivery.js +3 -8
- package/build/lib/machines/transport/index.d.ts +2 -0
- package/build/lib/machines/transport/index.js +2 -0
- package/build/lib/machines/transport/memory.d.ts +2 -0
- package/build/lib/machines/transport/memory.js +6 -0
- package/build/lib/machines/transport/mqtt-bus.d.ts +2 -0
- package/build/lib/machines/transport/mqtt-bus.js +4 -0
- package/build/lib/machines/transport/nats-bus.d.ts +8 -13
- package/build/lib/machines/transport/nats-bus.js +26 -43
- package/build/lib/machines/transport/nats-feed.d.ts +1 -0
- package/build/lib/machines/transport/nats-feed.js +6 -3
- package/build/lib/machines/transport/pubsub-feed.d.ts +18 -0
- package/build/lib/machines/transport/pubsub-feed.js +42 -0
- package/build/lib/machines/transport/stream-bus.d.ts +42 -0
- package/build/lib/machines/transport/stream-bus.js +61 -0
- package/build/lib/machines/transport/streams.d.ts +10 -14
- package/build/lib/machines/transport/streams.js +18 -61
- package/build/lib/messaging/config.d.ts +25 -0
- package/build/lib/messaging/config.js +55 -0
- package/build/lib/messaging/constants.d.ts +26 -0
- package/build/lib/messaging/constants.js +26 -0
- package/build/lib/messaging/index.d.ts +24 -0
- package/build/lib/messaging/index.js +65 -0
- package/build/lib/messaging/memory.d.ts +16 -0
- package/build/lib/messaging/memory.js +147 -0
- package/build/lib/messaging/nats/permissions.d.ts +13 -0
- package/build/lib/messaging/nats/permissions.js +22 -0
- package/build/lib/messaging/nats/provider.d.ts +30 -0
- package/build/lib/messaging/nats/provider.js +77 -0
- package/build/lib/messaging/nats/render-conf.d.ts +68 -0
- package/build/lib/messaging/nats/render-conf.js +58 -0
- package/build/lib/messaging/nats/streams.d.ts +26 -0
- package/build/lib/messaging/nats/streams.js +97 -0
- package/build/lib/messaging/subjects.d.ts +8 -0
- package/build/lib/messaging/subjects.js +25 -0
- package/build/modules/machines.d.ts +8 -0
- package/build/modules/machines.js +16 -0
- package/build/routes/index.js +2 -0
- package/build/routes/machines.d.ts +2 -0
- package/build/routes/machines.js +220 -0
- package/build/scripts/bambu-boat.d.ts +17 -0
- package/build/scripts/bambu-boat.js +134 -0
- package/build/scripts/bambu-print.d.ts +18 -0
- package/build/scripts/bambu-print.js +114 -0
- package/build/services/machines/commands.d.ts +5 -5
- package/build/services/machines/commands.js +3 -2
- package/build/services/machines/config.d.ts +8 -1
- package/build/services/machines/config.js +17 -7
- package/build/services/machines/contracts.d.ts +29 -2
- package/build/services/machines/contracts.js +12 -3
- package/build/services/machines/gateway/actions.d.ts +2 -1
- package/build/services/machines/gateway/admission.d.ts +15 -3
- package/build/services/machines/gateway/admission.js +29 -14
- package/build/services/machines/gateway/dispatcher.d.ts +19 -3
- package/build/services/machines/gateway/dispatcher.js +61 -13
- package/build/services/machines/gateway/executor.d.ts +18 -4
- package/build/services/machines/gateway/executor.js +99 -34
- package/build/services/machines/gateway/gateway.d.ts +22 -1
- package/build/services/machines/gateway/gateway.js +83 -28
- package/build/services/machines/gateway/index.d.ts +3 -0
- package/build/services/machines/gateway/index.js +3 -0
- package/build/services/machines/gateway/inspect.d.ts +17 -0
- package/build/services/machines/gateway/inspect.js +68 -0
- package/build/services/machines/gateway/lifecycle.d.ts +21 -0
- package/build/services/machines/gateway/lifecycle.js +89 -0
- package/build/services/machines/gateway/log.d.ts +8 -0
- package/build/services/machines/gateway/log.js +18 -0
- package/build/services/machines/gateway/pacing.d.ts +14 -0
- package/build/services/machines/gateway/pacing.js +27 -2
- package/build/services/machines/gateway/plan-escalation.js +21 -7
- package/build/services/machines/gateway/plan-machine.d.ts +5 -4
- package/build/services/machines/gateway/plan-machine.js +70 -19
- package/build/services/machines/gateway/project.d.ts +9 -0
- package/build/services/machines/gateway/project.js +55 -0
- package/build/services/machines/gateway/receipts.d.ts +3 -0
- package/build/services/machines/gateway/receipts.js +3 -1
- package/build/services/machines/gateway/reconcile.d.ts +2 -0
- package/build/services/machines/gateway/reconcile.js +16 -3
- package/build/services/machines/gateway/registration.js +1 -1
- package/build/services/machines/gateway/reply-waiter.d.ts +6 -3
- package/build/services/machines/gateway/reply-waiter.js +37 -16
- package/build/services/machines/gateway/state.d.ts +50 -4
- package/build/services/machines/gateway/state.js +77 -10
- package/build/services/machines/gateway/wire.d.ts +58 -0
- package/build/services/machines/gateway/wire.js +171 -0
- package/build/services/machines/index.d.ts +3 -0
- package/build/services/machines/index.js +2 -0
- package/build/services/machines/leadership.d.ts +17 -4
- package/build/services/machines/leadership.js +43 -18
- package/build/services/machines/line-index.d.ts +16 -0
- package/build/services/machines/line-index.js +39 -0
- package/build/services/machines/registry-sql.d.ts +31 -0
- package/build/services/machines/registry-sql.js +110 -0
- package/build/services/machines/registry-sync.d.ts +31 -0
- package/build/services/machines/registry-sync.js +81 -0
- package/build/services/machines/registry.d.ts +77 -0
- package/build/services/machines/registry.js +158 -0
- package/build/services/machines/rows.js +26 -2
- package/build/services/machines/select.d.ts +9 -2
- package/build/services/machines/select.js +20 -7
- package/build/services/machines/surface.d.ts +45 -5
- package/build/services/machines/surface.js +102 -16
- package/build/services/machines/testing/fake-long-tail.d.ts +1 -0
- package/build/services/machines/testing/fake-long-tail.js +6 -3
- package/build/start/adapters.js +11 -2
- package/build/start/apply-report.d.ts +1 -1
- package/build/start/apply-report.js +3 -25
- package/build/start/index.js +23 -5
- package/build/system/index.js +13 -0
- package/build/system/mcp-servers/admin/schemas.d.ts +22 -22
- package/build/system/mcp-servers/human-queue-schemas.d.ts +7 -7
- package/build/system/mcp-servers/machines-schemas.d.ts +35 -0
- package/build/system/mcp-servers/machines-schemas.js +35 -0
- package/build/system/mcp-servers/machines.d.ts +20 -0
- package/build/system/mcp-servers/machines.js +154 -0
- package/build/system/seed/tool-manifests-machines.d.ts +2 -0
- package/build/system/seed/tool-manifests-machines.js +88 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/events.d.ts +6 -1
- package/build/types/index.d.ts +2 -0
- package/build/types/machines-view.d.ts +159 -0
- package/build/types/machines-view.js +7 -0
- package/build/types/machines.d.ts +6 -1
- package/build/types/messaging.d.ts +72 -0
- package/build/types/messaging.js +11 -0
- package/build/types/startup.d.ts +26 -1
- package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js → AdminDashboard-Bm7VG65H.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js.map → AdminDashboard-Bm7VG65H.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js → AgentConfigPage-aJF7Sdbc.js} +6 -6
- package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js.map → AgentConfigPage-aJF7Sdbc.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js → AgentDetailPage-GwwghhxT.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js.map → AgentDetailPage-GwwghhxT.js.map} +1 -1
- package/dashboard/dist/assets/AgentsPage-DVvCzZyg.js +2 -0
- package/dashboard/dist/assets/{AgentsPage-C9UuUKhr.js.map → AgentsPage-DVvCzZyg.js.map} +1 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-Cxmcji_K.js +2 -0
- package/dashboard/dist/assets/{AvailableEscalationsPage-DrvfXz70.js.map → AvailableEscalationsPage-Cxmcji_K.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js → BotPicker-CofRxk4L.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js.map → BotPicker-CofRxk4L.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js → BulkAssignModal-BARWuz4L.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js.map → BulkAssignModal-BARWuz4L.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js → CapabilitiesPage-BJAWVNEx.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js.map → CapabilitiesPage-BJAWVNEx.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js → CollapsibleSection-CtgoaG75.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js.map → CollapsibleSection-CtgoaG75.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js → ConfirmDeleteModal-BYXXBWs6.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js.map → ConfirmDeleteModal-BYXXBWs6.js.map} +1 -1
- package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js → ConnectedAppsPage-D0JkzWa7.js} +2 -2
- package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js.map → ConnectedAppsPage-D0JkzWa7.js.map} +1 -1
- package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js → CountdownTimer-BcFxdZYN.js} +2 -2
- package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js.map → CountdownTimer-BcFxdZYN.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js → CredentialsPage-DPSY20rV.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js.map → CredentialsPage-DPSY20rV.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js → CronLabel-Dg_Oew_Y.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js.map → CronLabel-Dg_Oew_Y.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-u1JGfR9G.js → DropZone-Cl_Flb16.js} +2 -2
- package/dashboard/dist/assets/{DropZone-u1JGfR9G.js.map → DropZone-Cl_Flb16.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js → ElapsedCell-Dm3G5fK2.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js.map → ElapsedCell-Dm3G5fK2.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js → EntityTimelinePanel-CrEEP04e.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js.map → EntityTimelinePanel-CrEEP04e.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js → EscalationListSchemaPage-wOInXcjs.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js.map → EscalationListSchemaPage-wOInXcjs.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js → EscalationSchemaPage-CrIj_g9d.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js.map → EscalationSchemaPage-CrIj_g9d.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js → EscalationTimeline-CeAsl5IT.js} +2 -2
- package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js.map → EscalationTimeline-CeAsl5IT.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js → EscalationTitleSelect-D8qpCYiy.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js.map → EscalationTitleSelect-D8qpCYiy.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js → EscalationsOverview-CvaqVPsr.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js.map → EscalationsOverview-CvaqVPsr.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-V4RF_n58.js → EventTable-Be0JuEl6.js} +2 -2
- package/dashboard/dist/assets/{EventTable-V4RF_n58.js.map → EventTable-Be0JuEl6.js.map} +1 -1
- package/dashboard/dist/assets/FilterBar-BVyAjIgv.js +2 -0
- package/dashboard/dist/assets/FilterBar-BVyAjIgv.js.map +1 -0
- package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js → GraphInvokePage-D_QigJeD.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js.map → GraphInvokePage-D_QigJeD.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-EjcNxlKx.js → HomePage-C1haeuNy.js} +2 -2
- package/dashboard/dist/assets/{HomePage-EjcNxlKx.js.map → HomePage-C1haeuNy.js.map} +1 -1
- package/dashboard/dist/assets/LinePage-CWD5pv1g.js +5 -0
- package/dashboard/dist/assets/LinePage-CWD5pv1g.js.map +1 -0
- package/dashboard/dist/assets/LinesPage-NqChsKcO.js +3 -0
- package/dashboard/dist/assets/LinesPage-NqChsKcO.js.map +1 -0
- package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js → ListToolbar-BZCNrTh6.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js.map → ListToolbar-BZCNrTh6.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js → McpOverview-yJTYnh1z.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js.map → McpOverview-yJTYnh1z.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js → McpQueryDetailPage-ChuLpJ4u.js} +3 -3
- package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js.map → McpQueryDetailPage-ChuLpJ4u.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js → McpQueryPage-9S-v9soF.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js.map → McpQueryPage-9S-v9soF.js.map} +1 -1
- package/dashboard/dist/assets/McpRunDetailPage-BhrcfxD5.js +2 -0
- package/dashboard/dist/assets/{McpRunDetailPage-80fQn9iX.js.map → McpRunDetailPage-BhrcfxD5.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js → McpRunsPage-C5_i8_Zx.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js.map → McpRunsPage-C5_i8_Zx.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js → NamespacePill-OTZD2hzt.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js.map → NamespacePill-OTZD2hzt.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js → OperationsPage-C03CeU5P.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js.map → OperationsPage-C03CeU5P.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js → OperatorDashboard-BzC134Jt.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js.map → OperatorDashboard-BzC134Jt.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-BSWIspNB.js → PageHeader-Hx8APPwE.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-BSWIspNB.js.map → PageHeader-Hx8APPwE.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js → PageHeaderWithStats-BEQYYBJv.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js.map → PageHeaderWithStats-BEQYYBJv.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js → PersonaDetailPage-D0mY9L6j.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js.map → PersonaDetailPage-D0mY9L6j.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js → PersonasPage-FFlm5Eug.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js.map → PersonasPage-FFlm5Eug.js.map} +1 -1
- package/dashboard/dist/assets/{PortalPage-CucNZn_w.js → PortalPage-Cpc25uO-.js} +2 -2
- package/dashboard/dist/assets/{PortalPage-CucNZn_w.js.map → PortalPage-Cpc25uO-.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js → ProcessDetailPage-Di2J7KwY.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js.map → ProcessDetailPage-Di2J7KwY.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js → ProcessesListPage-BEXwU3Z0.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js.map → ProcessesListPage-BEXwU3Z0.js.map} +1 -1
- package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js → ResolverForm-2ks-3jXC.js} +6 -6
- package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js.map → ResolverForm-2ks-3jXC.js.map} +1 -1
- package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js → RoleDetailPage-DqoOk0xc.js} +3 -3
- package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js.map → RoleDetailPage-DqoOk0xc.js.map} +1 -1
- package/dashboard/dist/assets/{RolePill-CoETDpjF.js → RolePill-R5_ctGFy.js} +2 -2
- package/dashboard/dist/assets/{RolePill-CoETDpjF.js.map → RolePill-R5_ctGFy.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-DBKxeam4.js → RolesPage-CPmo8Srr.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-DBKxeam4.js.map → RolesPage-CPmo8Srr.js.map} +1 -1
- package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js → RosterWidget-D2yovCKw.js} +2 -2
- package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js.map → RosterWidget-D2yovCKw.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js → RunAsSelector-CMv96On6.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js.map → RunAsSelector-CMv96On6.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js → ScanCodesPage-CA6cTT-M.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js.map → ScanCodesPage-CA6cTT-M.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js → ScanSchemeDetailPage-DnctN5-H.js} +2 -2
- package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js.map → ScanSchemeDetailPage-DnctN5-H.js.map} +1 -1
- package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js → ScanStationPage-Bk8RwkKL.js} +2 -2
- package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js.map → ScanStationPage-Bk8RwkKL.js.map} +1 -1
- package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js → ScopeBadge-BXZ084nD.js} +2 -2
- package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js.map → ScopeBadge-BXZ084nD.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js → StickyPagination-B0FSuUgs.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js.map → StickyPagination-B0FSuUgs.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js → StreamMessageDetail-BwZEvMpP.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js.map → StreamMessageDetail-BwZEvMpP.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js → SwimlaneTimeline-BDVQEaMw.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js.map → SwimlaneTimeline-BDVQEaMw.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-S7UuVT_M.js → TagInput-DjPUDp2M.js} +2 -2
- package/dashboard/dist/assets/{TagInput-S7UuVT_M.js.map → TagInput-DjPUDp2M.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js → TaskDetailPage-BOlv3iGB.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js.map → TaskDetailPage-BOlv3iGB.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js → TaskQueuePill-D-4Ynf3K.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js.map → TaskQueuePill-D-4Ynf3K.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js → TasksListPage-e2teY0bD.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js.map → TasksListPage-e2teY0bD.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js → TimeAgo-Cvkpf_b3.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js.map → TimeAgo-Cvkpf_b3.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js → TimestampCell-B3btAV0N.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js.map → TimestampCell-B3btAV0N.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-D40uLM_v.js → ToolPill-GsKQ80CO.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-D40uLM_v.js.map → ToolPill-GsKQ80CO.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js → ToolTestPanel-B03nebR7.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js.map → ToolTestPanel-B03nebR7.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js → TopicDetailPage-DBRWne3O.js} +3 -3
- package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js.map → TopicDetailPage-DBRWne3O.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js → TopicsPage-CVe2M9HD.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js.map → TopicsPage-CVe2M9HD.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-DQFjuoib.js → UserName-B_q_qp6V.js} +2 -2
- package/dashboard/dist/assets/{UserName-DQFjuoib.js.map → UserName-B_q_qp6V.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowExecutionPage-Bh_dr9tM.js +2 -0
- package/dashboard/dist/assets/{WorkflowExecutionPage-Di08wCbs.js.map → WorkflowExecutionPage-Bh_dr9tM.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js → WorkflowPill-D7244fKp.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js.map → WorkflowPill-D7244fKp.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js → WorkflowsDashboard-DA6Mj7qH.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js.map → WorkflowsDashboard-DA6Mj7qH.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js → WorkflowsOverview-B1kBLj-a.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js.map → WorkflowsOverview-B1kBLj-a.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js → YamlWorkflowDetailPage-6GJM8QIX.js} +8 -8
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js.map → YamlWorkflowDetailPage-6GJM8QIX.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js → YamlWorkflowsPage-Bu811C7f.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js.map → YamlWorkflowsPage-Bu811C7f.js.map} +1 -1
- package/dashboard/dist/assets/{agents-PuftRTB2.js → agents-MPk_GnYz.js} +2 -2
- package/dashboard/dist/assets/{agents-PuftRTB2.js.map → agents-MPk_GnYz.js.map} +1 -1
- package/dashboard/dist/assets/{bots-BmEiPAWY.js → bots-2RihE2Tc.js} +2 -2
- package/dashboard/dist/assets/{bots-BmEiPAWY.js.map → bots-2RihE2Tc.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-CRii4Soa.js → capabilities-CC4iwJ1P.js} +2 -2
- package/dashboard/dist/assets/{capabilities-CRii4Soa.js.map → capabilities-CC4iwJ1P.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-DO_czaYo.js → controlplane-Bmkic8BH.js} +2 -2
- package/dashboard/dist/assets/{controlplane-DO_czaYo.js.map → controlplane-Bmkic8BH.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js → escalation-columns-B0lhUUrQ.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js.map → escalation-columns-B0lhUUrQ.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js → escalation-items-7WFpPo46.js} +2 -2
- package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js.map → escalation-items-7WFpPo46.js.map} +1 -1
- package/dashboard/dist/assets/index-B9uv-euR.css +1 -0
- package/dashboard/dist/assets/{index-DhSCCpqM.js → index-B_XV1rwu.js} +2 -2
- package/dashboard/dist/assets/{index-DhSCCpqM.js.map → index-B_XV1rwu.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cx8xb-oU.js → index-C2CLfGwL.js} +2 -2
- package/dashboard/dist/assets/{index-Cx8xb-oU.js.map → index-C2CLfGwL.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cga5IW3D.js → index-C3AeFihz.js} +2 -2
- package/dashboard/dist/assets/{index-Cga5IW3D.js.map → index-C3AeFihz.js.map} +1 -1
- package/dashboard/dist/assets/{index-DiaRlFYI.js → index-CBri8fYM.js} +2 -2
- package/dashboard/dist/assets/{index-DiaRlFYI.js.map → index-CBri8fYM.js.map} +1 -1
- package/dashboard/dist/assets/{index-CL_1VpGb.js → index-CRWsB7ZC.js} +2 -2
- package/dashboard/dist/assets/{index-CL_1VpGb.js.map → index-CRWsB7ZC.js.map} +1 -1
- package/dashboard/dist/assets/{index-XntldBd0.js → index-CTOv3G7a.js} +2 -2
- package/dashboard/dist/assets/{index-XntldBd0.js.map → index-CTOv3G7a.js.map} +1 -1
- package/dashboard/dist/assets/{index-CfP2nKRc.js → index-CcArGkzI.js} +3 -3
- package/dashboard/dist/assets/{index-CfP2nKRc.js.map → index-CcArGkzI.js.map} +1 -1
- package/dashboard/dist/assets/{index-Dz6R8-Dw.js → index-CkMHS-hG.js} +25 -25
- package/dashboard/dist/assets/index-CkMHS-hG.js.map +1 -0
- package/dashboard/dist/assets/index-CmsmwCyv.js +2 -0
- package/dashboard/dist/assets/{index-4YaDUcKd.js.map → index-CmsmwCyv.js.map} +1 -1
- package/dashboard/dist/assets/{index-2SM2_onB.js → index-CvJsvqIc.js} +2 -2
- package/dashboard/dist/assets/{index-2SM2_onB.js.map → index-CvJsvqIc.js.map} +1 -1
- package/dashboard/dist/assets/{index-Rwqrflm-.js → index-D-ilRyfy.js} +2 -2
- package/dashboard/dist/assets/{index-Rwqrflm-.js.map → index-D-ilRyfy.js.map} +1 -1
- package/dashboard/dist/assets/{index-CZ7A3AcD.js → index-DSUtfDXx.js} +2 -2
- package/dashboard/dist/assets/{index-CZ7A3AcD.js.map → index-DSUtfDXx.js.map} +1 -1
- package/dashboard/dist/assets/{index-jL2K6us4.js → index-Da6ycKyf.js} +2 -2
- package/dashboard/dist/assets/{index-jL2K6us4.js.map → index-Da6ycKyf.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-CeUqGPuo.js → knowledge-Bpbg20DC.js} +2 -2
- package/dashboard/dist/assets/{knowledge-CeUqGPuo.js.map → knowledge-Bpbg20DC.js.map} +1 -1
- package/dashboard/dist/assets/machines-BqOZZU-3.js +2 -0
- package/dashboard/dist/assets/machines-BqOZZU-3.js.map +1 -0
- package/dashboard/dist/assets/{mcp-Cx96NTeD.js → mcp-CmcUXYce.js} +2 -2
- package/dashboard/dist/assets/{mcp-Cx96NTeD.js.map → mcp-CmcUXYce.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js → mcp-query-C8buQxN9.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js.map → mcp-query-C8buQxN9.js.map} +1 -1
- package/dashboard/dist/assets/{personas--4kjwyOw.js → personas-C2n5oDmY.js} +2 -2
- package/dashboard/dist/assets/{personas--4kjwyOw.js.map → personas-C2n5oDmY.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-PgkwvG7f.js → pipelines-RKpSkFz7.js} +2 -2
- package/dashboard/dist/assets/{pipelines-PgkwvG7f.js.map → pipelines-RKpSkFz7.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-CcYxdBa3.js → tasks-Dab4hExW.js} +2 -2
- package/dashboard/dist/assets/{tasks-CcYxdBa3.js.map → tasks-Dab4hExW.js.map} +1 -1
- package/dashboard/dist/assets/{topics-_lik7cNY.js → topics-FTMNP7r3.js} +2 -2
- package/dashboard/dist/assets/{topics-_lik7cNY.js.map → topics-FTMNP7r3.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js → useDebouncedValue-B_1u1YIk.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js.map → useDebouncedValue-B_1u1YIk.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js → useNamespace-HUeAI7Qb.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js.map → useNamespace-HUeAI7Qb.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js → useYamlActivityEvents-Cax54qHH.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js.map → useYamlActivityEvents-Cax54qHH.js.map} +1 -1
- package/dashboard/dist/assets/{validate-FlXCBBT6.js → validate-DxOaV7QS.js} +2 -2
- package/dashboard/dist/assets/{validate-FlXCBBT6.js.map → validate-DxOaV7QS.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-DUYcKTjP.js → vendor-icons-fxBvvHBi.js} +187 -182
- package/dashboard/dist/assets/vendor-icons-fxBvvHBi.js.map +1 -0
- package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js → yaml-workflows-BgY1XHJx.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js.map → yaml-workflows-BgY1XHJx.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/architecture.md +1 -0
- package/docs/code-owned-configuration.md +6 -0
- package/docs/dashboard.md +1 -0
- package/docs/events.md +83 -4
- package/docs/machines.md +129 -23
- package/docs/mcp.md +19 -0
- package/package.json +3 -1
- package/build/lib/machines/transport/nats-durable.d.ts +0 -11
- package/build/lib/machines/transport/nats-durable.js +0 -28
- package/dashboard/dist/assets/AgentsPage-C9UuUKhr.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-DrvfXz70.js +0 -2
- package/dashboard/dist/assets/FilterBar-BygWrnB1.js +0 -2
- package/dashboard/dist/assets/FilterBar-BygWrnB1.js.map +0 -1
- package/dashboard/dist/assets/McpRunDetailPage-80fQn9iX.js +0 -2
- package/dashboard/dist/assets/WorkflowExecutionPage-Di08wCbs.js +0 -2
- package/dashboard/dist/assets/index-4YaDUcKd.js +0 -2
- package/dashboard/dist/assets/index-CnU7Jjz3.css +0 -1
- package/dashboard/dist/assets/index-Dz6R8-Dw.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-DUYcKTjP.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LinePage-CWD5pv1g.js","sources":["../../src/hooks/useWireTape.ts","../../src/pages/lines/line-view-prefs.ts","../../src/pages/lines/wire-display.ts","../../src/pages/lines/CommandForm.tsx","../../src/pages/lines/InspectForm.tsx","../../src/pages/lines/MachinePanel.tsx","../../src/pages/lines/MachineRows.tsx","../../src/pages/lines/MachineStrip.tsx","../../src/pages/lines/MachineViews.tsx","../../src/pages/lines/WireRow.tsx","../../src/pages/lines/WireTape.tsx","../../src/pages/lines/TapeSection.tsx","../../src/pages/lines/WireDetailPanel.tsx","../../src/pages/lines/LinePage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useReducer } from 'react';\nimport { useEventSubscription } from './useEventContext';\nimport {\n machineWirePattern,\n WIRE_EVENT_TYPE,\n WIRE_KINDS,\n type WireDirection,\n type WireEvent,\n type WireKind,\n} from '../api/machines';\n\n/** The tape keeps this many events, newest first; older ones fall off the end. */\nexport const WIRE_TAPE_CAPACITY = 2000;\n\nexport interface WireTapeFilters {\n machine: string | null;\n channel: string | null;\n direction: WireDirection | null;\n kind: WireKind | null;\n violationsOnly: boolean;\n}\n\nexport interface WireTapeState {\n /** Newest first. */\n events: WireEvent[];\n /** Events that arrived while paused, newest first; they join the tape on resume. */\n held: WireEvent[];\n paused: boolean;\n filters: WireTapeFilters;\n}\n\nexport type WireTapeAction =\n | { type: 'ingest'; event: WireEvent }\n | { type: 'pause' }\n | { type: 'resume' }\n | { type: 'clear' }\n | { type: 'filter'; patch: Partial<WireTapeFilters> };\n\nexport const EMPTY_FILTERS: WireTapeFilters = {\n machine: null,\n channel: null,\n direction: null,\n kind: null,\n violationsOnly: false,\n};\n\nexport function initialTapeState(): WireTapeState {\n return { events: [], held: [], paused: false, filters: EMPTY_FILTERS };\n}\n\nfunction cap(events: WireEvent[]): WireEvent[] {\n return events.length > WIRE_TAPE_CAPACITY ? events.slice(0, WIRE_TAPE_CAPACITY) : events;\n}\n\nexport function wireTapeReducer(state: WireTapeState, action: WireTapeAction): WireTapeState {\n switch (action.type) {\n case 'ingest':\n return state.paused\n ? { ...state, held: cap([action.event, ...state.held]) }\n : { ...state, events: cap([action.event, ...state.events]) };\n case 'pause':\n return state.paused ? state : { ...state, paused: true };\n case 'resume':\n return { ...state, paused: false, held: [], events: cap([...state.held, ...state.events]) };\n case 'clear':\n return { ...state, events: [], held: [] };\n case 'filter':\n return { ...state, filters: { ...state.filters, ...action.patch } };\n }\n}\n\nexport function matchesFilters(event: WireEvent, filters: WireTapeFilters): boolean {\n if (filters.machine && event.machineId !== filters.machine) return false;\n if (filters.channel && event.channel !== filters.channel) return false;\n if (filters.direction && event.direction !== filters.direction) return false;\n if (filters.kind && event.kind !== filters.kind) return false;\n if (filters.violationsOnly && event.violations.length === 0) return false;\n return true;\n}\n\nexport function applyFilters(events: WireEvent[], filters: WireTapeFilters): WireEvent[] {\n return events.filter((event) => matchesFilters(event, filters));\n}\n\nconst KINDS = new Set<string>(WIRE_KINDS);\n\n/**\n * The transport hands over the published event envelope: its routing type\n * carries the site, line, machine and direction tokens after `machine.wire`,\n * and the wire event itself rides in `data`. A bare wire event is read as is.\n */\nexport function toWireEvent(raw: unknown): WireEvent | null {\n if (!raw || typeof raw !== 'object') return null;\n const envelope = raw as Record<string, unknown>;\n const type = envelope.type;\n if (typeof type !== 'string' || (type !== WIRE_EVENT_TYPE && !type.startsWith(`${WIRE_EVENT_TYPE}.`))) {\n return null;\n }\n const e = envelope.data && typeof envelope.data === 'object' ? (envelope.data as Record<string, unknown>) : envelope;\n if (typeof e.siteId !== 'string' || typeof e.lineId !== 'string') return null;\n if (e.direction !== 'in' && e.direction !== 'out') return null;\n const kind = typeof e.kind === 'string' && KINDS.has(e.kind) ? (e.kind as WireKind) : 'unknown';\n const at = [e.at, envelope.timestamp].find((v): v is string => typeof v === 'string') ?? new Date().toISOString();\n return {\n type: WIRE_EVENT_TYPE,\n siteId: e.siteId,\n lineId: e.lineId,\n machineId: typeof e.machineId === 'string' ? e.machineId : null,\n address: typeof e.address === 'string' ? e.address : null,\n direction: e.direction,\n channel: typeof e.channel === 'string' ? e.channel : '',\n topic: typeof e.topic === 'string' ? e.topic : '',\n id: typeof e.id === 'string' ? e.id : null,\n at,\n retained: e.retained === true,\n kind,\n event: typeof e.event === 'string' ? e.event : null,\n summary: typeof e.summary === 'string' ? e.summary : '',\n violations: Array.isArray(e.violations) ? e.violations.filter((v): v is string => typeof v === 'string') : [],\n actions: Array.isArray(e.actions) ? (e.actions as WireEvent['actions']) : [],\n ...('payload' in e ? { payload: e.payload } : {}),\n };\n}\n\nfunction distinct(values: (string | null)[]): string[] {\n return [...new Set(values.filter((v): v is string => !!v))].sort();\n}\n\n/**\n * The live tape of one line's wire events: a bounded ring buffer fed by the\n * event transport, with filters and a pause that holds new arrivals aside.\n */\nexport function useWireTape(siteId: string, lineId: string) {\n const [state, dispatch] = useReducer(wireTapeReducer, undefined, initialTapeState);\n\n useEffect(() => {\n dispatch({ type: 'clear' });\n }, [siteId, lineId]);\n\n useEventSubscription(machineWirePattern(siteId, lineId), (raw) => {\n const event = toWireEvent(raw);\n if (event) dispatch({ type: 'ingest', event });\n });\n\n const visible = useMemo(() => applyFilters(state.events, state.filters), [state.events, state.filters]);\n const machines = useMemo(() => distinct(state.events.map((e) => e.machineId)), [state.events]);\n const channels = useMemo(() => distinct(state.events.map((e) => e.channel)), [state.events]);\n\n const setFilter = useCallback((patch: Partial<WireTapeFilters>) => dispatch({ type: 'filter', patch }), []);\n const togglePause = useCallback(() => dispatch({ type: state.paused ? 'resume' : 'pause' }), [state.paused]);\n const clear = useCallback(() => dispatch({ type: 'clear' }), []);\n\n return {\n events: visible,\n total: state.events.length,\n heldCount: state.held.length,\n paused: state.paused,\n filters: state.filters,\n machines,\n channels,\n setFilter,\n togglePause,\n clear,\n };\n}\n","import type { MachineView } from '../../api/machines';\n\n/** How the machines region lists its machines. */\nexport const MACHINE_VIEWS = ['tiles', 'rows'] as const;\nexport type MachineViewMode = (typeof MACHINE_VIEWS)[number];\nexport const MACHINE_VIEW_LABEL: Record<MachineViewMode, string> = { tiles: 'Tiles', rows: 'Rows' };\n\n/** Tiles read well to a dozen machines; beyond that, rows. */\nexport const TILES_MAX = 12;\n\nexport function machineViewStorageKey(siteId: string, lineId: string): string {\n return `lt:lines:${siteId}/${lineId}:machines-view`;\n}\n\nexport function autoMachineView(count: number): MachineViewMode {\n return count <= TILES_MAX ? 'tiles' : 'rows';\n}\n\nexport function readStored<T extends string>(key: string, allowed: readonly T[]): T | null {\n try {\n const value = localStorage.getItem(key);\n return value && (allowed as readonly string[]).includes(value) ? (value as T) : null;\n } catch {\n return null;\n }\n}\n\nexport function writeStored(key: string, value: string | null): void {\n try {\n if (value === null) localStorage.removeItem(key);\n else localStorage.setItem(key, value);\n } catch {\n // storage may be unavailable; the choice then lasts the session\n }\n}\n\n/** A machine that needs a person: offline, quiet, an active alarm, or an open row. */\nexport function needsAttention(view: MachineView | undefined): boolean {\n if (!view) return false;\n if (view.online === false) return true;\n if (view.rows.offlineRowId || view.rows.quietRowId) return true;\n if (view.alarms.length > 0) return true;\n return view.rows.handoff + view.rows.command + view.rows.alarm > 0;\n}\n","import type { MachineView, WireAction, WireVerb } from '../../api/machines';\nimport { getDisplayTimeZone } from '../../lib/display-zone';\n\n/** Past-tense wording for each action the gateway took on a message. */\nexport const WIRE_VERB_LABEL: Record<WireVerb, string> = {\n claim: 'claimed',\n accumulate: 'accumulated',\n resolve: 'resolved',\n 'create-row': 'row created',\n refuse: 'refused',\n hold: 'held',\n unmatched: 'unmatched',\n unreadable: 'unreadable',\n ack: 'acknowledged',\n none: '',\n};\n\n/** Text-safe status tone per verb. */\nexport const WIRE_VERB_TONE: Record<WireVerb, string> = {\n claim: 'text-text-secondary',\n accumulate: 'text-text-secondary',\n resolve: 'text-status-success',\n 'create-row': 'text-text-secondary',\n refuse: 'text-status-error',\n hold: 'text-status-warning',\n unmatched: 'text-status-warning',\n unreadable: 'text-status-error',\n ack: 'text-text-secondary',\n none: 'text-text-quaternary',\n};\n\n/** \"accumulated arrived:U1\": the verb plus the item it touched. */\nexport function describeAction(action: WireAction): string {\n const label = WIRE_VERB_LABEL[action.verb] ?? action.verb;\n return action.itemKey ? `${label} ${action.itemKey}` : label;\n}\n\n/** Actions worth a word; `none` stays silent. */\nexport function visibleActions(actions: WireAction[]): WireAction[] {\n return actions.filter((a) => a.verb !== 'none');\n}\n\n/** The escalation detail route for a row the gateway named. */\nexport function rowPath(rowId: string): string {\n return `/escalations/detail/${encodeURIComponent(rowId)}`;\n}\n\n/** \"13:02:07\" in the display zone, for the tape's time column. */\nexport function formatClock(iso: string): string {\n const date = new Date(iso);\n if (Number.isNaN(date.getTime())) return iso;\n const zone = getDisplayTimeZone();\n return new Intl.DateTimeFormat('en-GB', {\n ...(zone ? { timeZone: zone } : {}),\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n }).format(date);\n}\n\nexport type Presence = 'online' | 'quiet' | 'offline' | 'unknown';\n\n/** Ring color per presence, through the graphic status tokens. */\nexport const PRESENCE_DOT: Record<Presence, string> = {\n online: 'bg-status-success-graphic',\n quiet: 'bg-status-pending-graphic',\n offline: 'bg-status-error',\n unknown: 'bg-text-quaternary',\n};\n\nexport const PRESENCE_LABEL: Record<Presence, string> = {\n online: 'online',\n quiet: 'quiet',\n offline: 'offline',\n unknown: 'unknown',\n};\n\n/** Quiet is online with an open quiet row; unknown is a machine the leader has yet to hear. */\nexport function presenceOf(view: MachineView | undefined): Presence {\n if (!view || view.online === null) return 'unknown';\n if (!view.online) return 'offline';\n return view.rows.quietRowId ? 'quiet' : 'online';\n}\n\n/** Pretty JSON for panels; strings stay as they are. */\nexport function formatJson(value: unknown): string {\n if (typeof value === 'string') return value;\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n","import { useState, type FormEvent } from 'react';\nimport { Link } from 'react-router-dom';\nimport { commandOpsFor, sendCommand, SNAPSHOT_OP, type LineSummaryMachine } from '../../api/machines';\nimport { rowPath } from './wire-display';\n\nexport type CommandOutcome =\n | { request: string; ok: true; rowId: string }\n | { request: string; ok: false; message: string };\n\n/** The scan idiom: the request in mono, the verdict in its tone. */\nexport function CommandOutcomeBody({ outcome }: { outcome: CommandOutcome }) {\n return (\n <div className=\"min-w-0\" data-testid=\"command-outcome\">\n <div className=\"text-xs font-mono text-text-secondary truncate\" title={outcome.request}>{outcome.request}</div>\n {outcome.ok ? (\n <div className=\"text-xs font-medium text-status-success\">\n Row created{' '}\n <Link to={rowPath(outcome.rowId)} className=\"font-mono text-accent hover:underline\">{outcome.rowId}</Link>\n </div>\n ) : (\n <div className=\"text-xs font-medium text-status-error\">{outcome.message}</div>\n )}\n </div>\n );\n}\n\nconst ARG_HELPERS = ['jobId', 'recipe'] as const;\n\nfunction mergeArgKey(text: string, key: string): string {\n let current: Record<string, unknown> = {};\n try {\n const parsed = text.trim() ? JSON.parse(text) : {};\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) current = parsed;\n } catch {\n current = {};\n }\n if (!(key in current)) current[key] = '';\n return JSON.stringify(current, null, 2);\n}\n\nfunction parseArgs(text: string): Record<string, unknown> {\n if (!text.trim()) return {};\n const parsed = JSON.parse(text);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('Args must be a JSON object.');\n }\n return parsed;\n}\n\n/**\n * Send one command to a machine: an op from the line's vocabulary and a\n * small JSON args object. The server creates the row; the role decides.\n */\nexport function CommandForm({\n siteId,\n lineId,\n machine,\n}: {\n siteId: string;\n lineId: string;\n machine: LineSummaryMachine;\n}) {\n const [op, setOp] = useState('');\n const [args, setArgs] = useState('');\n const [busy, setBusy] = useState(false);\n const [outcome, setOutcome] = useState<CommandOutcome | null>(null);\n const ops = commandOpsFor(machine);\n\n const submit = async (e: FormEvent) => {\n e.preventDefault();\n if (!op) return;\n const request = `${op} ${args.trim() || '{}'}`;\n setBusy(true);\n try {\n const parsed = parseArgs(args);\n const receipt = await sendCommand(siteId, lineId, machine.machineId, { op, args: parsed });\n setOutcome({ request, ok: true, rowId: receipt.rowId });\n } catch (err) {\n setOutcome({ request, ok: false, message: (err as Error).message });\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <form onSubmit={submit} className=\"space-y-3\" aria-label=\"Send command\">\n <div>\n <label htmlFor=\"command-op\" className=\"block text-2xs font-medium text-text-secondary\">\n Op <span className=\"text-status-error\">*</span>\n </label>\n <p className=\"text-2xs text-text-tertiary mb-1\">Pick the operation the machine runs.</p>\n <select\n id=\"command-op\"\n className=\"select text-xs font-mono\"\n value={op}\n required\n onChange={(e) => setOp(e.target.value)}\n >\n <option value=\"\" disabled>Choose…</option>\n {ops.map((o) => <option key={o} value={o}>{o}</option>)}\n </select>\n </div>\n <div>\n <label htmlFor=\"command-args\" className=\"block text-2xs font-medium text-text-secondary\">Args</label>\n <p className=\"text-2xs text-text-tertiary mb-1\">Write a JSON object, or add a key from the helpers.</p>\n <textarea\n id=\"command-args\"\n className=\"textarea text-2xs font-mono min-h-[4.5rem]\"\n value={args}\n placeholder=\"{}\"\n onChange={(e) => setArgs(e.target.value)}\n />\n <div className=\"flex items-center gap-2 mt-1\">\n {ARG_HELPERS.map((key) => (\n <button\n key={key}\n type=\"button\"\n onClick={() => setArgs((t) => mergeArgKey(t, key))}\n className=\"text-2xs font-mono icon-link\"\n >\n + {key}\n </button>\n ))}\n </div>\n </div>\n <button type=\"submit\" disabled={busy || !op} className=\"btn-primary text-xs py-1.5 px-4\">\n Send\n </button>\n {outcome && <CommandOutcomeBody outcome={outcome} />}\n </form>\n );\n}\n\n/** One click asks the machine for a fresh snapshot, as a command row. */\nexport function SnapshotButton({\n siteId,\n lineId,\n machineId,\n}: {\n siteId: string;\n lineId: string;\n machineId: string;\n}) {\n const [busy, setBusy] = useState(false);\n const [outcome, setOutcome] = useState<CommandOutcome | null>(null);\n\n const ask = async () => {\n setBusy(true);\n try {\n const receipt = await sendCommand(siteId, lineId, machineId, { op: SNAPSHOT_OP, args: {} });\n setOutcome({ request: `${SNAPSHOT_OP} {}`, ok: true, rowId: receipt.rowId });\n } catch (err) {\n setOutcome({ request: `${SNAPSHOT_OP} {}`, ok: false, message: (err as Error).message });\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <div className=\"space-y-2\">\n <button type=\"button\" onClick={ask} disabled={busy} className=\"btn-secondary text-xs py-1.5 px-4\">\n Ask for a snapshot\n </button>\n {outcome && <CommandOutcomeBody outcome={outcome} />}\n </div>\n );\n}\n","import { useState, type FormEvent } from 'react';\nimport { Link } from 'react-router-dom';\nimport { inspectMessage, type InspectResult } from '../../api/machines';\nimport { describeAction, formatJson, rowPath, visibleActions, WIRE_VERB_TONE } from './wire-display';\n\nconst RETAINED_CHOICES = [\n { value: 'live', label: 'Live', retained: false },\n { value: 'retained', label: 'Retained', retained: true },\n] as const;\n\ntype Retained = (typeof RETAINED_CHOICES)[number]['value'];\n\n/** A payload that parses as JSON goes as JSON; anything else goes as the text typed. */\nexport function parsePayload(text: string): unknown {\n const trimmed = text.trim();\n if (!trimmed) return '';\n try {\n return JSON.parse(trimmed);\n } catch {\n return text;\n }\n}\n\ntype InspectOutcome =\n | { request: string; ok: true; result: InspectResult }\n | { request: string; ok: false; message: string };\n\n/** The dry-run verdict: summary, violations in the warning tone, planned actions with row links. */\nexport function InspectOutcomeBody({ outcome }: { outcome: InspectOutcome }) {\n return (\n <div className=\"min-w-0 space-y-2\" data-testid=\"inspect-outcome\">\n <div className=\"text-xs font-mono text-text-secondary truncate\" title={outcome.request}>{outcome.request}</div>\n {!outcome.ok ? (\n <div className=\"text-xs font-medium text-status-error\">{outcome.message}</div>\n ) : (\n <>\n <div className={`text-xs font-medium ${outcome.result.violations.length ? 'text-status-warning' : 'text-status-success'}`}>\n {outcome.result.kind ?? 'message'}\n {outcome.result.event ? ` · ${outcome.result.event}` : ''}\n {outcome.result.violations.length\n ? ` · ${outcome.result.violations.length} violation${outcome.result.violations.length === 1 ? '' : 's'}`\n : ' · matches the contract'}\n </div>\n {outcome.result.summary && <div className=\"text-2xs text-text-secondary\">{outcome.result.summary}</div>}\n {outcome.result.violations.length > 0 && (\n <ul className=\"space-y-0.5\" aria-label=\"Violations\">\n {outcome.result.violations.map((v, i) => (\n <li key={i} className=\"text-2xs text-status-warning\">{v}</li>\n ))}\n </ul>\n )}\n <div>\n <p className=\"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1\">Planned actions</p>\n {visibleActions(outcome.result.actions).length === 0 ? (\n <p className=\"text-2xs text-text-quaternary\">The gateway would take no action.</p>\n ) : (\n <ul className=\"space-y-0.5\" aria-label=\"Planned actions\">\n {visibleActions(outcome.result.actions).map((a, i) => (\n <li key={`${a.verb}-${i}`} className=\"text-2xs\">\n <span className={WIRE_VERB_TONE[a.verb]}>{describeAction(a)}</span>\n {a.rowId && (\n <>\n {' '}\n <Link to={rowPath(a.rowId)} className=\"font-mono text-accent hover:underline\">{a.rowId}</Link>\n </>\n )}\n {a.detail && <span className=\"text-text-tertiary\"> · {a.detail}</span>}\n </li>\n ))}\n </ul>\n )}\n </div>\n {outcome.result.inspections !== undefined && (\n <pre className=\"text-2xs font-mono text-text-secondary whitespace-pre-wrap break-all bg-surface-sunken rounded px-2 py-1.5\">\n {formatJson(outcome.result.inspections)}\n </pre>\n )}\n </>\n )}\n </div>\n );\n}\n\n/**\n * Inspect a message as a dry run: the leader decodes it and plans what it\n * would do, without applying anything.\n */\nexport function InspectForm({ siteId, lineId }: { siteId: string; lineId: string }) {\n const [topic, setTopic] = useState('');\n const [payload, setPayload] = useState('');\n const [retained, setRetained] = useState<Retained | ''>('');\n const [busy, setBusy] = useState(false);\n const [outcome, setOutcome] = useState<InspectOutcome | null>(null);\n\n const submit = async (e: FormEvent) => {\n e.preventDefault();\n const choice = RETAINED_CHOICES.find((c) => c.value === retained);\n if (!topic.trim() || !choice) return;\n const request = `${topic.trim()} ${payload.trim() || '\"\"'}`;\n setBusy(true);\n try {\n const result = await inspectMessage(siteId, lineId, {\n topic: topic.trim(),\n payload: parsePayload(payload),\n retained: choice.retained,\n });\n setOutcome({ request, ok: true, result: { ...result, violations: result.violations ?? [], actions: result.actions ?? [] } });\n } catch (err) {\n setOutcome({ request, ok: false, message: (err as Error).message });\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <form onSubmit={submit} className=\"space-y-3\" aria-label=\"Inspect a message\">\n <div>\n <label htmlFor=\"inspect-topic\" className=\"block text-2xs font-medium text-text-secondary\">\n Topic <span className=\"text-status-error\">*</span>\n </label>\n <p className=\"text-2xs text-text-tertiary mb-1\">Enter the topic the message arrives on.</p>\n <input\n id=\"inspect-topic\"\n className=\"input text-2xs font-mono\"\n value={topic}\n required\n onChange={(e) => setTopic(e.target.value)}\n />\n </div>\n <div>\n <label htmlFor=\"inspect-payload\" className=\"block text-2xs font-medium text-text-secondary\">Payload</label>\n <p className=\"text-2xs text-text-tertiary mb-1\">Paste the body; JSON is sent as JSON, anything else as text.</p>\n <textarea\n id=\"inspect-payload\"\n className=\"textarea text-2xs font-mono min-h-[5rem]\"\n value={payload}\n onChange={(e) => setPayload(e.target.value)}\n />\n </div>\n <div>\n <label htmlFor=\"inspect-retained\" className=\"block text-2xs font-medium text-text-secondary\">\n Delivery <span className=\"text-status-error\">*</span>\n </label>\n <p className=\"text-2xs text-text-tertiary mb-1\">Say whether the broker would hand this over as a retained message.</p>\n <select\n id=\"inspect-retained\"\n className=\"select text-xs\"\n value={retained}\n required\n onChange={(e) => setRetained(e.target.value as Retained)}\n >\n <option value=\"\" disabled>Choose…</option>\n {RETAINED_CHOICES.map((c) => <option key={c.value} value={c.value}>{c.label}</option>)}\n </select>\n </div>\n <button type=\"submit\" disabled={busy || !topic.trim() || !retained} className=\"btn-primary text-xs py-1.5 px-4\">\n Inspect\n </button>\n {outcome && <InspectOutcomeBody outcome={outcome} />}\n </form>\n );\n}\n","import { useCallback, useState } from 'react';\nimport { Link } from 'react-router-dom';\nimport { X, ChevronRight } from 'lucide-react';\nimport { MACHINE_FACETS, type LineSummaryMachine, type MachineView } from '../../api/machines';\nimport { PanelField } from '../../components/common/layout/SlidePanel';\nimport { EntityTimelinePanel } from '../../components/escalation/EntityTimelinePanel';\nimport { useShellPanelOptional } from '../../hooks/useShellPanel';\nimport { formatDateTime } from '../../lib/format';\nimport { CommandForm, SnapshotButton } from './CommandForm';\nimport { InspectForm } from './InspectForm';\nimport { formatJson, PRESENCE_DOT, PRESENCE_LABEL, presenceOf, rowPath } from './wire-display';\n\nexport const MACHINE_PANEL_KEY = 'machine';\nexport const MACHINE_PANEL_WIDTH = 440;\nconst TIMELINE_PANEL_KEY = 'entity-timeline';\n\nfunction Section({ title, children }: { title: string; children: React.ReactNode }) {\n return (\n <section>\n <p className=\"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1.5\">{title}</p>\n {children}\n </section>\n );\n}\n\nfunction RowLink({ rowId, label }: { rowId: string; label: string }) {\n return (\n <li className=\"text-2xs\">\n <span className=\"text-text-secondary\">{label}</span>{' '}\n <Link to={rowPath(rowId)} className=\"font-mono text-accent hover:underline\">{rowId}</Link>\n </li>\n );\n}\n\n/**\n * One machine in the shell's right panel: the last snapshot in brief, its\n * open rows, a way into its timeline, and the tools for those who may act.\n */\nexport function MachinePanel({\n siteId,\n lineId,\n summary,\n view,\n canAct,\n onClose,\n}: {\n siteId: string;\n lineId: string;\n summary: LineSummaryMachine;\n view: MachineView | undefined;\n canAct: boolean;\n onClose: () => void;\n}) {\n const presence = presenceOf(view);\n const shell = useShellPanelOptional();\n const [jobsOpen, setJobsOpen] = useState(false);\n\n // The timeline takes the shell slot; the strip tile reopens this panel.\n const openTimeline = useCallback(\n (facetKey: string) => {\n shell?.setPanel(\n <EntityTimelinePanel facetKey={facetKey} value={summary.machineId} role={summary.role} />,\n { key: TIMELINE_PANEL_KEY, width: 420 },\n );\n },\n [shell, summary.machineId, summary.role],\n );\n\n const alarms = view?.alarms ?? [];\n const held = view?.heldUnits ?? [];\n const jobs = view?.jobs ?? [];\n\n return (\n <div className=\"h-full flex flex-col\">\n <div className=\"flex items-start justify-between px-5 pt-5 pb-3 border-b border-surface-border/40\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className={`w-2.5 h-2.5 rounded-full dot-ring shrink-0 ${PRESENCE_DOT[presence]}`} title={PRESENCE_LABEL[presence]} />\n <span className=\"text-sm font-mono text-text-primary truncate\">{summary.machineId}</span>\n <span className=\"text-2xs text-text-quaternary\">{PRESENCE_LABEL[presence]}</span>\n </div>\n <p className=\"text-2xs font-mono text-text-tertiary mt-0.5\">\n {summary.process} · {summary.role}\n </p>\n </div>\n <button onClick={onClose} className=\"icon-link shrink-0 ml-2\" title=\"Close\">\n <X className=\"w-4 h-4\" />\n </button>\n </div>\n\n <div className=\"flex-1 overflow-y-auto px-5 py-4 space-y-5\">\n <Section title=\"Snapshot\">\n <dl className=\"grid grid-cols-2 gap-x-4 gap-y-3\">\n <PanelField label=\"Address\">\n <span className=\"font-mono\">{view?.address ?? summary.address ?? '—'}</span>\n <span className=\"text-text-quaternary\"> · {summary.addressing}</span>\n </PanelField>\n <PanelField label=\"Software\"><span className=\"font-mono\">{view?.software ?? '—'}</span></PanelField>\n <PanelField label=\"Since\">{view?.since ? formatDateTime(view.since) : '—'}</PanelField>\n <PanelField label=\"Last seen\">{view?.lastSeen ? formatDateTime(view.lastSeen) : '—'}</PanelField>\n <PanelField label=\"Boot\"><span className=\"font-mono break-all\">{view?.bootId ?? '—'}</span></PanelField>\n <PanelField label=\"Session\"><span className=\"font-mono break-all\">{view?.sessionId ?? '—'}</span></PanelField>\n </dl>\n </Section>\n\n <Section title={`Jobs · ${jobs.length}`}>\n {jobs.length === 0 ? (\n <p className=\"text-2xs text-text-quaternary\">The last snapshot carried no jobs.</p>\n ) : (\n <>\n <button type=\"button\" onClick={() => setJobsOpen((v) => !v)} className=\"inline-flex items-center gap-1 text-2xs icon-link\">\n <ChevronRight className={`w-3 h-3 transition-transform ${jobsOpen ? 'rotate-90' : ''}`} />\n {jobsOpen ? 'Hide' : 'Show'} the jobs as reported\n </button>\n {jobsOpen && (\n <pre className=\"mt-1.5 text-2xs font-mono text-text-secondary whitespace-pre-wrap break-all bg-surface-sunken rounded px-2 py-1.5\">\n {formatJson(jobs)}\n </pre>\n )}\n </>\n )}\n </Section>\n\n <Section title={`Alarms · ${alarms.length}`}>\n {alarms.length === 0 ? (\n <p className=\"text-2xs text-text-quaternary\">The machine reports no active alarm.</p>\n ) : (\n <ul className=\"space-y-1\">\n {alarms.map((a) => (\n <li key={a.alarmId} className=\"text-2xs flex items-baseline gap-2\">\n <span className=\"font-mono text-status-warning\">{a.alarmId}</span>\n <span className=\"text-text-tertiary\">{a.level}</span>\n <span className=\"text-text-quaternary ml-auto\">{formatDateTime(a.raisedAt)}</span>\n {a.rowId && <Link to={rowPath(a.rowId)} className=\"font-mono text-accent hover:underline\">row</Link>}\n </li>\n ))}\n </ul>\n )}\n </Section>\n\n <Section title={`Held units · ${held.length}`}>\n {held.length === 0 ? (\n <p className=\"text-2xs text-text-quaternary\">The machine holds no unit.</p>\n ) : (\n <ul className=\"space-y-1\">\n {held.map((u) => (\n <RowLink key={u.unitId} rowId={u.rowId} label={u.carrierId ? `${u.unitId} on ${u.carrierId}` : u.unitId} />\n ))}\n </ul>\n )}\n </Section>\n\n <Section title=\"Open rows\">\n <p className=\"text-2xs font-mono text-text-secondary tabular-nums\">\n handoff {view?.rows.handoff ?? 0} · command {view?.rows.command ?? 0} · alarm {view?.rows.alarm ?? 0}\n </p>\n {(view?.rows.offlineRowId || view?.rows.quietRowId) && (\n <ul className=\"space-y-1 mt-1\">\n {view.rows.offlineRowId && <RowLink rowId={view.rows.offlineRowId} label=\"offline\" />}\n {view.rows.quietRowId && <RowLink rowId={view.rows.quietRowId} label=\"quiet\" />}\n </ul>\n )}\n </Section>\n\n <Section title=\"Over a window\">\n <p className=\"text-2xs text-text-tertiary mb-1.5\">Open the rows that moved work to or from this machine.</p>\n <div className=\"flex items-center gap-3\">\n <button type=\"button\" onClick={() => openTimeline(MACHINE_FACETS.TO)} className=\"text-2xs icon-link font-mono\">\n {MACHINE_FACETS.TO}\n </button>\n <button type=\"button\" onClick={() => openTimeline(MACHINE_FACETS.FROM)} className=\"text-2xs icon-link font-mono\">\n {MACHINE_FACETS.FROM}\n </button>\n </div>\n </Section>\n\n {canAct && (\n <>\n <Section title=\"Ask for a snapshot\">\n <SnapshotButton siteId={siteId} lineId={lineId} machineId={summary.machineId} />\n </Section>\n <Section title=\"Send command\">\n <CommandForm siteId={siteId} lineId={lineId} machine={summary} />\n </Section>\n <Section title=\"Inspect a message\">\n <InspectForm siteId={siteId} lineId={lineId} />\n </Section>\n </>\n )}\n </div>\n </div>\n );\n}\n","import { useMemo, useState } from 'react';\nimport type { StripMachine } from './MachineStrip';\nimport { PRESENCE_DOT, PRESENCE_LABEL, presenceOf } from './wire-display';\n\nconst ROWS_BOX_CLASS = 'flex-1 min-h-0 overflow-y-auto border-t border-surface-border';\n\nfunction matches(machine: StripMachine, needle: string): boolean {\n if (!needle) return true;\n const { summary, view } = machine;\n const hay = [summary.machineId, summary.process, summary.role, view?.address ?? summary.address ?? ''].join(' ').toLowerCase();\n return hay.includes(needle);\n}\n\n/**\n * One dense line per machine in line order, in a list that scrolls within\n * the region. The search narrows the declared list by id, process, role or address.\n */\nexport function MachineRows({\n machines,\n selectedId,\n onSelect,\n}: {\n machines: StripMachine[];\n selectedId: string | null;\n onSelect: (machineId: string) => void;\n}) {\n const [query, setQuery] = useState('');\n const needle = query.trim().toLowerCase();\n const shown = useMemo(() => machines.filter((m) => matches(m, needle)), [machines, needle]);\n return (\n <div className=\"flex flex-col h-full min-h-0\">\n <div className=\"flex items-center gap-3 pb-2 shrink-0\">\n <label className=\"sr-only\" htmlFor=\"machine-search\">Find a machine</label>\n <input\n id=\"machine-search\"\n type=\"search\"\n className=\"input text-2xs font-mono py-1 w-full max-w-[16rem]\"\n placeholder=\"id, process, role, address\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n />\n <span className=\"text-2xs text-text-quaternary tabular-nums\">{shown.length} of {machines.length}</span>\n </div>\n <ul className={ROWS_BOX_CLASS} aria-label=\"Machines\">\n {shown.map(({ summary, view }) => {\n const presence = presenceOf(view);\n const selected = summary.machineId === selectedId;\n const address = view?.address ?? summary.address;\n const alarms = view?.alarms.length ?? 0;\n return (\n <li key={summary.machineId}>\n <button\n type=\"button\"\n onClick={() => onSelect(summary.machineId)}\n aria-pressed={selected}\n data-presence={presence}\n className={`w-full text-left grid grid-cols-[auto_minmax(6rem,1fr)_minmax(0,2fr)_auto_auto_auto] items-baseline gap-x-3 px-2 py-1 border-l-2 border-b border-surface-border/60 hover:bg-surface-hover transition-colors ${\n selected ? 'border-l-accent' : 'border-l-transparent'\n }`}\n >\n <span className={`w-2 h-2 rounded-full dot-ring self-center ${PRESENCE_DOT[presence]}`} title={PRESENCE_LABEL[presence]} />\n <span className=\"text-2xs font-mono text-text-primary truncate\">{summary.machineId}</span>\n <span className=\"text-2xs font-mono text-text-tertiary truncate\" title={address ?? undefined}>\n {summary.process}\n {address ? <span className=\"text-text-quaternary\"> · {address}</span> : null}\n </span>\n <span className=\"text-2xs text-text-tertiary truncate max-w-[6rem]\" title=\"Software\">{view?.software ?? '—'}</span>\n <span className=\"text-2xs text-text-secondary tabular-nums whitespace-nowrap\" title=\"Units held\">held {view?.heldUnits.length ?? 0}</span>\n <span className=\"text-2xs font-mono text-text-tertiary tabular-nums whitespace-nowrap\">\n h {view?.rows.handoff ?? 0} c {view?.rows.command ?? 0} a {view?.rows.alarm ?? 0}\n {alarms > 0 && <span className=\"text-status-warning ml-2\" title=\"Active alarms\">{alarms} alarm{alarms === 1 ? '' : 's'}</span>}\n </span>\n </button>\n </li>\n );\n })}\n </ul>\n {shown.length === 0 && <p className=\"text-2xs text-text-tertiary py-2\">No machine matches.</p>}\n </div>\n );\n}\n","import type { LineSummaryMachine, MachineView } from '../../api/machines';\nimport { PRESENCE_DOT, PRESENCE_LABEL, presenceOf } from './wire-display';\n\nexport interface StripMachine {\n summary: LineSummaryMachine;\n /** Absent while the replica stands by or before the leader has heard the machine. */\n view: MachineView | undefined;\n}\n\n/**\n * One tile per machine in line order: presence ring, identity in mono, the\n * software it runs, what it holds, and its open rows by kind. Click selects.\n * Tiles fill the width in as many columns as fit.\n */\nexport function MachineStrip({\n machines,\n selectedId,\n onSelect,\n}: {\n machines: StripMachine[];\n selectedId: string | null;\n onSelect: (machineId: string) => void;\n}) {\n if (machines.length === 0) {\n return <p className=\"text-2xs text-text-tertiary\">The line declares no machines.</p>;\n }\n return (\n <div className=\"grid grid-cols-[repeat(auto-fill,minmax(11rem,1fr))] gap-y-3\" role=\"list\" aria-label=\"Machines\">\n {machines.map(({ summary, view }) => {\n const presence = presenceOf(view);\n const selected = summary.machineId === selectedId;\n const address = view?.address ?? summary.address;\n const alarms = view?.alarms.length ?? 0;\n return (\n <button\n key={summary.machineId}\n type=\"button\"\n role=\"listitem\"\n onClick={() => onSelect(summary.machineId)}\n aria-pressed={selected}\n data-presence={presence}\n className={`text-left min-w-0 pl-3 pr-4 py-1.5 border-l-2 transition-colors hover:bg-surface-hover ${\n selected ? 'border-accent' : 'border-surface-border'\n }`}\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <span\n className={`w-2.5 h-2.5 rounded-full dot-ring shrink-0 ${PRESENCE_DOT[presence]}`}\n title={PRESENCE_LABEL[presence]}\n />\n <span className=\"text-xs font-mono text-text-primary truncate\">{summary.machineId}</span>\n <span className=\"text-2xs text-text-quaternary ml-auto shrink-0\">{PRESENCE_LABEL[presence]}</span>\n </div>\n <div className=\"text-2xs font-mono text-text-tertiary truncate mt-0.5\" title={address ?? undefined}>\n {summary.process}\n {address ? <span className=\"text-text-quaternary\"> · {address}</span> : null}\n </div>\n <div className=\"flex items-center gap-3 text-2xs mt-1 tabular-nums\">\n <span className=\"text-text-tertiary truncate\" title=\"Software\">{view?.software ?? '—'}</span>\n <span className=\"text-text-secondary shrink-0\" title=\"Units held\">\n held {view?.heldUnits.length ?? 0}\n </span>\n </div>\n <div className=\"flex items-center gap-3 text-2xs font-mono mt-0.5 tabular-nums\">\n <span className=\"text-text-tertiary\" title=\"Open handoff rows\">h {view?.rows.handoff ?? 0}</span>\n <span className=\"text-text-tertiary\" title=\"Open command rows\">c {view?.rows.command ?? 0}</span>\n <span className=\"text-text-tertiary\" title=\"Open alarm rows\">a {view?.rows.alarm ?? 0}</span>\n {alarms > 0 && (\n <span className=\"text-status-warning ml-auto\" title=\"Active alarms\">\n {alarms} alarm{alarms === 1 ? '' : 's'}\n </span>\n )}\n </div>\n </button>\n );\n })}\n </div>\n );\n}\n","import { useMemo } from 'react';\nimport { LayoutGrid, List } from 'lucide-react';\nimport { MACHINE_VIEWS, MACHINE_VIEW_LABEL, needsAttention, type MachineViewMode } from './line-view-prefs';\nimport { MachineRows } from './MachineRows';\nimport { MachineStrip, type StripMachine } from './MachineStrip';\n\nconst VIEW_ICON: Record<MachineViewMode, typeof LayoutGrid> = { tiles: LayoutGrid, rows: List };\nconst RADIO_CLASS = 'p-1 transition-colors';\nconst RADIO_ON = 'text-text-primary bg-surface-sunken';\nconst RADIO_OFF = 'text-text-tertiary hover:text-text-primary';\n\nexport interface MachineViewsProps {\n machines: StripMachine[];\n selectedId: string | null;\n onSelect: (machineId: string) => void;\n view: MachineViewMode;\n onView: (view: MachineViewMode) => void;\n attentionOnly: boolean;\n onAttentionOnly: (on: boolean) => void;\n}\n\n/**\n * The machines region: the count, a needs-attention filter and the view\n * radios on the right (tiles or rows), with the chosen view filling the\n * region beneath. The region is bounded, so the wire below never moves.\n */\nexport function MachineViews(props: MachineViewsProps) {\n const { machines, selectedId, onSelect, view, onView, attentionOnly, onAttentionOnly } = props;\n const shown = useMemo(\n () => (attentionOnly ? machines.filter((m) => needsAttention(m.view)) : machines),\n [machines, attentionOnly],\n );\n const attention = useMemo(() => machines.filter((m) => needsAttention(m.view)).length, [machines]);\n if (machines.length === 0) {\n return <p className=\"text-2xs text-text-tertiary\">The line declares no machines.</p>;\n }\n const View = view === 'rows' ? MachineRows : MachineStrip;\n return (\n <section aria-label=\"Machines region\" data-view={view} className=\"flex flex-col h-full min-h-0\">\n <div className=\"flex items-center gap-3 pb-2 shrink-0\">\n <span className=\"text-2xs text-text-quaternary tabular-nums\">\n {machines.length} machine{machines.length === 1 ? '' : 's'}\n {attention > 0 && <span className=\"text-status-warning\"> · {attention} need{attention === 1 ? 's' : ''} attention</span>}\n </span>\n <span className=\"ml-auto flex items-center gap-3\">\n <button\n type=\"button\"\n aria-pressed={attentionOnly}\n onClick={() => onAttentionOnly(!attentionOnly)}\n className={`px-2 py-0.5 text-2xs rounded border transition-colors ${\n attentionOnly ? 'border-status-warning text-status-warning' : 'border-surface-border text-text-secondary hover:text-text-primary'\n }`}\n >\n Needs attention\n </button>\n <span className=\"inline-flex rounded border border-surface-border overflow-hidden\" role=\"radiogroup\" aria-label=\"Machines view\">\n {MACHINE_VIEWS.map((mode) => {\n const Icon = VIEW_ICON[mode];\n return (\n <button\n key={mode}\n type=\"button\"\n role=\"radio\"\n aria-checked={view === mode}\n aria-label={MACHINE_VIEW_LABEL[mode]}\n title={MACHINE_VIEW_LABEL[mode]}\n onClick={() => onView(mode)}\n className={`${RADIO_CLASS} ${view === mode ? RADIO_ON : RADIO_OFF}`}\n >\n <Icon className=\"w-3.5 h-3.5\" />\n </button>\n );\n })}\n </span>\n </span>\n </div>\n {shown.length === 0 ? (\n <p className=\"text-2xs text-text-tertiary py-1\">Every machine is quiet.</p>\n ) : (\n <div className=\"flex-1 min-h-0 overflow-y-auto\">\n <View machines={shown} selectedId={selectedId} onSelect={onSelect} />\n </div>\n )}\n </section>\n );\n}\n","import { ArrowDownLeft, ArrowUpRight } from 'lucide-react';\nimport type { WireEvent } from '../../api/machines';\nimport { describeAction, formatClock, visibleActions, WIRE_VERB_TONE } from './wire-display';\n\n/**\n * One line of the tape. At table width it is one row of columns: time,\n * direction, machine, channel and topic in mono, the summary, then the\n * violations and the actions the gateway took. Below it the row is a\n * dictionary: identity on the first line, the summary and the actions on\n * the second, the topic on the third.\n */\nexport function WireRow({ event, onOpen }: { event: WireEvent; onOpen: (event: WireEvent) => void }) {\n const actions = visibleActions(event.actions);\n const Direction = event.direction === 'in' ? ArrowDownLeft : ArrowUpRight;\n return (\n <li>\n <button\n type=\"button\"\n onClick={() => onOpen(event)}\n data-direction={event.direction}\n data-kind={event.kind}\n className=\"w-full text-left grid items-baseline gap-x-3 gap-y-0.5 px-2 py-1.5 border-b border-surface-border/60 hover:bg-surface-hover transition-colors\n grid-cols-[auto_auto_minmax(0,1fr)_auto]\n @table/tape:grid-cols-[auto_auto_6rem_11rem_minmax(0,1fr)_auto]\"\n >\n <span className=\"text-2xs font-mono tabular-nums text-text-quaternary\">{formatClock(event.at)}</span>\n <Direction\n className=\"w-3 h-3 self-center text-accent/65\"\n aria-label={event.direction === 'in' ? 'in' : 'out'}\n />\n <span\n className=\"text-2xs font-mono text-text-primary min-w-0 truncate col-span-2 @table/tape:col-span-1\"\n title={event.machineId ?? event.address ?? undefined}\n >\n {event.machineId ?? event.address ?? '—'}\n </span>\n <span\n className=\"text-2xs font-mono text-text-tertiary min-w-0 truncate col-start-3 col-span-2 @table/tape:col-start-4 @table/tape:col-span-1\"\n title={`${event.channel} ${event.topic}`}\n >\n {event.channel}\n <span className=\"text-text-quaternary\"> · </span>\n {event.topic}\n </span>\n <span\n className=\"text-xs text-text-secondary min-w-0 truncate col-start-3 @table/tape:col-start-5\"\n title={event.summary}\n >\n {event.summary || `${event.kind}${event.event ? ` · ${event.event}` : ''}`}\n </span>\n <span className=\"min-w-0 max-w-[12rem] @table/tape:max-w-[22rem] truncate text-2xs col-start-4 @table/tape:col-start-6\">\n {event.violations.length > 0 && (\n <span className=\"text-status-warning tabular-nums mr-2\" title={event.violations.join('\\n')}>\n {event.violations.length} violation{event.violations.length === 1 ? '' : 's'}\n </span>\n )}\n {actions.map((a, i) => (\n <span\n key={`${a.verb}-${a.rowId ?? ''}-${i}`}\n className={`${WIRE_VERB_TONE[a.verb] ?? 'text-text-secondary'} ${i < actions.length - 1 ? 'mr-2' : ''}`}\n >\n {describeAction(a)}\n </span>\n ))}\n </span>\n </button>\n </li>\n );\n}\n","import { Pause, Play, Eraser, X } from 'lucide-react';\nimport type { ReactNode, RefObject } from 'react';\nimport { WIRE_KINDS, type WireDirection, type WireEvent, type WireKind } from '../../api/machines';\nimport type { WireTapeFilters } from '../../hooks/useWireTape';\nimport { FilterBar, FilterSelect } from '../../components/common/data/FilterBar';\nimport { WireRow } from './WireRow';\n\nexport interface WireTapeProps {\n events: WireEvent[];\n total: number;\n paused: boolean;\n heldCount: number;\n filters: WireTapeFilters;\n machines: string[];\n channels: string[];\n setFilter: (patch: Partial<WireTapeFilters>) => void;\n togglePause: () => void;\n clear: () => void;\n onOpen: (event: WireEvent) => void;\n /** Extra header controls after Clear: full screen, watch. */\n controls?: ReactNode;\n /** Sizes the scrolling list; the section decides how much room it has. */\n listClassName?: string;\n listRef?: RefObject<HTMLUListElement | null>;\n}\n\nconst DEFAULT_LIST_CLASS = 'flex-1 min-h-0';\n\nconst DIRECTIONS: { value: WireDirection; label: string }[] = [\n { value: 'in', label: 'in' },\n { value: 'out', label: 'out' },\n];\n\nfunction activeFilterCount(filters: WireTapeFilters): number {\n return [filters.machine, filters.channel, filters.direction, filters.kind].filter(Boolean).length\n + (filters.violationsOnly ? 1 : 0);\n}\n\n/**\n * The live list of wire events, newest first, with its filter band and the\n * pause that holds new arrivals aside while you read. The band folds its\n * controls behind one Filters button when the container is narrow; the rows\n * fold from columns into console cards below the table threshold.\n */\nexport function WireTape(props: WireTapeProps) {\n const { events, total, paused, heldCount, filters, machines, channels, setFilter, togglePause, clear, onOpen, controls, listClassName, listRef } = props;\n return (\n <div className=\"flex flex-col min-h-0 flex-1 @container/tape\">\n <FilterBar\n embedded\n activeFilterCount={activeFilterCount(filters)}\n actions={\n <>\n <span className=\"text-2xs text-text-quaternary tabular-nums whitespace-nowrap\">\n {events.length} shown · {total} on tape\n </span>\n <button\n type=\"button\"\n onClick={togglePause}\n aria-pressed={paused}\n className=\"inline-flex items-center gap-1 text-2xs icon-link whitespace-nowrap\"\n title={paused ? 'Resume the tape' : 'Pause the tape'}\n >\n {paused ? <Play className=\"w-3 h-3\" /> : <Pause className=\"w-3 h-3\" />}\n {paused ? `Resume${heldCount ? ` · ${heldCount} held` : ''}` : 'Pause'}\n </button>\n <button type=\"button\" onClick={clear} className=\"inline-flex items-center gap-1 text-2xs icon-link\" title=\"Clear the tape\">\n <Eraser className=\"w-3 h-3\" />\n Clear\n </button>\n {controls}\n </>\n }\n >\n <FilterSelect\n label=\"Machine\"\n value={filters.machine ?? ''}\n onChange={(v) => setFilter({ machine: v || null })}\n options={machines.map((m) => ({ value: m, label: m }))}\n placeholder=\"every machine\"\n />\n <FilterSelect\n label=\"Channel\"\n value={filters.channel ?? ''}\n onChange={(v) => setFilter({ channel: v || null })}\n options={channels.map((c) => ({ value: c, label: c }))}\n placeholder=\"every channel\"\n />\n <FilterSelect\n label=\"Direction\"\n value={filters.direction ?? ''}\n onChange={(v) => setFilter({ direction: (v || null) as WireDirection | null })}\n options={DIRECTIONS}\n placeholder=\"both\"\n />\n <FilterSelect\n label=\"Kind\"\n value={filters.kind ?? ''}\n onChange={(v) => setFilter({ kind: (v || null) as WireKind | null })}\n options={WIRE_KINDS.map((k) => ({ value: k, label: k }))}\n placeholder=\"every kind\"\n />\n <button\n type=\"button\"\n aria-pressed={filters.violationsOnly}\n onClick={() => setFilter({ violationsOnly: !filters.violationsOnly })}\n className={`self-start px-2 py-1 text-2xs rounded border transition-colors whitespace-nowrap ${\n filters.violationsOnly\n ? 'border-status-warning text-status-warning'\n : 'border-surface-border text-text-secondary hover:text-text-primary'\n }`}\n >\n Violations only\n </button>\n </FilterBar>\n {filters.machine && (\n <div className=\"flex items-center gap-2 px-3 py-1.5 text-2xs shrink-0\">\n <span className=\"text-text-quaternary\">Following</span>\n <button\n type=\"button\"\n onClick={() => setFilter({ machine: null })}\n className=\"inline-flex items-center gap-1 rounded-full border border-surface-border px-2 py-0.5 font-mono text-text-primary hover:text-accent transition-colors\"\n title=\"Show every machine\"\n >\n {filters.machine}\n <X className=\"w-3 h-3\" />\n <span className=\"font-sans text-text-tertiary\">release</span>\n </button>\n </div>\n )}\n {events.length === 0 ? (\n <p className=\"text-2xs text-text-tertiary px-3 py-3\">\n {total === 0 ? 'Waiting for traffic on the wire.' : 'Every event on the tape is filtered out.'}\n </p>\n ) : (\n <ul ref={listRef} className={`${listClassName ?? DEFAULT_LIST_CLASS} overflow-y-auto`} aria-label=\"Wire tape\">\n {events.map((event) => (\n <WireRow key={`${event.at}-${event.id ?? ''}-${event.topic}-${event.direction}`} event={event} onOpen={onOpen} />\n ))}\n </ul>\n )}\n </div>\n );\n}\n","import { useRef } from 'react';\nimport { Maximize2, Minimize2, Radio } from 'lucide-react';\nimport { FullscreenOverlay } from '../../components/common/layout/FullscreenOverlay';\nimport { WireTape, type WireTapeProps } from './WireTape';\n\n/** The embed: a bordered box of its own, the band inside, the list scrolling within. */\nexport const TAPE_BOX_CLASS = 'flex flex-col h-full min-h-0 overflow-hidden rounded-[var(--lt-radius-section)] border border-surface-border bg-surface-sunken';\n\nexport interface TapeSectionProps extends Omit<WireTapeProps, 'controls' | 'listClassName' | 'listRef'> {\n fullscreen: boolean;\n onFullscreen: (open: boolean) => void;\n /** Whether the shell's event stream already carries this line's wire. */\n watching: boolean;\n onWatch: () => void;\n}\n\n/**\n * The wire as an embed beneath the machines: boxed in, its filters and\n * controls in its own band, a full-screen view in the shell's overlay, and\n * a way to keep watching the line from the event stream anywhere in the app.\n */\nexport function TapeSection(props: TapeSectionProps) {\n const { fullscreen, onFullscreen, watching, onWatch, ...tape } = props;\n const listRef = useRef<HTMLUListElement | null>(null);\n const controls = (\n <>\n <button type=\"button\" onClick={() => onFullscreen(true)} className=\"inline-flex items-center gap-1 text-2xs icon-link\" title=\"Full screen\">\n <Maximize2 className=\"w-3 h-3\" />\n Full screen\n </button>\n <button\n type=\"button\"\n onClick={onWatch}\n disabled={watching}\n className=\"inline-flex items-center gap-1 text-2xs icon-link disabled:opacity-60\"\n title={watching ? 'The event stream carries this line' : 'Add this line to the event stream'}\n >\n <Radio className=\"w-3 h-3\" />\n {watching ? 'Watching' : 'Watch on the event stream'}\n </button>\n </>\n );\n return (\n <section aria-label=\"Wire tape\" className={TAPE_BOX_CLASS}>\n <WireTape {...tape} controls={controls} listRef={listRef} />\n <FullscreenOverlay open={fullscreen} onClose={() => onFullscreen(false)} sourceRef={listRef}>\n <div className=\"sticky top-0 float-right z-10\">\n <button\n type=\"button\"\n onClick={() => onFullscreen(false)}\n className=\"p-2 rounded text-text-tertiary hover:text-text-primary hover:bg-surface-raised transition-colors duration-150 bg-surface-sunken/80 backdrop-blur-sm\"\n title=\"Close (Esc)\"\n >\n <Minimize2 className=\"w-5 h-5\" />\n </button>\n </div>\n {fullscreen && <WireTape {...tape} listClassName=\"min-h-[60vh]\" />}\n </FullscreenOverlay>\n </section>\n );\n}\n","import { Link } from 'react-router-dom';\nimport { X } from 'lucide-react';\nimport type { WireEvent } from '../../api/machines';\nimport { PanelField } from '../../components/common/layout/SlidePanel';\nimport { formatDateTime } from '../../lib/format';\nimport { describeAction, formatJson, rowPath, visibleActions, WIRE_VERB_TONE } from './wire-display';\n\nexport const WIRE_PANEL_KEY = 'wire';\n\n/**\n * One wire event in full: the envelope, the payload when the server sends it,\n * the violations, and each action with a link to its row.\n */\nexport function WireDetailPanel({ event, onClose }: { event: WireEvent; onClose: () => void }) {\n const actions = visibleActions(event.actions);\n return (\n <div className=\"h-full flex flex-col\">\n <div className=\"flex items-start justify-between px-5 pt-5 pb-3 border-b border-surface-border/40\">\n <div className=\"min-w-0\">\n <p className=\"text-2xs font-semibold uppercase tracking-widest text-text-tertiary\">\n {event.kind}{event.event ? <span className=\"normal-case font-mono\"> · {event.event}</span> : null}\n </p>\n <p className=\"text-sm text-text-primary mt-0.5\">{event.summary || event.topic}</p>\n </div>\n <button onClick={onClose} className=\"icon-link shrink-0 ml-2\" title=\"Close\">\n <X className=\"w-4 h-4\" />\n </button>\n </div>\n\n <div className=\"flex-1 overflow-y-auto px-5 py-4 space-y-5\">\n <dl className=\"grid grid-cols-2 gap-x-4 gap-y-3\">\n <PanelField label=\"At\">{formatDateTime(event.at)}</PanelField>\n <PanelField label=\"Direction\">{event.direction}</PanelField>\n <PanelField label=\"Machine\"><span className=\"font-mono\">{event.machineId ?? '—'}</span></PanelField>\n <PanelField label=\"Address\"><span className=\"font-mono\">{event.address ?? '—'}</span></PanelField>\n <PanelField label=\"Channel\"><span className=\"font-mono\">{event.channel}</span></PanelField>\n <PanelField label=\"Retained\">{event.retained ? 'yes' : 'no'}</PanelField>\n <div className=\"col-span-2\">\n <PanelField label=\"Topic\"><span className=\"font-mono break-all\">{event.topic}</span></PanelField>\n </div>\n {event.id && (\n <div className=\"col-span-2\">\n <PanelField label=\"Message id\"><span className=\"font-mono break-all\">{event.id}</span></PanelField>\n </div>\n )}\n </dl>\n\n <section>\n <p className=\"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1.5\">\n Violations{event.violations.length ? ` · ${event.violations.length}` : ''}\n </p>\n {event.violations.length === 0 ? (\n <p className=\"text-2xs text-text-quaternary\">The message matched the contract.</p>\n ) : (\n <ul className=\"space-y-1\">\n {event.violations.map((v, i) => (\n <li key={i} className=\"text-xs text-status-warning\">{v}</li>\n ))}\n </ul>\n )}\n </section>\n\n <section>\n <p className=\"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1.5\">Actions</p>\n {actions.length === 0 ? (\n <p className=\"text-2xs text-text-quaternary\">The gateway took no action.</p>\n ) : (\n <ul className=\"space-y-1.5\">\n {actions.map((a, i) => (\n <li key={`${a.verb}-${i}`} className=\"text-xs\">\n <span className={WIRE_VERB_TONE[a.verb]}>{describeAction(a)}</span>\n {a.rowId && (\n <>\n {' '}\n <Link to={rowPath(a.rowId)} className=\"font-mono text-accent hover:underline\">{a.rowId}</Link>\n </>\n )}\n {a.detail && <span className=\"block text-2xs text-text-tertiary\">{a.detail}</span>}\n </li>\n ))}\n </ul>\n )}\n </section>\n\n <section>\n <p className=\"text-2xs font-semibold uppercase tracking-widest text-text-tertiary mb-1.5\">Payload</p>\n {event.payload === undefined ? (\n <p className=\"text-2xs text-text-quaternary\">Builders see the payload here.</p>\n ) : (\n <pre className=\"text-2xs font-mono text-text-secondary whitespace-pre-wrap break-all bg-surface-sunken rounded px-2 py-1.5\">\n {formatJson(event.payload)}\n </pre>\n )}\n </section>\n </div>\n </div>\n );\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n machineLineQueryKey,\n machineWirePattern,\n useLine,\n type LineSummaryMachine,\n type WireEvent,\n} from '../../api/machines';\nimport { PageHeader } from '../../components/common/layout/PageHeader';\nimport { useAccess } from '../../hooks/useAccess';\nimport { useEventSubscriptions } from '../../hooks/useEventContext';\nimport { useThrottledInvalidation } from '../../hooks/useEventHooks';\nimport { useEventFeedPatterns } from '../../hooks/useEventFeedPatterns';\nimport { useShellPanel } from '../../hooks/useShellPanel';\nimport { useWireTape } from '../../hooks/useWireTape';\nimport { escalationPattern } from '../../lib/events/subjects';\nimport { formatDateTime } from '../../lib/format';\nimport {\n MACHINE_VIEWS,\n autoMachineView,\n machineViewStorageKey,\n readStored,\n writeStored,\n type MachineViewMode,\n} from './line-view-prefs';\nimport { MachinePanel, MACHINE_PANEL_KEY, MACHINE_PANEL_WIDTH } from './MachinePanel';\nimport type { StripMachine } from './MachineStrip';\nimport { MachineViews } from './MachineViews';\nimport { TapeSection } from './TapeSection';\nimport { WireDetailPanel, WIRE_PANEL_KEY } from './WireDetailPanel';\n\nconst WIRE_PANEL_WIDTH = 420;\n/** The machines take three quarters of the page below the header, the wire the last quarter. */\nconst MACHINES_REGION_CLASS = 'flex-[3] min-h-0 flex flex-col mb-4';\nconst TAPE_REGION_CLASS = 'flex-[1] min-h-[14rem] flex flex-col';\n\n/** The tape's size, remembered per device. */\n/** The machines view: the count picks it, an override remembered per line wins. */\nfunction useMachineView(siteId: string, lineId: string, count: number): [MachineViewMode, (view: MachineViewMode) => void] {\n const key = machineViewStorageKey(siteId, lineId);\n const [override, setOverride] = useState<MachineViewMode | null>(() => readStored(key, MACHINE_VIEWS));\n useEffect(() => {\n setOverride(readStored(key, MACHINE_VIEWS));\n }, [key]);\n const choose = useCallback((view: MachineViewMode) => {\n setOverride(view);\n writeStored(key, view);\n }, [key]);\n return [override ?? autoMachineView(count), choose];\n}\n\n/**\n * Line state refreshes through the LIST tier on the line's own wire events\n * and on escalation events in the roles its machines own.\n */\nfunction useLineRefresh(siteId: string, lineId: string, roles: string[]) {\n const invalidate = useThrottledInvalidation('LIST');\n const patterns = useMemo(\n () => [machineWirePattern(siteId, lineId), ...roles.map((role) => escalationPattern({ role }))],\n [siteId, lineId, roles],\n );\n useEventSubscriptions(patterns, () => {\n invalidate([machineLineQueryKey(siteId, lineId)]);\n });\n}\n\n/** One line: the machines region, the tape section, the machine and wire panels. */\nexport function LinePage() {\n const { siteId = '', lineId = '' } = useParams<{ siteId: string; lineId: string }>();\n const { isOps, isBuilder } = useAccess();\n const canAct = isOps || isBuilder;\n const { data: line, isLoading, error } = useLine(siteId, lineId);\n const { setPanel, closePanel, ownerKey } = useShellPanel();\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [fullscreen, setFullscreen] = useState(false);\n const [attentionOnly, setAttentionOnly] = useState(false);\n const { userPatterns, addPattern } = useEventFeedPatterns();\n\n const summary = line?.summary ?? null;\n // The summary is line order; the view, when leading, enriches each tile.\n const machines = useMemo<StripMachine[]>(() => {\n const views = new Map((line?.machines ?? []).map((m) => [m.machineId, m]));\n const declared: LineSummaryMachine[] = summary?.machines\n ?? (line?.machines ?? []).map((m) => ({\n machineId: m.machineId, process: m.process, role: m.role, address: m.address, addressing: 'declared' as const,\n }));\n return declared.map((s) => ({ summary: s, view: views.get(s.machineId) }));\n }, [summary, line]);\n const roles = useMemo(() => [...new Set(machines.map((m) => m.summary.role))].sort(), [machines]);\n\n useLineRefresh(siteId, lineId, roles);\n const tape = useWireTape(siteId, lineId);\n const [machineView, setMachineView] = useMachineView(siteId, lineId, machines.length);\n const wirePattern = machineWirePattern(siteId, lineId);\n const watching = userPatterns.includes(wirePattern);\n\n const selected = machines.find((m) => m.summary.machineId === selectedId) ?? null;\n // One focus: the chosen machine opens its panel and the tape follows it.\n const selectMachine = useCallback((machineId: string) => {\n setSelectedId(machineId);\n tape.setFilter({ machine: machineId });\n }, [tape.setFilter]);\n const closeMachine = useCallback(() => {\n setSelectedId(null);\n closePanel(MACHINE_PANEL_KEY);\n }, [closePanel]);\n\n // The panel re-renders with every refresh of the line while it stays selected.\n useEffect(() => {\n if (!selected) return;\n setPanel(\n <MachinePanel\n siteId={siteId}\n lineId={lineId}\n summary={selected.summary}\n view={selected.view}\n canAct={canAct}\n onClose={closeMachine}\n />,\n { key: MACHINE_PANEL_KEY, width: MACHINE_PANEL_WIDTH },\n );\n }, [selected, siteId, lineId, canAct, closeMachine, setPanel]);\n\n // Another claimant taking the slot (a wire row, a timeline) clears the\n // selection. Ownership is tracked, since the slot changes hands one render\n // after the selection is made.\n const ownedRef = useRef(false);\n useEffect(() => {\n if (ownerKey === MACHINE_PANEL_KEY) {\n ownedRef.current = true;\n return;\n }\n if (ownedRef.current) {\n ownedRef.current = false;\n setSelectedId(null);\n }\n }, [ownerKey]);\n\n const openWire = useCallback((event: WireEvent) => {\n setPanel(\n <WireDetailPanel event={event} onClose={() => closePanel(WIRE_PANEL_KEY)} />,\n { key: WIRE_PANEL_KEY, width: WIRE_PANEL_WIDTH },\n );\n }, [setPanel, closePanel]);\n\n const standingBy = !!line && !line.leading;\n\n return (\n <div className=\"flex flex-col flex-1 min-h-0\">\n <PageHeader\n title={<span className=\"font-mono\">{siteId} · {lineId}</span>}\n actions={\n line?.leading && line.takenAt ? (\n <span className=\"text-2xs text-text-quaternary\">leading since {formatDateTime(line.takenAt)}</span>\n ) : null\n }\n />\n\n {isLoading && <p className=\"text-2xs text-text-tertiary italic mb-4\">Loading the line…</p>}\n {error && <p className=\"text-2xs text-status-error mb-4\">{(error as Error).message}</p>}\n {standingBy && (\n <p className=\"text-xs text-text-secondary mb-4\" data-testid=\"standing-by\">\n Standing by. Another replica leads this line; the tape stays live from the leader.\n </p>\n )}\n {line && line.contested.length > 0 && (\n <p className=\"text-2xs text-status-warning mb-4\">\n Contested: {line.contested.map((c) => `${c.address} at ${c.station}`).join(', ')}\n </p>\n )}\n\n <div className={MACHINES_REGION_CLASS}>\n <MachineViews\n machines={machines}\n selectedId={selectedId}\n onSelect={selectMachine}\n view={machineView}\n onView={setMachineView}\n attentionOnly={attentionOnly}\n onAttentionOnly={setAttentionOnly}\n />\n </div>\n\n <div className={TAPE_REGION_CLASS}>\n <TapeSection\n events={tape.events}\n total={tape.total}\n paused={tape.paused}\n heldCount={tape.heldCount}\n filters={tape.filters}\n machines={tape.machines}\n channels={tape.channels}\n setFilter={tape.setFilter}\n togglePause={tape.togglePause}\n clear={tape.clear}\n onOpen={openWire}\n fullscreen={fullscreen}\n onFullscreen={setFullscreen}\n watching={watching}\n onWatch={() => addPattern(wirePattern)}\n />\n </div>\n </div>\n );\n}\n"],"names":["WIRE_TAPE_CAPACITY","EMPTY_FILTERS","initialTapeState","cap","events","wireTapeReducer","state","action","matchesFilters","event","filters","applyFilters","KINDS","WIRE_KINDS","toWireEvent","raw","envelope","type","WIRE_EVENT_TYPE","e","kind","at","v","distinct","values","useWireTape","siteId","lineId","dispatch","useReducer","useEffect","useEventSubscription","machineWirePattern","visible","useMemo","machines","channels","setFilter","useCallback","patch","togglePause","clear","MACHINE_VIEWS","MACHINE_VIEW_LABEL","TILES_MAX","machineViewStorageKey","autoMachineView","count","readStored","key","allowed","value","writeStored","needsAttention","view","WIRE_VERB_LABEL","WIRE_VERB_TONE","describeAction","label","visibleActions","actions","a","rowPath","rowId","formatClock","iso","date","zone","getDisplayTimeZone","PRESENCE_DOT","PRESENCE_LABEL","presenceOf","formatJson","CommandOutcomeBody","outcome","jsxs","jsx","Link","ARG_HELPERS","mergeArgKey","text","current","parsed","parseArgs","CommandForm","machine","op","setOp","useState","args","setArgs","busy","setBusy","setOutcome","ops","commandOpsFor","submit","request","receipt","sendCommand","err","o","t","SnapshotButton","machineId","ask","SNAPSHOT_OP","RETAINED_CHOICES","parsePayload","trimmed","InspectOutcomeBody","Fragment","i","InspectForm","topic","setTopic","payload","setPayload","retained","setRetained","choice","c","result","inspectMessage","MACHINE_PANEL_KEY","MACHINE_PANEL_WIDTH","TIMELINE_PANEL_KEY","Section","title","children","RowLink","MachinePanel","summary","canAct","onClose","presence","shell","useShellPanelOptional","jobsOpen","setJobsOpen","openTimeline","facetKey","EntityTimelinePanel","alarms","held","jobs","X","PanelField","formatDateTime","ChevronRight","u","MACHINE_FACETS","ROWS_BOX_CLASS","matches","needle","MachineRows","selectedId","onSelect","query","setQuery","shown","m","selected","address","MachineStrip","VIEW_ICON","LayoutGrid","List","RADIO_CLASS","RADIO_ON","RADIO_OFF","MachineViews","props","onView","attentionOnly","onAttentionOnly","attention","View","mode","Icon","WireRow","onOpen","Direction","ArrowDownLeft","ArrowUpRight","DEFAULT_LIST_CLASS","DIRECTIONS","activeFilterCount","WireTape","total","paused","heldCount","controls","listClassName","listRef","FilterBar","Play","Pause","Eraser","FilterSelect","k","TAPE_BOX_CLASS","TapeSection","fullscreen","onFullscreen","watching","onWatch","tape","useRef","Maximize2","Radio","FullscreenOverlay","Minimize2","WIRE_PANEL_KEY","WireDetailPanel","WIRE_PANEL_WIDTH","MACHINES_REGION_CLASS","TAPE_REGION_CLASS","useMachineView","override","setOverride","choose","useLineRefresh","roles","invalidate","useThrottledInvalidation","patterns","role","escalationPattern","useEventSubscriptions","machineLineQueryKey","LinePage","useParams","isOps","isBuilder","useAccess","line","isLoading","error","useLine","setPanel","closePanel","ownerKey","useShellPanel","setSelectedId","setFullscreen","setAttentionOnly","userPatterns","addPattern","useEventFeedPatterns","views","s","machineView","setMachineView","wirePattern","selectMachine","closeMachine","ownedRef","openWire","standingBy","PageHeader"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{a as c,j as e}from"./vendor-query-DvWWuNIB.js";import{d as z,r as U,u as B,M as D,a as O,m as H,b as K}from"./machines-BqOZZU-3.js";import{D as P}from"./DataTable-FjFhx0SE.js";import{F as J,a as Q,b as T}from"./FilterBar-BVyAjIgv.js";import{S as V}from"./StickyPagination-B0FSuUgs.js";import{P as X}from"./PageHeader-Hx8APPwE.js";import{ax as G,bi as W,O as Z,a_ as ee,j as R,b1 as te}from"./index-CkMHS-hG.js";import{u as se}from"./useDebouncedValue-B_1u1YIk.js";import{u as ne}from"./useFilterParams-DBRw1Hcv.js";import{X as ae,ac as ie,h as re}from"./vendor-icons-fxBvvHBi.js";import{L as le,u as oe}from"./vendor-react-_9U4mKFr.js";import"./EmptyState-DgC_6njU.js";import"./useContainerWidth-DSLp1gEm.js";const ce={attention:"bg-status-warning",running:"bg-status-success-graphic",idle:"bg-text-quaternary"},de={attention:"needs attention",running:"running",idle:"idle"};function me(t){return t.health.attention?"attention":t.leading||t.health.handoff>0||t.health.command>0?"running":"idle"}const q=[{value:"attention",label:"Attention first"},{value:"site",label:"Site and line"},{value:"updated",label:"Recently changed"}];function ue(t){const i=new Map;for(const s of t){const n=i.get(s.siteId)??{siteId:s.siteId,lines:[],attention:0};n.lines.push(s),s.health.attention&&(n.attention+=1),i.set(s.siteId,n)}return[...i.values()]}const xe={siteId:"site-2",lineId:"line-1",machines:[{machineId:"print-01",process:"print",cycleSec:12},{machineId:"press-01",process:"bond",cycleSec:8},{machineId:"inspect-01",process:"inspect",cycleSec:5}]};function he(t){return`${JSON.stringify(t,null,2)}
|
|
2
|
+
`}function pe(t){return{siteId:t.siteId,lineId:t.lineId,machines:t.machines.map(i=>({machineId:i.machineId,process:i.process,...i.address?{address:i.address}:{}}))}}function fe(t){let i;try{i=JSON.parse(t)}catch(n){return{ok:!1,message:`The definition is not JSON: ${n.message}`}}if(!i||typeof i!="object"||Array.isArray(i))return{ok:!1,message:"The definition must be an object."};const s=i;if(typeof s.siteId!="string"||!s.siteId)return{ok:!1,message:"siteId is required."};if(typeof s.lineId!="string"||!s.lineId)return{ok:!1,message:"lineId is required."};if(!Array.isArray(s.machines)||s.machines.length===0)return{ok:!1,message:"machines must list at least one machine."};for(const n of s.machines)if(!n||typeof n!="object"||typeof n.machineId!="string"||typeof n.process!="string")return{ok:!1,message:"Every machine needs a machineId and a process."};return{ok:!0,definition:s}}const E="line-declare",ge=460;function ye({outcome:t}){return e.jsxs("div",{className:"min-w-0 space-y-1","data-testid":"declare-outcome",children:[e.jsx("div",{className:"text-xs font-mono text-text-secondary truncate",title:t.request,children:t.request}),e.jsx("div",{className:`text-xs font-medium ${t.ok?"text-status-success":"text-status-error"}`,children:t.message})]})}function _(t){return t instanceof G&&t.status===409?`Someone changed this line first: ${t.message}`:t.message}function be({initial:t,onClose:i,onDone:s}){const[n,N]=c.useState(()=>he(t?pe(t):xe)),[l,g]=c.useState(t?String(t.version):""),[o,u]=c.useState(!1),[x,p]=c.useState(!1),[j,r]=c.useState(null),S=async d=>{d.preventDefault();const m=fe(n);if(!m.ok){r({request:"definition",ok:!1,message:m.message});return}const{siteId:y,lineId:I}=m.definition,b=`PUT /machines/lines/${y}/${I}`;u(!0);try{const f=l.trim(),{line:h}=await z(y,I,{definition:m.definition,...f?{version:Number(f)}:{}});r({request:b,ok:!0,message:`declared · ${h.machines.length} machine${h.machines.length===1?"":"s"} · v${h.version}`}),s()}catch(f){r({request:b,ok:!1,message:_(f)})}finally{u(!1)}},v=async()=>{if(!t)return;const d=`DELETE /machines/lines/${t.siteId}/${t.lineId}`;u(!0);try{await U(t.siteId,t.lineId),r({request:d,ok:!0,message:"retired · its gateway stops on every replica"}),p(!1),s()}catch(m){r({request:d,ok:!1,message:_(m)})}finally{u(!1)}};return e.jsxs("div",{className:"h-full flex flex-col",children:[e.jsxs("div",{className:"flex items-start justify-between px-5 pt-5 pb-3 border-b border-surface-border/40",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-sm font-mono text-text-primary truncate",children:t?`${t.siteId} · ${t.lineId}`:"Declare a line"}),e.jsx("p",{className:"text-2xs text-text-tertiary mt-0.5",children:t?`${t.source} · v${t.version}`:"The registry keeps it; every replica starts its gateway."})]}),e.jsx("button",{onClick:i,className:"icon-link shrink-0 ml-2",title:"Close",children:e.jsx(ae,{className:"w-4 h-4"})})]}),e.jsxs("form",{onSubmit:S,className:"flex-1 overflow-y-auto px-5 py-4 space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"line-definition",className:"text-2xs font-medium text-text-secondary uppercase tracking-wide",children:"Definition"}),e.jsx("textarea",{id:"line-definition",value:n,onChange:d=>N(d.target.value),spellCheck:!1,rows:16,className:"input w-full mt-1 font-mono text-2xs"}),e.jsx("p",{className:"text-2xs text-text-quaternary mt-1",children:"siteId, lineId and the machines in route order, each with a machineId and a process."})]}),t&&e.jsxs("div",{children:[e.jsx("label",{htmlFor:"line-version",className:"text-2xs font-medium text-text-secondary uppercase tracking-wide",children:"Version"}),e.jsx("input",{id:"line-version",value:l,onChange:d=>g(d.target.value),inputMode:"numeric",className:"input mt-1 font-mono text-2xs w-24"}),e.jsx("p",{className:"text-2xs text-text-quaternary mt-1",children:"The version you edited; a newer one on the server refuses the save."})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("button",{type:"submit",disabled:o,className:"btn-primary text-xs",children:t?"Save":"Declare"}),t&&!x&&e.jsx("button",{type:"button",disabled:o,onClick:()=>p(!0),className:"text-2xs text-status-error hover:underline",children:"Retire this line"})]}),t&&x&&e.jsxs("div",{className:"border-l-2 border-status-error pl-3 space-y-2","data-testid":"retire-confirm",children:[e.jsxs("p",{className:"text-xs text-text-secondary",children:["Retire ",t.siteId," · ",t.lineId,"? Its gateway stops on every replica. Rows and roles stay."]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("button",{type:"button",disabled:o,onClick:v,className:"text-xs font-medium text-status-error hover:underline",children:"Retire"}),e.jsx("button",{type:"button",disabled:o,onClick:()=>p(!1),className:"text-xs text-text-secondary hover:underline",children:"Keep"})]})]}),j&&e.jsx(ye,{outcome:j})]})]})}function F(t){return`/lines/${encodeURIComponent(t.siteId)}/${encodeURIComponent(t.lineId)}`}function $({value:t,tone:i,title:s}){return e.jsx("span",{className:`tabular-nums ${t>0?i??"text-text-primary":"text-text-quaternary"}`,title:s,children:t})}function Ie(t){const i=[{key:"line",label:"Line",priority:1,render:s=>{const n=me(s);return e.jsxs("span",{className:"flex items-center gap-2 min-w-0",children:[e.jsx("span",{className:`w-2.5 h-2.5 rounded-full dot-ring shrink-0 ${ce[n]}`,title:de[n]}),e.jsxs(le,{to:F(s),className:"text-xs font-mono text-accent hover:underline truncate",title:`${s.siteId} · ${s.lineId}`,children:[s.siteId," · ",s.lineId]})]})}},{key:"machines",label:"Machines",className:"w-28",render:s=>e.jsxs("span",{className:"text-2xs tabular-nums",children:[e.jsx("span",{className:"text-text-primary",children:s.health.machines}),s.health.offline>0&&e.jsxs("span",{className:"text-status-warning",children:[" · ",s.health.offline," offline"]}),s.health.quiet>0&&e.jsxs("span",{className:"text-status-warning",children:[" · ",s.health.quiet," quiet"]})]})},{key:"alarms",label:"Alarms",className:"w-16 text-right",render:s=>e.jsx($,{value:s.health.alarms,tone:"text-status-warning",title:"Active alarms"})},{key:"people",label:"People",className:"w-16 text-right",render:s=>e.jsx($,{value:s.health.people,tone:"text-status-warning",title:"Rows waiting on a person"})},{key:"inflight",label:"In flight",className:"w-20 text-right",render:s=>e.jsx($,{value:s.health.handoff+s.health.command,title:"Open handoff and command rows"})},{key:"led",label:"Led",className:"w-20",render:s=>e.jsx("span",{className:`text-2xs ${s.leading?"text-text-primary":"text-text-tertiary"}`,children:s.leading?"here":"elsewhere"})},{key:"chain",label:"Chain",showFrom:"wall",priority:3,render:s=>e.jsx("span",{className:"text-2xs font-mono text-text-tertiary truncate block",title:s.machines.map(n=>n.machineId).join(" → "),children:s.machines.map(n=>n.machineId).join(" → ")})},{key:"source",label:"Source",showFrom:"wall",className:"w-28",priority:3,render:s=>e.jsxs("span",{className:"text-2xs text-text-tertiary tabular-nums",title:`changed ${W(s.updatedAt)}`,children:[s.source," · v",s.version]})}];return t&&i.push({key:"manage",label:"",className:"w-10",priority:1,render:s=>e.jsx("button",{type:"button",onClick:n=>{n.stopPropagation(),t(s)},className:"icon-link",title:`Edit ${s.siteId} · ${s.lineId}`,"aria-label":`Edit ${s.siteId} · ${s.lineId}`,children:e.jsx(ie,{className:"w-3.5 h-3.5"})})}),i}const Ne=50,M="settings",A="true",je="attention",k={undeclared:"Lines appear here once the server declares them.",none:"No lines declared yet.",noMatch:"No line matches.",loading:"Loading lines…"};function ve(){const t=R("LIST"),i=c.useMemo(()=>[H(),K()],[]);te(i,()=>{t([[D],[O],[M]])})}function ke({group:t}){return e.jsxs("div",{className:"flex items-baseline gap-3 pt-5 pb-1.5","data-testid":"site-heading",children:[e.jsx("span",{className:"text-xs font-mono text-text-primary",children:t.siteId}),e.jsxs("span",{className:"text-2xs text-text-quaternary tabular-nums",children:[t.lines.length," line",t.lines.length===1?"":"s"]}),t.attention>0&&e.jsxs("span",{className:"text-2xs text-status-warning tabular-nums",children:[t.attention," need",t.attention===1?"s":""," attention"]})]})}function Re(){const t=oe(),{canAdminister:i}=Z(),s=i,n=ee(),N=R("LIST"),{filters:l,setFilter:g,pagination:o}=ne({filters:{q:"",site:"",attention:"",sort:""},pageSize:Ne}),u=se(l.q),x=l.attention===A,p=q.some(a=>a.value===l.sort)?l.sort:je,j=c.useMemo(()=>({q:u||void 0,site:l.site||void 0,attention:x||void 0,sort:p,limit:o.pageSize,offset:o.offset}),[u,l.site,x,p,o.pageSize,o.offset]),{data:r,isLoading:S,error:v}=B(j);ve();const d=c.useCallback(()=>{N([[D],[O],[M]])},[N]),m=c.useCallback(()=>n==null?void 0:n.closePanel(E),[n]),y=c.useCallback(a=>{n==null||n.setPanel(e.jsx(be,{initial:a,onClose:m,onDone:d}),{key:E,width:ge})},[n,m,d]);c.useEffect(()=>()=>n==null?void 0:n.closePanel(E),[n]);const I=c.useMemo(()=>Ie(s?a=>y(a):null),[s,y]),b=!u&&!l.site,f=c.useMemo(()=>b&&r?ue(r.lines):[],[b,r]),h=(r==null?void 0:r.total)??0,C=[l.q,l.site,l.attention].filter(Boolean).length,Y=r!=null&&r.declared?C>0?k.noMatch:k.none:k.undeclared,w=a=>t(F(a));return e.jsxs("div",{children:[e.jsx(X,{title:"Lines"}),e.jsxs(J,{activeFilterCount:C,actions:e.jsxs(e.Fragment,{children:[e.jsxs("span",{className:"text-2xs text-text-quaternary tabular-nums whitespace-nowrap",children:[h," line",h===1?"":"s"]}),s&&e.jsxs("button",{type:"button",onClick:()=>y(null),className:"inline-flex items-center gap-1 text-2xs icon-link whitespace-nowrap",children:[e.jsx(re,{className:"w-3 h-3"}),"Declare line"]})]}),children:[e.jsx(Q,{label:"Search",value:l.q,onChange:a=>g("q",a),placeholder:"site, line, machine, process, address"}),e.jsx(T,{label:"Site",value:l.site,onChange:a=>g("site",a),options:((r==null?void 0:r.sites)??[]).map(a=>({value:a.siteId,label:`${a.siteId} · ${a.lines} line${a.lines===1?"":"s"}`})),placeholder:"every site"}),e.jsx(T,{label:"Order",value:p,onChange:a=>g("sort",a),options:q,required:!0}),e.jsx("button",{type:"button","aria-pressed":x,onClick:()=>g("attention",x?"":A),className:`self-start px-2 py-1 text-2xs rounded border transition-colors whitespace-nowrap ${x?"border-status-warning text-status-warning":"border-surface-border text-text-secondary hover:text-text-primary"}`,children:"Needs attention"})]}),v&&e.jsx("p",{className:"text-2xs text-status-error mb-4",children:v.message}),S?e.jsx("p",{className:"text-2xs text-text-tertiary italic",children:k.loading}):b&&f.length>0?f.map(a=>e.jsxs("section",{"aria-label":a.siteId,children:[e.jsx(ke,{group:a}),e.jsx(P,{columns:I,data:a.lines,keyFn:L=>`${L.siteId}/${L.lineId}`,onRowClick:w,layout:"fixed",inline:!0})]},a.siteId)):e.jsx(P,{columns:I,data:(r==null?void 0:r.lines)??[],keyFn:a=>`${a.siteId}/${a.lineId}`,onRowClick:w,layout:"fixed",emptyMessage:Y}),e.jsx(V,{page:o.page,totalPages:o.totalPages(h),onPageChange:o.setPage,total:h,pageSize:o.pageSize,onPageSizeChange:o.setPageSize})]})}export{Re as LinesPage};
|
|
3
|
+
//# sourceMappingURL=LinesPage-NqChsKcO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LinesPage-NqChsKcO.js","sources":["../../src/pages/lines/line-index.ts","../../src/pages/lines/LineDeclarePanel.tsx","../../src/pages/lines/LineIndexColumns.tsx","../../src/pages/lines/LinesPage.tsx"],"sourcesContent":["import type { LineDefinition, LineIndexRow, LineSort } from '../../api/machines';\n\n/** The tone of a line at a glance: attention, running, or nothing led anywhere yet. */\nexport type LineTone = 'attention' | 'running' | 'idle';\n\nexport const LINE_TONE_DOT: Record<LineTone, string> = {\n attention: 'bg-status-warning',\n running: 'bg-status-success-graphic',\n idle: 'bg-text-quaternary',\n};\n\nexport const LINE_TONE_LABEL: Record<LineTone, string> = {\n attention: 'needs attention',\n running: 'running',\n idle: 'idle',\n};\n\n/** Attention wins; a line with work in flight or a leader is running; otherwise idle. */\nexport function lineTone(row: LineIndexRow): LineTone {\n if (row.health.attention) return 'attention';\n if (row.leading || row.health.handoff > 0 || row.health.command > 0) return 'running';\n return 'idle';\n}\n\nexport const SORT_OPTIONS: { value: LineSort; label: string }[] = [\n { value: 'attention', label: 'Attention first' },\n { value: 'site', label: 'Site and line' },\n { value: 'updated', label: 'Recently changed' },\n];\n\nexport interface SiteGroup {\n siteId: string;\n lines: LineIndexRow[];\n attention: number;\n}\n\n/** Rows grouped under their site, in the order the page delivered them. */\nexport function groupBySite(lines: LineIndexRow[]): SiteGroup[] {\n const groups = new Map<string, SiteGroup>();\n for (const line of lines) {\n const group = groups.get(line.siteId) ?? { siteId: line.siteId, lines: [], attention: 0 };\n group.lines.push(line);\n if (line.health.attention) group.attention += 1;\n groups.set(line.siteId, group);\n }\n return [...groups.values()];\n}\n\n/** The starting point for a new declaration: three stations, the fields a line needs. */\nexport const EXAMPLE_DEFINITION: LineDefinition = {\n siteId: 'site-2',\n lineId: 'line-1',\n machines: [\n { machineId: 'print-01', process: 'print', cycleSec: 12 },\n { machineId: 'press-01', process: 'bond', cycleSec: 8 },\n { machineId: 'inspect-01', process: 'inspect', cycleSec: 5 },\n ],\n};\n\n/** The definition the registry holds for a row, as text to edit. */\nexport function definitionText(def: LineDefinition): string {\n return `${JSON.stringify(def, null, 2)}\\n`;\n}\n\n/** A row carries its summary fields; the definition is what it declared. */\nexport function definitionOf(row: LineIndexRow): LineDefinition {\n return {\n siteId: row.siteId,\n lineId: row.lineId,\n machines: row.machines.map((m) => ({\n machineId: m.machineId,\n process: m.process,\n ...(m.address ? { address: m.address } : {}),\n })),\n };\n}\n\n/** Parse what was typed; a readable message names what is missing. */\nexport function parseDefinition(text: string): { ok: true; definition: LineDefinition } | { ok: false; message: string } {\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (err) {\n return { ok: false, message: `The definition is not JSON: ${(err as Error).message}` };\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return { ok: false, message: 'The definition must be an object.' };\n const def = parsed as Record<string, unknown>;\n if (typeof def.siteId !== 'string' || !def.siteId) return { ok: false, message: 'siteId is required.' };\n if (typeof def.lineId !== 'string' || !def.lineId) return { ok: false, message: 'lineId is required.' };\n if (!Array.isArray(def.machines) || def.machines.length === 0) return { ok: false, message: 'machines must list at least one machine.' };\n for (const m of def.machines) {\n if (!m || typeof m !== 'object' || typeof (m as { machineId?: unknown }).machineId !== 'string' || typeof (m as { process?: unknown }).process !== 'string') {\n return { ok: false, message: 'Every machine needs a machineId and a process.' };\n }\n }\n return { ok: true, definition: def as unknown as LineDefinition };\n}\n","import { useState, type FormEvent } from 'react';\nimport { X } from 'lucide-react';\nimport { ApiError } from '../../api/client';\nimport { declareLine, retireLine, type LineIndexRow } from '../../api/machines';\nimport { definitionOf, definitionText, EXAMPLE_DEFINITION, parseDefinition } from './line-index';\n\nexport const DECLARE_PANEL_KEY = 'line-declare';\nexport const DECLARE_PANEL_WIDTH = 460;\n\ntype Outcome =\n | { request: string; ok: true; message: string }\n | { request: string; ok: false; message: string };\n\nfunction OutcomeBody({ outcome }: { outcome: Outcome }) {\n return (\n <div className=\"min-w-0 space-y-1\" data-testid=\"declare-outcome\">\n <div className=\"text-xs font-mono text-text-secondary truncate\" title={outcome.request}>{outcome.request}</div>\n <div className={`text-xs font-medium ${outcome.ok ? 'text-status-success' : 'text-status-error'}`}>{outcome.message}</div>\n </div>\n );\n}\n\nfunction messageOf(err: unknown): string {\n if (err instanceof ApiError && err.status === 409) return `Someone changed this line first: ${err.message}`;\n return (err as Error).message;\n}\n\n/**\n * Declare a line to the registry, or edit and retire one already declared.\n * The definition is the JSON the server validates; a retire asks once more\n * before it goes.\n */\nexport function LineDeclarePanel({\n initial,\n onClose,\n onDone,\n}: {\n initial: LineIndexRow | null;\n onClose: () => void;\n onDone: () => void;\n}) {\n const [text, setText] = useState(() => definitionText(initial ? definitionOf(initial) : EXAMPLE_DEFINITION));\n const [version, setVersion] = useState(initial ? String(initial.version) : '');\n const [busy, setBusy] = useState(false);\n const [confirmRetire, setConfirmRetire] = useState(false);\n const [outcome, setOutcome] = useState<Outcome | null>(null);\n\n const submit = async (e: FormEvent) => {\n e.preventDefault();\n const parsed = parseDefinition(text);\n if (!parsed.ok) {\n setOutcome({ request: 'definition', ok: false, message: parsed.message });\n return;\n }\n const { siteId, lineId } = parsed.definition;\n const request = `PUT /machines/lines/${siteId}/${lineId}`;\n setBusy(true);\n try {\n const trimmed = version.trim();\n const { line } = await declareLine(siteId, lineId, {\n definition: parsed.definition,\n ...(trimmed ? { version: Number(trimmed) } : {}),\n });\n setOutcome({ request, ok: true, message: `declared · ${line.machines.length} machine${line.machines.length === 1 ? '' : 's'} · v${line.version}` });\n onDone();\n } catch (err) {\n setOutcome({ request, ok: false, message: messageOf(err) });\n } finally {\n setBusy(false);\n }\n };\n\n const retire = async () => {\n if (!initial) return;\n const request = `DELETE /machines/lines/${initial.siteId}/${initial.lineId}`;\n setBusy(true);\n try {\n await retireLine(initial.siteId, initial.lineId);\n setOutcome({ request, ok: true, message: 'retired · its gateway stops on every replica' });\n setConfirmRetire(false);\n onDone();\n } catch (err) {\n setOutcome({ request, ok: false, message: messageOf(err) });\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <div className=\"h-full flex flex-col\">\n <div className=\"flex items-start justify-between px-5 pt-5 pb-3 border-b border-surface-border/40\">\n <div className=\"min-w-0\">\n <p className=\"text-sm font-mono text-text-primary truncate\">{initial ? `${initial.siteId} · ${initial.lineId}` : 'Declare a line'}</p>\n <p className=\"text-2xs text-text-tertiary mt-0.5\">\n {initial ? `${initial.source} · v${initial.version}` : 'The registry keeps it; every replica starts its gateway.'}\n </p>\n </div>\n <button onClick={onClose} className=\"icon-link shrink-0 ml-2\" title=\"Close\">\n <X className=\"w-4 h-4\" />\n </button>\n </div>\n\n <form onSubmit={submit} className=\"flex-1 overflow-y-auto px-5 py-4 space-y-4\">\n <div>\n <label htmlFor=\"line-definition\" className=\"text-2xs font-medium text-text-secondary uppercase tracking-wide\">Definition</label>\n <textarea\n id=\"line-definition\"\n value={text}\n onChange={(e) => setText(e.target.value)}\n spellCheck={false}\n rows={16}\n className=\"input w-full mt-1 font-mono text-2xs\"\n />\n <p className=\"text-2xs text-text-quaternary mt-1\">siteId, lineId and the machines in route order, each with a machineId and a process.</p>\n </div>\n {initial && (\n <div>\n <label htmlFor=\"line-version\" className=\"text-2xs font-medium text-text-secondary uppercase tracking-wide\">Version</label>\n <input\n id=\"line-version\"\n value={version}\n onChange={(e) => setVersion(e.target.value)}\n inputMode=\"numeric\"\n className=\"input mt-1 font-mono text-2xs w-24\"\n />\n <p className=\"text-2xs text-text-quaternary mt-1\">The version you edited; a newer one on the server refuses the save.</p>\n </div>\n )}\n <div className=\"flex items-center gap-3\">\n <button type=\"submit\" disabled={busy} className=\"btn-primary text-xs\">\n {initial ? 'Save' : 'Declare'}\n </button>\n {initial && !confirmRetire && (\n <button type=\"button\" disabled={busy} onClick={() => setConfirmRetire(true)} className=\"text-2xs text-status-error hover:underline\">\n Retire this line\n </button>\n )}\n </div>\n {initial && confirmRetire && (\n <div className=\"border-l-2 border-status-error pl-3 space-y-2\" data-testid=\"retire-confirm\">\n <p className=\"text-xs text-text-secondary\">\n Retire {initial.siteId} · {initial.lineId}? Its gateway stops on every replica. Rows and roles stay.\n </p>\n <div className=\"flex items-center gap-3\">\n <button type=\"button\" disabled={busy} onClick={retire} className=\"text-xs font-medium text-status-error hover:underline\">\n Retire\n </button>\n <button type=\"button\" disabled={busy} onClick={() => setConfirmRetire(false)} className=\"text-xs text-text-secondary hover:underline\">\n Keep\n </button>\n </div>\n </div>\n )}\n {outcome && <OutcomeBody outcome={outcome} />}\n </form>\n </div>\n );\n}\n","import { Link } from 'react-router-dom';\nimport { Pencil } from 'lucide-react';\nimport type { LineIndexRow } from '../../api/machines';\nimport type { Column } from '../../components/common/data/DataTable';\nimport { formatDateTime } from '../../lib/format';\nimport { LINE_TONE_DOT, LINE_TONE_LABEL, lineTone } from './line-index';\n\nexport function linePath(row: Pick<LineIndexRow, 'siteId' | 'lineId'>): string {\n return `/lines/${encodeURIComponent(row.siteId)}/${encodeURIComponent(row.lineId)}`;\n}\n\nfunction Count({ value, tone, title }: { value: number; tone?: string; title?: string }) {\n return (\n <span className={`tabular-nums ${value > 0 ? tone ?? 'text-text-primary' : 'text-text-quaternary'}`} title={title}>\n {value}\n </span>\n );\n}\n\n/** The index columns; `onEdit` adds the manage column for those who may declare. */\nexport function lineColumns(onEdit: ((row: LineIndexRow) => void) | null): Column<LineIndexRow>[] {\n const columns: Column<LineIndexRow>[] = [\n {\n key: 'line',\n label: 'Line',\n priority: 1,\n render: (row) => {\n const tone = lineTone(row);\n return (\n <span className=\"flex items-center gap-2 min-w-0\">\n <span className={`w-2.5 h-2.5 rounded-full dot-ring shrink-0 ${LINE_TONE_DOT[tone]}`} title={LINE_TONE_LABEL[tone]} />\n <Link to={linePath(row)} className=\"text-xs font-mono text-accent hover:underline truncate\" title={`${row.siteId} · ${row.lineId}`}>\n {row.siteId} · {row.lineId}\n </Link>\n </span>\n );\n },\n },\n {\n key: 'machines',\n label: 'Machines',\n className: 'w-28',\n render: (row) => (\n <span className=\"text-2xs tabular-nums\">\n <span className=\"text-text-primary\">{row.health.machines}</span>\n {row.health.offline > 0 && <span className=\"text-status-warning\"> · {row.health.offline} offline</span>}\n {row.health.quiet > 0 && <span className=\"text-status-warning\"> · {row.health.quiet} quiet</span>}\n </span>\n ),\n },\n {\n key: 'alarms',\n label: 'Alarms',\n className: 'w-16 text-right',\n render: (row) => <Count value={row.health.alarms} tone=\"text-status-warning\" title=\"Active alarms\" />,\n },\n {\n key: 'people',\n label: 'People',\n className: 'w-16 text-right',\n render: (row) => <Count value={row.health.people} tone=\"text-status-warning\" title=\"Rows waiting on a person\" />,\n },\n {\n key: 'inflight',\n label: 'In flight',\n className: 'w-20 text-right',\n render: (row) => <Count value={row.health.handoff + row.health.command} title=\"Open handoff and command rows\" />,\n },\n {\n key: 'led',\n label: 'Led',\n className: 'w-20',\n render: (row) => (\n <span className={`text-2xs ${row.leading ? 'text-text-primary' : 'text-text-tertiary'}`}>{row.leading ? 'here' : 'elsewhere'}</span>\n ),\n },\n {\n key: 'chain',\n label: 'Chain',\n showFrom: 'wall',\n priority: 3,\n render: (row) => (\n <span className=\"text-2xs font-mono text-text-tertiary truncate block\" title={row.machines.map((m) => m.machineId).join(' → ')}>\n {row.machines.map((m) => m.machineId).join(' → ')}\n </span>\n ),\n },\n {\n key: 'source',\n label: 'Source',\n showFrom: 'wall',\n className: 'w-28',\n priority: 3,\n render: (row) => (\n <span className=\"text-2xs text-text-tertiary tabular-nums\" title={`changed ${formatDateTime(row.updatedAt)}`}>\n {row.source} · v{row.version}\n </span>\n ),\n },\n ];\n if (onEdit) {\n columns.push({\n key: 'manage',\n label: '',\n className: 'w-10',\n priority: 1,\n render: (row) => (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onEdit(row);\n }}\n className=\"icon-link\"\n title={`Edit ${row.siteId} · ${row.lineId}`}\n aria-label={`Edit ${row.siteId} · ${row.lineId}`}\n >\n <Pencil className=\"w-3.5 h-3.5\" />\n </button>\n ),\n });\n }\n return columns;\n}\n","import { useCallback, useEffect, useMemo } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { Plus } from 'lucide-react';\nimport {\n MACHINE_LINE_INDEX_QUERY_KEY,\n MACHINE_LINES_QUERY_KEY,\n machineLinePattern,\n machineLogPattern,\n useLineIndex,\n type LineIndexRow,\n type LineSort,\n} from '../../api/machines';\nimport { DataTable } from '../../components/common/data/DataTable';\nimport { FilterBar, FilterInput, FilterSelect } from '../../components/common/data/FilterBar';\nimport { StickyPagination } from '../../components/common/data/StickyPagination';\nimport { PageHeader } from '../../components/common/layout/PageHeader';\nimport { useAccess } from '../../hooks/useAccess';\nimport { useDebouncedValue } from '../../hooks/useDebouncedValue';\nimport { useEventSubscriptions } from '../../hooks/useEventContext';\nimport { useThrottledInvalidation } from '../../hooks/useEventHooks';\nimport { useFilterParams } from '../../hooks/useFilterParams';\nimport { useShellPanelOptional } from '../../hooks/useShellPanel';\nimport { LineDeclarePanel, DECLARE_PANEL_KEY, DECLARE_PANEL_WIDTH } from './LineDeclarePanel';\nimport { lineColumns, linePath } from './LineIndexColumns';\nimport { groupBySite, SORT_OPTIONS, type SiteGroup } from './line-index';\n\nconst PAGE_SIZE = 50;\nconst SETTINGS_QUERY_KEY = 'settings';\nconst ATTENTION_ON = 'true';\nconst DEFAULT_SORT: LineSort = 'attention';\n\nconst COPY = {\n undeclared: 'Lines appear here once the server declares them.',\n none: 'No lines declared yet.',\n noMatch: 'No line matches.',\n loading: 'Loading lines…',\n} as const;\n\n/** The index refreshes through the LIST tier when a line is declared or retired, or a gateway logs. */\nfunction useIndexRefresh() {\n const invalidate = useThrottledInvalidation('LIST');\n const patterns = useMemo(() => [machineLinePattern(), machineLogPattern()], []);\n useEventSubscriptions(patterns, () => {\n invalidate([[MACHINE_LINE_INDEX_QUERY_KEY], [MACHINE_LINES_QUERY_KEY], [SETTINGS_QUERY_KEY]]);\n });\n}\n\nfunction SiteHeading({ group }: { group: SiteGroup }) {\n return (\n <div className=\"flex items-baseline gap-3 pt-5 pb-1.5\" data-testid=\"site-heading\">\n <span className=\"text-xs font-mono text-text-primary\">{group.siteId}</span>\n <span className=\"text-2xs text-text-quaternary tabular-nums\">\n {group.lines.length} line{group.lines.length === 1 ? '' : 's'}\n </span>\n {group.attention > 0 && (\n <span className=\"text-2xs text-status-warning tabular-nums\">{group.attention} need{group.attention === 1 ? 's' : ''} attention</span>\n )}\n </div>\n );\n}\n\n/**\n * Every declared line across every site: searchable, paged on the server,\n * trouble first, grouped by site until a search or a site narrows the page.\n */\nexport function LinesPage() {\n const navigate = useNavigate();\n const { canAdminister } = useAccess();\n const canDeclare = canAdminister;\n const shell = useShellPanelOptional();\n const invalidate = useThrottledInvalidation('LIST');\n const { filters, setFilter, pagination } = useFilterParams({\n filters: { q: '', site: '', attention: '', sort: '' },\n pageSize: PAGE_SIZE,\n });\n const q = useDebouncedValue(filters.q);\n const attention = filters.attention === ATTENTION_ON;\n const sort = (SORT_OPTIONS.some((o) => o.value === filters.sort) ? filters.sort : DEFAULT_SORT) as LineSort;\n\n const params = useMemo(\n () => ({ q: q || undefined, site: filters.site || undefined, attention: attention || undefined, sort, limit: pagination.pageSize, offset: pagination.offset }),\n [q, filters.site, attention, sort, pagination.pageSize, pagination.offset],\n );\n const { data, isLoading, error } = useLineIndex(params);\n useIndexRefresh();\n\n const refresh = useCallback(() => {\n invalidate([[MACHINE_LINE_INDEX_QUERY_KEY], [MACHINE_LINES_QUERY_KEY], [SETTINGS_QUERY_KEY]]);\n }, [invalidate]);\n\n const closeDeclare = useCallback(() => shell?.closePanel(DECLARE_PANEL_KEY), [shell]);\n const openDeclare = useCallback(\n (initial: LineIndexRow | null) => {\n shell?.setPanel(\n <LineDeclarePanel initial={initial} onClose={closeDeclare} onDone={refresh} />,\n { key: DECLARE_PANEL_KEY, width: DECLARE_PANEL_WIDTH },\n );\n },\n [shell, closeDeclare, refresh],\n );\n useEffect(() => () => shell?.closePanel(DECLARE_PANEL_KEY), [shell]);\n\n const columns = useMemo(() => lineColumns(canDeclare ? (row) => openDeclare(row) : null), [canDeclare, openDeclare]);\n const grouped = !q && !filters.site;\n const groups = useMemo(() => (grouped && data ? groupBySite(data.lines) : []), [grouped, data]);\n const total = data?.total ?? 0;\n const activeFilters = [filters.q, filters.site, filters.attention].filter(Boolean).length;\n const emptyMessage = !data?.declared ? COPY.undeclared : activeFilters > 0 ? COPY.noMatch : COPY.none;\n const openRow = (row: LineIndexRow) => navigate(linePath(row));\n\n return (\n <div>\n <PageHeader title=\"Lines\" />\n <FilterBar\n activeFilterCount={activeFilters}\n actions={\n <>\n <span className=\"text-2xs text-text-quaternary tabular-nums whitespace-nowrap\">\n {total} line{total === 1 ? '' : 's'}\n </span>\n {canDeclare && (\n <button type=\"button\" onClick={() => openDeclare(null)} className=\"inline-flex items-center gap-1 text-2xs icon-link whitespace-nowrap\">\n <Plus className=\"w-3 h-3\" />\n Declare line\n </button>\n )}\n </>\n }\n >\n <FilterInput label=\"Search\" value={filters.q} onChange={(v) => setFilter('q', v)} placeholder=\"site, line, machine, process, address\" />\n <FilterSelect\n label=\"Site\"\n value={filters.site}\n onChange={(v) => setFilter('site', v)}\n options={(data?.sites ?? []).map((s) => ({ value: s.siteId, label: `${s.siteId} · ${s.lines} line${s.lines === 1 ? '' : 's'}` }))}\n placeholder=\"every site\"\n />\n <FilterSelect label=\"Order\" value={sort} onChange={(v) => setFilter('sort', v)} options={SORT_OPTIONS} required />\n <button\n type=\"button\"\n aria-pressed={attention}\n onClick={() => setFilter('attention', attention ? '' : ATTENTION_ON)}\n className={`self-start px-2 py-1 text-2xs rounded border transition-colors whitespace-nowrap ${\n attention ? 'border-status-warning text-status-warning' : 'border-surface-border text-text-secondary hover:text-text-primary'\n }`}\n >\n Needs attention\n </button>\n </FilterBar>\n\n {error && <p className=\"text-2xs text-status-error mb-4\">{(error as Error).message}</p>}\n {isLoading ? (\n <p className=\"text-2xs text-text-tertiary italic\">{COPY.loading}</p>\n ) : grouped && groups.length > 0 ? (\n groups.map((group) => (\n <section key={group.siteId} aria-label={group.siteId}>\n <SiteHeading group={group} />\n <DataTable columns={columns} data={group.lines} keyFn={(row) => `${row.siteId}/${row.lineId}`} onRowClick={openRow} layout=\"fixed\" inline />\n </section>\n ))\n ) : (\n <DataTable\n columns={columns}\n data={data?.lines ?? []}\n keyFn={(row) => `${row.siteId}/${row.lineId}`}\n onRowClick={openRow}\n layout=\"fixed\"\n emptyMessage={emptyMessage}\n />\n )}\n\n <StickyPagination\n page={pagination.page}\n totalPages={pagination.totalPages(total)}\n onPageChange={pagination.setPage}\n total={total}\n pageSize={pagination.pageSize}\n onPageSizeChange={pagination.setPageSize}\n />\n </div>\n );\n}\n"],"names":["LINE_TONE_DOT","LINE_TONE_LABEL","lineTone","row","SORT_OPTIONS","groupBySite","lines","groups","line","group","EXAMPLE_DEFINITION","definitionText","def","definitionOf","m","parseDefinition","text","parsed","err","DECLARE_PANEL_KEY","DECLARE_PANEL_WIDTH","OutcomeBody","outcome","jsxs","jsx","messageOf","ApiError","LineDeclarePanel","initial","onClose","onDone","setText","useState","version","setVersion","busy","setBusy","confirmRetire","setConfirmRetire","setOutcome","submit","e","siteId","lineId","request","trimmed","declareLine","retire","retireLine","X","linePath","Count","value","tone","title","lineColumns","onEdit","columns","Link","formatDateTime","Pencil","PAGE_SIZE","SETTINGS_QUERY_KEY","ATTENTION_ON","DEFAULT_SORT","COPY","useIndexRefresh","invalidate","useThrottledInvalidation","patterns","useMemo","machineLinePattern","machineLogPattern","useEventSubscriptions","MACHINE_LINE_INDEX_QUERY_KEY","MACHINE_LINES_QUERY_KEY","SiteHeading","LinesPage","navigate","useNavigate","canAdminister","useAccess","canDeclare","shell","useShellPanelOptional","filters","setFilter","pagination","useFilterParams","q","useDebouncedValue","attention","sort","o","params","data","isLoading","error","useLineIndex","refresh","useCallback","closeDeclare","openDeclare","useEffect","grouped","total","activeFilters","emptyMessage","openRow","PageHeader","FilterBar","Fragment","Plus","FilterInput","v","FilterSelect","s","DataTable","StickyPagination"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as C,j as s}from"./vendor-query-DvWWuNIB.js";import{b7 as u,b8 as b}from"./index-
|
|
2
|
-
//# sourceMappingURL=ListToolbar-
|
|
1
|
+
import{a as C,j as s}from"./vendor-query-DvWWuNIB.js";import{b7 as u,b8 as b}from"./index-CkMHS-hG.js";import{ad as d,bD as j,bE as N,ao as h}from"./vendor-icons-fxBvvHBi.js";function g({onRefresh:m,isFetching:a=!1,apiPath:t,standalone:x=!1}){const[c,r]=C.useState(null),i=(e,l)=>{navigator.clipboard.writeText(e).then(()=>{r(l),setTimeout(()=>r(null),2e3)})},p=()=>{if(!t)return;const e=`${window.location.origin}${u}/api${t}`;i(e,"url")},f=()=>{if(!t)return;const e=`${window.location.origin}${u}/api${t}`,l=b(),$=l?`curl -H "Authorization: Bearer ${l}" "${e}"`:`curl "${e}"`;i($,"curl")},n="p-1 icon-link rounded",o="w-2.5 h-2.5";return s.jsxs("div",{className:"flex items-center gap-0.5",children:[t&&s.jsxs("div",{className:x?"flex items-center gap-0.5":"hidden @filters/filters:flex items-center gap-0.5",children:[s.jsx("button",{onClick:p,className:n,title:"Copy API URL",children:c==="url"?s.jsx(d,{className:`${o} text-status-success`}):s.jsx(j,{className:o})}),s.jsx("button",{onClick:f,className:n,title:"Copy curl (includes auth token)",children:c==="curl"?s.jsx(d,{className:`${o} text-status-success`}):s.jsx(N,{className:o})})]}),s.jsx("button",{onClick:m,disabled:a,className:`${n} disabled:opacity-50`,title:"Refresh",children:s.jsx(h,{className:`${o} ${a?"animate-spin":""}`})})]})}export{g as L};
|
|
2
|
+
//# sourceMappingURL=ListToolbar-BZCNrTh6.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListToolbar-
|
|
1
|
+
{"version":3,"file":"ListToolbar-BZCNrTh6.js","sources":["../../src/components/common/data/ListToolbar.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { RefreshCw, Link2, Terminal, Check } from 'lucide-react';\nimport { getToken } from '../../../api/client';\nimport { LT_BASE } from '../../../lib/base-path';\n\ninterface ListToolbarProps {\n onRefresh: () => void;\n isFetching?: boolean;\n /** API path (e.g. \"/workflow-states/jobs?limit=50\") for URL/curl copy. */\n apiPath?: string;\n /**\n * Set when the toolbar renders outside a `@container/filters` ancestor\n * (e.g. a page header) — skips the narrow-container fold classes, which\n * would otherwise never match and hide the copy actions.\n */\n standalone?: boolean;\n}\n\ntype CopiedState = 'url' | 'curl' | null;\n\n/**\n * Toolbar for list pages: refresh, copy API URL, copy curl command.\n * Designed to sit in FilterBar `actions` slot.\n */\nexport function ListToolbar({ onRefresh, isFetching = false, apiPath, standalone = false }: ListToolbarProps) {\n const [copied, setCopied] = useState<CopiedState>(null);\n\n const copyToClipboard = (text: string, type: CopiedState) => {\n navigator.clipboard.writeText(text).then(() => {\n setCopied(type);\n setTimeout(() => setCopied(null), 2000);\n });\n };\n\n const handleCopyUrl = () => {\n if (!apiPath) return;\n const url = `${window.location.origin}${LT_BASE}/api${apiPath}`;\n copyToClipboard(url, 'url');\n };\n\n const handleCopyCurl = () => {\n if (!apiPath) return;\n const url = `${window.location.origin}${LT_BASE}/api${apiPath}`;\n const token = getToken();\n const cmd = token\n ? `curl -H \"Authorization: Bearer ${token}\" \"${url}\"`\n : `curl \"${url}\"`;\n copyToClipboard(cmd, 'curl');\n };\n\n const BTN = 'p-1 icon-link rounded';\n const ICON = 'w-2.5 h-2.5';\n\n return (\n <div className=\"flex items-center gap-0.5\">\n {apiPath && (\n // Developer copy actions yield first at narrow containers — refresh\n // is the affordance the floor actually uses.\n <div className={standalone ? 'flex items-center gap-0.5' : 'hidden @filters/filters:flex items-center gap-0.5'}>\n <button onClick={handleCopyUrl} className={BTN} title=\"Copy API URL\">\n {copied === 'url' ? <Check className={`${ICON} text-status-success`} /> : <Link2 className={ICON} />}\n </button>\n <button onClick={handleCopyCurl} className={BTN} title=\"Copy curl (includes auth token)\">\n {copied === 'curl' ? <Check className={`${ICON} text-status-success`} /> : <Terminal className={ICON} />}\n </button>\n </div>\n )}\n <button onClick={onRefresh} disabled={isFetching} className={`${BTN} disabled:opacity-50`} title=\"Refresh\">\n <RefreshCw className={`${ICON} ${isFetching ? 'animate-spin' : ''}`} />\n </button>\n </div>\n );\n}\n"],"names":["ListToolbar","onRefresh","isFetching","apiPath","standalone","copied","setCopied","useState","copyToClipboard","text","type","handleCopyUrl","url","LT_BASE","handleCopyCurl","token","getToken","cmd","BTN","ICON","jsxs","jsx","Check","Link2","Terminal","RefreshCw"],"mappings":"+KAwBO,SAASA,EAAY,CAAE,UAAAC,EAAW,WAAAC,EAAa,GAAO,QAAAC,EAAS,WAAAC,EAAa,IAA2B,CAC5G,KAAM,CAACC,EAAQC,CAAS,EAAIC,EAAAA,SAAsB,IAAI,EAEhDC,EAAkB,CAACC,EAAcC,IAAsB,CAC3D,UAAU,UAAU,UAAUD,CAAI,EAAE,KAAK,IAAM,CAC7CH,EAAUI,CAAI,EACd,WAAW,IAAMJ,EAAU,IAAI,EAAG,GAAI,CACxC,CAAC,CACH,EAEMK,EAAgB,IAAM,CAC1B,GAAI,CAACR,EAAS,OACd,MAAMS,EAAM,GAAG,OAAO,SAAS,MAAM,GAAGC,CAAO,OAAOV,CAAO,GAC7DK,EAAgBI,EAAK,KAAK,CAC5B,EAEME,EAAiB,IAAM,CAC3B,GAAI,CAACX,EAAS,OACd,MAAMS,EAAM,GAAG,OAAO,SAAS,MAAM,GAAGC,CAAO,OAAOV,CAAO,GACvDY,EAAQC,EAAA,EACRC,EAAMF,EACR,kCAAkCA,CAAK,MAAMH,CAAG,IAChD,SAASA,CAAG,IAChBJ,EAAgBS,EAAK,MAAM,CAC7B,EAEMC,EAAM,wBACNC,EAAO,cAEb,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAU,4BACZ,SAAA,CAAAjB,GAGCiB,EAAAA,KAAC,MAAA,CAAI,UAAWhB,EAAa,4BAA8B,oDACzD,SAAA,CAAAiB,EAAAA,IAAC,SAAA,CAAO,QAASV,EAAe,UAAWO,EAAK,MAAM,eACnD,aAAW,MAAQG,EAAAA,IAACC,GAAM,UAAW,GAAGH,CAAI,sBAAA,CAAwB,QAAMI,EAAA,CAAM,UAAWJ,EAAM,CAAA,CACpG,EACAE,EAAAA,IAAC,UAAO,QAASP,EAAgB,UAAWI,EAAK,MAAM,kCACpD,SAAAb,IAAW,aAAUiB,EAAA,CAAM,UAAW,GAAGH,CAAI,sBAAA,CAAwB,EAAKE,EAAAA,IAACG,EAAA,CAAS,UAAWL,CAAA,CAAM,CAAA,CACxG,CAAA,EACF,EAEFE,EAAAA,IAAC,UAAO,QAASpB,EAAW,SAAUC,EAAY,UAAW,GAAGgB,CAAG,uBAAwB,MAAM,UAC/F,SAAAG,MAACI,EAAA,CAAU,UAAW,GAAGN,CAAI,IAAIjB,EAAa,eAAiB,EAAE,EAAA,CAAI,CAAA,CACvE,CAAA,EACF,CAEJ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as o,j as e}from"./vendor-query-DvWWuNIB.js";import{u as A}from"./mcp-
|
|
2
|
-
//# sourceMappingURL=McpOverview-
|
|
1
|
+
import{a as o,j as e}from"./vendor-query-DvWWuNIB.js";import{u as A}from"./mcp-CmcUXYce.js";import{u as F}from"./pipelines-RKpSkFz7.js";import{u as I}from"./yaml-workflows-BgY1XHJx.js";import{u as W}from"./controlplane-Bmkic8BH.js";import{P as z}from"./PageHeader-Hx8APPwE.js";import{S as b}from"./StatCard-nWY4sndl.js";import{Q as E,W as O}from"./vendor-icons-fxBvvHBi.js";import{u as U}from"./vendor-react-_9U4mKFr.js";import"./index-CkMHS-hG.js";const T=[{label:"1h",ms:36e5},{label:"24h",ms:864e5},{label:"7d",ms:6048e5},{label:"30d",ms:2592e6}];function q(r){return r<1e3?`${Math.round(r)}ms`:r<6e4?`${(r/1e3).toFixed(1)}s`:r<36e5?`${(r/6e4).toFixed(1)}m`:`${(r/36e5).toFixed(1)}h`}function j({value:r,colorClass:c,onClick:v}){return r===0?e.jsx("span",{className:"text-text-tertiary",children:"0"}):e.jsx("button",{onClick:v,className:`${c} hover:underline tabular-nums font-medium`,children:r})}function ee(){const r=U(),[c,v]=o.useState("24h"),[D,P]=o.useState(""),{data:d}=W(),k=o.useMemo(()=>((d==null?void 0:d.apps)??[]).map(t=>t.appId).sort(),[d==null?void 0:d.apps]),u=D||k[0]||"",{data:m}=F({limit:500,app_id:u}),{data:N,isLoading:L}=A(),{data:y,isLoading:_}=I({limit:200}),w=k,p=(N==null?void 0:N.servers)??[],h=(y==null?void 0:y.workflows)??[],M=o.useMemo(()=>p.reduce((t,l)=>t+(Array.isArray(l.tool_manifest)?l.tool_manifest.length:0),0),[p]),S=o.useMemo(()=>new Set(h.map(l=>l.app_id)).size,[h]),$=o.useMemo(()=>{const t=T.find(l=>l.label===c);return Date.now()-t.ms},[c]),i=o.useMemo(()=>((m==null?void 0:m.jobs)??[]).filter(t=>new Date(t.created_at).getTime()>=$),[m==null?void 0:m.jobs,$]),C=o.useMemo(()=>{const t=new Map;for(const s of i){const a=t.get(s.entity)??{total:0,running:0,completed:0,failed:0,durations:[]};if(a.total++,s.status==="running"&&a.running++,s.status==="completed"){a.completed++;const g=new Date(s.updated_at).getTime()-new Date(s.created_at).getTime();g>0&&a.durations.push(g)}s.status==="failed"&&a.failed++,t.set(s.entity,a)}const l=[];for(const[s,a]of t)l.push({pipeline:s,...a,avgDuration:a.durations.length>0?a.durations.reduce((g,R)=>g+R,0)/a.durations.length:null});return l.sort((s,a)=>a.total-s.total)},[i]),f=o.useMemo(()=>({total:i.length,running:i.filter(t=>t.status==="running").length,completed:i.filter(t=>t.status==="completed").length,failed:i.filter(t=>t.status==="failed").length}),[i]),n=(t,l)=>{const s=new URLSearchParams;u&&s.set("namespace",u),t&&s.set("entity",t),l&&s.set("status",l);const a=s.toString();r(`/mcp/executions${a?`?${a}`:""}`)},x="pb-2 text-2xs font-semibold uppercase tracking-widest text-text-tertiary";return e.jsxs("div",{children:[e.jsx(z,{title:"Discovered"}),e.jsxs("div",{className:"flex items-center gap-4 mb-6",children:[e.jsx("div",{className:"flex items-center gap-1",children:T.map(t=>e.jsx("button",{onClick:()=>v(t.label),className:`px-3 py-1 text-xs rounded-full transition-colors ${c===t.label?"bg-accent text-text-inverse":"text-text-tertiary hover:text-text-primary hover:bg-surface-hover"}`,children:t.label},t.label))}),w.length>1&&e.jsx("select",{value:u,onChange:t=>P(t.target.value),className:"select text-xs py-1 px-2",children:w.map(t=>e.jsx("option",{value:t,children:t},t))})]}),e.jsxs("div",{className:"grid grid-cols-4 gap-4 mb-8",children:[e.jsx(b,{label:"Total Runs",value:f.total,onClick:()=>n()}),e.jsx(b,{label:"Running",value:f.running,colorClass:"text-status-active",onClick:()=>n(void 0,"running")}),e.jsx(b,{label:"Completed",value:f.completed,colorClass:"text-status-success",onClick:()=>n(void 0,"completed")}),e.jsx(b,{label:"Failed",value:f.failed,colorClass:"text-status-error",onClick:()=>n(void 0,"failed")})]}),C.length>0&&e.jsxs("table",{className:"w-full text-left mb-10",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-surface-border",children:[e.jsx("th",{className:x,children:"Tool"}),e.jsx("th",{className:`${x} text-right w-20`,children:"Total"}),e.jsx("th",{className:`${x} text-right w-20`,children:"Running"}),e.jsx("th",{className:`${x} text-right w-24`,children:"Completed"}),e.jsx("th",{className:`${x} text-right w-20`,children:"Failed"}),e.jsx("th",{className:`${x} text-right w-28`,children:"Avg Duration"})]})}),e.jsx("tbody",{children:C.map(t=>e.jsxs("tr",{className:"border-b border-surface-border last:border-b-0",children:[e.jsx("td",{className:"py-3 text-sm font-mono text-text-primary",children:e.jsx("button",{onClick:()=>n(t.pipeline),className:"hover:text-accent hover:underline",children:t.pipeline})}),e.jsx("td",{className:"py-3 text-sm text-right",children:e.jsx(j,{value:t.total,colorClass:"text-text-secondary",onClick:()=>n(t.pipeline)})}),e.jsx("td",{className:"py-3 text-sm text-right",children:e.jsx(j,{value:t.running,colorClass:"text-status-active",onClick:()=>n(t.pipeline,"running")})}),e.jsx("td",{className:"py-3 text-sm text-right",children:e.jsx(j,{value:t.completed,colorClass:"text-status-success",onClick:()=>n(t.pipeline,"completed")})}),e.jsx("td",{className:"py-3 text-sm text-right",children:e.jsx(j,{value:t.failed,colorClass:"text-status-error",onClick:()=>n(t.pipeline,"failed")})}),e.jsx("td",{className:"py-3 text-sm font-mono text-text-secondary text-right",children:t.avgDuration!==null?q(t.avgDuration):"—"})]},t.pipeline))})]}),C.length===0&&e.jsx("div",{className:"py-12 text-center mb-8",children:e.jsxs("p",{className:"text-sm text-text-tertiary",children:["No MCP tool activity in the last ",c]})}),e.jsxs("div",{className:"grid grid-cols-1 @form-cols:grid-cols-2 gap-4",children:[e.jsxs("button",{onClick:()=>r("/mcp/servers"),className:"bg-surface-raised border border-surface-border rounded-md p-5 text-left hover:border-accent/40 transition-colors",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-3",children:[e.jsx(E,{size:16,className:"text-accent shrink-0"}),e.jsx("span",{className:"text-sm font-medium text-text-primary",children:"Tool Servers"})]}),e.jsxs("p",{className:"text-2xl font-light tabular-nums text-text-primary mb-1",children:[L?"—":p.length,e.jsxs("span",{className:"text-sm text-text-tertiary font-normal ml-2",children:["server",p.length!==1?"s":""," · ",M," tool",M!==1?"s":""]})]}),e.jsx("p",{className:"text-2xs text-text-tertiary leading-relaxed mt-2",children:"Built-in and external MCP servers. Each server exposes tools that workflows and agents can call."})]}),e.jsxs("button",{onClick:()=>r("/mcp/workflows"),className:"bg-surface-raised border border-surface-border rounded-md p-5 text-left hover:border-accent/40 transition-colors",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-3",children:[e.jsx(O,{size:16,className:"text-purple-400 shrink-0"}),e.jsx("span",{className:"text-sm font-medium text-text-primary",children:"Pipeline Registry"})]}),e.jsxs("p",{className:"text-2xl font-light tabular-nums text-text-primary mb-1",children:[_?"—":h.length,e.jsxs("span",{className:"text-sm text-text-tertiary font-normal ml-2",children:["workflow",h.length!==1?"s":""," · ",S," server",S!==1?"s":""]})]}),e.jsx("p",{className:"text-2xs text-text-tertiary leading-relaxed mt-2",children:"Compiled from discovery runs. Deterministic tool-to-tool pipelines — no LLM, no token costs."})]})]})]})}export{ee as McpOverview};
|
|
2
|
+
//# sourceMappingURL=McpOverview-yJTYnh1z.js.map
|