@polderlabs/bizar 10.2.0 → 10.3.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 +31 -8
- package/bizar-dash/CONTROL_SURFACES.md +0 -1
- package/bizar-dash/dist/assets/{ActivityFeed-JjmOY2AQ.js → ActivityFeed-xXiUCZLB.js} +1 -1
- package/bizar-dash/dist/assets/{ActivityFeed-JjmOY2AQ.js.map → ActivityFeed-xXiUCZLB.js.map} +1 -1
- package/bizar-dash/dist/assets/{ActivityView-BIIMvGWo.js → ActivityView-nOYhCp3h.js} +1 -1
- package/bizar-dash/dist/assets/{ActivityView-BIIMvGWo.js.map → ActivityView-nOYhCp3h.js.map} +1 -1
- package/bizar-dash/dist/assets/{AdminView-DRidJtkq.js → AdminView-Coi4V3sq.js} +1 -1
- package/bizar-dash/dist/assets/{AdminView-DRidJtkq.js.map → AdminView-Coi4V3sq.js.map} +1 -1
- package/bizar-dash/dist/assets/{AgentActivity-79l4SBMC.js → AgentActivity-nEri4lbx.js} +1 -1
- package/bizar-dash/dist/assets/{AgentActivity-79l4SBMC.js.map → AgentActivity-nEri4lbx.js.map} +1 -1
- package/bizar-dash/dist/assets/{AgentsView-0vT4uPSc.js → AgentsView-ByiIJ0ej.js} +3 -3
- package/bizar-dash/dist/assets/{AgentsView-0vT4uPSc.js.map → AgentsView-ByiIJ0ej.js.map} +1 -1
- package/bizar-dash/dist/assets/{Alert-CG5q_s75.js → Alert-Dg_Vwxh5.js} +1 -1
- package/bizar-dash/dist/assets/{Alert-CG5q_s75.js.map → Alert-Dg_Vwxh5.js.map} +1 -1
- package/bizar-dash/dist/assets/{ArtifactsView-DM8ZmpR9.js → ArtifactsView-CGclRNnz.js} +1 -1
- package/bizar-dash/dist/assets/{ArtifactsView-DM8ZmpR9.js.map → ArtifactsView-CGclRNnz.js.map} +1 -1
- package/bizar-dash/dist/assets/{AuthView-BveN94MC.js → AuthView-utVm6M3D.js} +1 -1
- package/bizar-dash/dist/assets/{AuthView-BveN94MC.js.map → AuthView-utVm6M3D.js.map} +1 -1
- package/bizar-dash/dist/assets/{Avatar-ulUPIYTd.js → Avatar-CXDZdKy4.js} +1 -1
- package/bizar-dash/dist/assets/{Avatar-ulUPIYTd.js.map → Avatar-CXDZdKy4.js.map} +1 -1
- package/bizar-dash/dist/assets/{BackgroundJobsView-BWErhqFo.js → BackgroundJobsView-j603pz6o.js} +1 -1
- package/bizar-dash/dist/assets/{BackgroundJobsView-BWErhqFo.js.map → BackgroundJobsView-j603pz6o.js.map} +1 -1
- package/bizar-dash/dist/assets/{BackupView-CnBjzG9N.js → BackupView-DgvnntTE.js} +1 -1
- package/bizar-dash/dist/assets/{BackupView-CnBjzG9N.js.map → BackupView-DgvnntTE.js.map} +1 -1
- package/bizar-dash/dist/assets/{Card-B0imhxMk.js → Card-D9019JOD.js} +1 -1
- package/bizar-dash/dist/assets/{Card-B0imhxMk.js.map → Card-D9019JOD.js.map} +1 -1
- package/bizar-dash/dist/assets/{ChatView-D6zGytzx.js → ChatView-C0cTgj5d.js} +1 -1
- package/bizar-dash/dist/assets/{ChatView-D6zGytzx.js.map → ChatView-C0cTgj5d.js.map} +1 -1
- package/bizar-dash/dist/assets/{Chip-wwZSGwLE.js → Chip-DQtalZ4y.js} +1 -1
- package/bizar-dash/dist/assets/{Chip-wwZSGwLE.js.map → Chip-DQtalZ4y.js.map} +1 -1
- package/bizar-dash/dist/assets/{ClaudeSessionsView-DK1sOLhi.js → ClaudeSessionsView-H3Bqjo6b.js} +1 -1
- package/bizar-dash/dist/assets/{ClaudeSessionsView-DK1sOLhi.js.map → ClaudeSessionsView-H3Bqjo6b.js.map} +1 -1
- package/bizar-dash/dist/assets/{ClipboardView-CZ2lYPr0.js → ClipboardView-BAguaKbx.js} +1 -1
- package/bizar-dash/dist/assets/{ClipboardView-CZ2lYPr0.js.map → ClipboardView-BAguaKbx.js.map} +1 -1
- package/bizar-dash/dist/assets/{ConfigView-D-zT9eNA.js → ConfigView-DWHJgoe8.js} +1 -1
- package/bizar-dash/dist/assets/{ConfigView-D-zT9eNA.js.map → ConfigView-DWHJgoe8.js.map} +1 -1
- package/bizar-dash/dist/assets/{DiagnosticsView-BocV68Lb.js → DiagnosticsView-oCT624hk.js} +1 -1
- package/bizar-dash/dist/assets/{DiagnosticsView-BocV68Lb.js.map → DiagnosticsView-oCT624hk.js.map} +1 -1
- package/bizar-dash/dist/assets/{DialogsView-BVjPI5x7.js → DialogsView-CqHNals_.js} +1 -1
- package/bizar-dash/dist/assets/{DialogsView-BVjPI5x7.js.map → DialogsView-CqHNals_.js.map} +1 -1
- package/bizar-dash/dist/assets/{DoctorView-84gJcZwM.js → DoctorView-6kfQq_Mx.js} +1 -1
- package/bizar-dash/dist/assets/{DoctorView-84gJcZwM.js.map → DoctorView-6kfQq_Mx.js.map} +1 -1
- package/bizar-dash/dist/assets/{EmptyState-BjgVOrcO.js → EmptyState-DLmtBX_6.js} +1 -1
- package/bizar-dash/dist/assets/{EmptyState-BjgVOrcO.js.map → EmptyState-DLmtBX_6.js.map} +1 -1
- package/bizar-dash/dist/assets/{EnvVarsView-BJ2TEzF7.js → EnvVarsView-DySOXlP1.js} +2 -2
- package/bizar-dash/dist/assets/{EnvVarsView-BJ2TEzF7.js.map → EnvVarsView-DySOXlP1.js.map} +1 -1
- package/bizar-dash/dist/assets/{ErrorState-BE3WBFqF.js → ErrorState-Bump8diE.js} +1 -1
- package/bizar-dash/dist/assets/{ErrorState-BE3WBFqF.js.map → ErrorState-Bump8diE.js.map} +1 -1
- package/bizar-dash/dist/assets/{EvalView-BJJ2P-kK.js → EvalView-FnZ5d93z.js} +1 -1
- package/bizar-dash/dist/assets/{EvalView-BJJ2P-kK.js.map → EvalView-FnZ5d93z.js.map} +1 -1
- package/bizar-dash/dist/assets/{GoalsView-pwROHApi.js → GoalsView-C4m1WnVv.js} +1 -1
- package/bizar-dash/dist/assets/{GoalsView-pwROHApi.js.map → GoalsView-C4m1WnVv.js.map} +1 -1
- package/bizar-dash/dist/assets/{Grid-qcvbhx6e.js → Grid-dEnoGGws.js} +1 -1
- package/bizar-dash/dist/assets/{Grid-qcvbhx6e.js.map → Grid-dEnoGGws.js.map} +1 -1
- package/bizar-dash/dist/assets/{HistoryView-C7SSOLJA.js → HistoryView-xdRybjZ2.js} +1 -1
- package/bizar-dash/dist/assets/{HistoryView-C7SSOLJA.js.map → HistoryView-xdRybjZ2.js.map} +1 -1
- package/bizar-dash/dist/assets/{Input-Bgzxf_Hu.js → Input-BSa3lh_-.js} +1 -1
- package/bizar-dash/dist/assets/{Input-Bgzxf_Hu.js.map → Input-BSa3lh_-.js.map} +1 -1
- package/bizar-dash/dist/assets/{LibrariesView-CbFFksox.js → LibrariesView-1zR04Eci.js} +1 -1
- package/bizar-dash/dist/assets/{LibrariesView-CbFFksox.js.map → LibrariesView-1zR04Eci.js.map} +1 -1
- package/bizar-dash/dist/assets/{LightRAGView-BqDrJbRq.js → LightRAGView-PubmA9oL.js} +1 -1
- package/bizar-dash/dist/assets/{LightRAGView-BqDrJbRq.js.map → LightRAGView-PubmA9oL.js.map} +1 -1
- package/bizar-dash/dist/assets/{ListHeader-TjPJrUfY.js → ListHeader-Ak9WJd39.js} +1 -1
- package/bizar-dash/dist/assets/{ListHeader-TjPJrUfY.js.map → ListHeader-Ak9WJd39.js.map} +1 -1
- package/bizar-dash/dist/assets/{MemoryView-BlTeHLhX.js → MemoryView-DBGpuETw.js} +1 -1
- package/bizar-dash/dist/assets/{MemoryView-BlTeHLhX.js.map → MemoryView-DBGpuETw.js.map} +1 -1
- package/bizar-dash/dist/assets/MiscView-DufqBHkX.js +1 -0
- package/bizar-dash/dist/assets/{MiscView-B8QY82Pm.js.map → MiscView-DufqBHkX.js.map} +1 -1
- package/bizar-dash/dist/assets/{ModsView-CvW1OWts.js → ModsView-DcX6eVU2.js} +2 -2
- package/bizar-dash/dist/assets/{ModsView-CvW1OWts.js.map → ModsView-DcX6eVU2.js.map} +1 -1
- package/bizar-dash/dist/assets/{NotificationsView-CsBt5U7x.js → NotificationsView-B8IhHRQC.js} +1 -1
- package/bizar-dash/dist/assets/{NotificationsView-CsBt5U7x.js.map → NotificationsView-B8IhHRQC.js.map} +1 -1
- package/bizar-dash/dist/assets/ObsidianView-DEuk65zS.js +1 -0
- package/bizar-dash/dist/assets/{ObsidianView-BCTejEj2.js.map → ObsidianView-DEuk65zS.js.map} +1 -1
- package/bizar-dash/dist/assets/{OverviewView-BsuPxwnB.js → OverviewView-CTI2spTd.js} +1 -1
- package/bizar-dash/dist/assets/{OverviewView-BsuPxwnB.js.map → OverviewView-CTI2spTd.js.map} +1 -1
- package/bizar-dash/dist/assets/{ProgressBar-DlZTETEn.js → ProgressBar-D3lkz42E.js} +1 -1
- package/bizar-dash/dist/assets/{ProgressBar-DlZTETEn.js.map → ProgressBar-D3lkz42E.js.map} +1 -1
- package/bizar-dash/dist/assets/{ProjectsView-Soxtmpet.js → ProjectsView-Du0LzE7A.js} +1 -1
- package/bizar-dash/dist/assets/{ProjectsView-Soxtmpet.js.map → ProjectsView-Du0LzE7A.js.map} +1 -1
- package/bizar-dash/dist/assets/{ProvidersView-DaCEV9pM.js → ProvidersView-5bCgXwBo.js} +1 -1
- package/bizar-dash/dist/assets/{ProvidersView-DaCEV9pM.js.map → ProvidersView-5bCgXwBo.js.map} +1 -1
- package/bizar-dash/dist/assets/{SchedulesView-DY2ByBj_.js → SchedulesView-DFHdIz5P.js} +1 -1
- package/bizar-dash/dist/assets/{SchedulesView-DY2ByBj_.js.map → SchedulesView-DFHdIz5P.js.map} +1 -1
- package/bizar-dash/dist/assets/{Select-Dbd88_n8.js → Select-C8EJj4NM.js} +1 -1
- package/bizar-dash/dist/assets/{Select-Dbd88_n8.js.map → Select-C8EJj4NM.js.map} +1 -1
- package/bizar-dash/dist/assets/{SettingsRow-CLMNd434.js → SettingsRow-BdOOmYMD.js} +1 -1
- package/bizar-dash/dist/assets/{SettingsRow-CLMNd434.js.map → SettingsRow-BdOOmYMD.js.map} +1 -1
- package/bizar-dash/dist/assets/{SettingsView-b24oFq9x.js → SettingsView-CqwQ6Knv.js} +1 -1
- package/bizar-dash/dist/assets/{SettingsView-b24oFq9x.js.map → SettingsView-CqwQ6Knv.js.map} +1 -1
- package/bizar-dash/dist/assets/{Sheet-DnDid58j.js → Sheet-Cztsvgse.js} +1 -1
- package/bizar-dash/dist/assets/{Sheet-DnDid58j.js.map → Sheet-Cztsvgse.js.map} +1 -1
- package/bizar-dash/dist/assets/{Slider-BJCvKI1I.js → Slider-BexNfF6K.js} +1 -1
- package/bizar-dash/dist/assets/{Slider-BJCvKI1I.js.map → Slider-BexNfF6K.js.map} +1 -1
- package/bizar-dash/dist/assets/{Sparkline-ktqQLdyb.js → Sparkline-CLZBtvsN.js} +1 -1
- package/bizar-dash/dist/assets/{Sparkline-ktqQLdyb.js.map → Sparkline-CLZBtvsN.js.map} +1 -1
- package/bizar-dash/dist/assets/{Switch-CwXfsDii.js → Switch-B1tiRwNK.js} +1 -1
- package/bizar-dash/dist/assets/{Switch-CwXfsDii.js.map → Switch-B1tiRwNK.js.map} +1 -1
- package/bizar-dash/dist/assets/{TasksView-BHmpzFCf.js → TasksView-CT0fPlos.js} +1 -1
- package/bizar-dash/dist/assets/{TasksView-BHmpzFCf.js.map → TasksView-CT0fPlos.js.map} +1 -1
- package/bizar-dash/dist/assets/{Textarea-BzIAwSlp.js → Textarea-D_TPpVMy.js} +1 -1
- package/bizar-dash/dist/assets/{Textarea-BzIAwSlp.js.map → Textarea-D_TPpVMy.js.map} +1 -1
- package/bizar-dash/dist/assets/{UpdateView-CSmX9NN0.js → UpdateView-tD2q2OhW.js} +1 -1
- package/bizar-dash/dist/assets/{UpdateView-CSmX9NN0.js.map → UpdateView-tD2q2OhW.js.map} +1 -1
- package/bizar-dash/dist/assets/{UsageView-COyr_Gfi.js → UsageView-B4BuAFKA.js} +1 -1
- package/bizar-dash/dist/assets/{UsageView-COyr_Gfi.js.map → UsageView-B4BuAFKA.js.map} +1 -1
- package/bizar-dash/dist/assets/{ViewHeader-BzYZ3m-e.js → ViewHeader-V_SzbUpw.js} +1 -1
- package/bizar-dash/dist/assets/{ViewHeader-BzYZ3m-e.js.map → ViewHeader-V_SzbUpw.js.map} +1 -1
- package/bizar-dash/dist/assets/{VoiceView-D33_xG5t.js → VoiceView-D3vb5OM2.js} +1 -1
- package/bizar-dash/dist/assets/{VoiceView-D33_xG5t.js.map → VoiceView-D3vb5OM2.js.map} +1 -1
- package/bizar-dash/dist/assets/{brain-CM-Vls8r.js → brain-BmfWcitQ.js} +1 -1
- package/bizar-dash/dist/assets/{brain-CM-Vls8r.js.map → brain-BmfWcitQ.js.map} +1 -1
- package/bizar-dash/dist/assets/{calendar-C0lgZk69.js → calendar-VntJUzFB.js} +1 -1
- package/bizar-dash/dist/assets/{calendar-C0lgZk69.js.map → calendar-VntJUzFB.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-Bx_hQEBC.js → circle-KrQQySeK.js} +1 -1
- package/bizar-dash/dist/assets/{circle-Bx_hQEBC.js.map → circle-KrQQySeK.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-alert-DHvsqpw5.js → circle-alert-CQ9MLygI.js} +1 -1
- package/bizar-dash/dist/assets/{circle-alert-DHvsqpw5.js.map → circle-alert-CQ9MLygI.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-check-Bx8wmXR9.js → circle-check-COtVgsWw.js} +1 -1
- package/bizar-dash/dist/assets/{circle-check-Bx8wmXR9.js.map → circle-check-COtVgsWw.js.map} +1 -1
- package/bizar-dash/dist/assets/{clock-CejGoecX.js → clock-C0GlM4qp.js} +1 -1
- package/bizar-dash/dist/assets/{clock-CejGoecX.js.map → clock-C0GlM4qp.js.map} +1 -1
- package/bizar-dash/dist/assets/{download-4cEUWue1.js → download-CW4DmtRe.js} +1 -1
- package/bizar-dash/dist/assets/{download-4cEUWue1.js.map → download-CW4DmtRe.js.map} +1 -1
- package/bizar-dash/dist/assets/{external-link-0NqUhI4i.js → external-link-CAOnh_DH.js} +1 -1
- package/bizar-dash/dist/assets/{external-link-0NqUhI4i.js.map → external-link-CAOnh_DH.js.map} +1 -1
- package/bizar-dash/dist/assets/{file-text-yEMkrSoZ.js → file-text-CS1jB_oV.js} +1 -1
- package/bizar-dash/dist/assets/{file-text-yEMkrSoZ.js.map → file-text-CS1jB_oV.js.map} +1 -1
- package/bizar-dash/dist/assets/{filter-BXt60zAS.js → filter-DyQbml3L.js} +1 -1
- package/bizar-dash/dist/assets/{filter-BXt60zAS.js.map → filter-DyQbml3L.js.map} +1 -1
- package/bizar-dash/dist/assets/{git-pull-request-BjG5lNtR.js → git-pull-request-Co6gYfba.js} +1 -1
- package/bizar-dash/dist/assets/{git-pull-request-BjG5lNtR.js.map → git-pull-request-Co6gYfba.js.map} +1 -1
- package/bizar-dash/dist/assets/{main-CokHAXWM.js → main-CyAIirBB.js} +28 -33
- package/bizar-dash/dist/assets/main-CyAIirBB.js.map +1 -0
- package/bizar-dash/dist/assets/network-CDn43Gsj.js +6 -0
- package/bizar-dash/dist/assets/network-CDn43Gsj.js.map +1 -0
- package/bizar-dash/dist/assets/{pause-CAmulU0F.js → pause-CKYjSTGX.js} +1 -1
- package/bizar-dash/dist/assets/{pause-CAmulU0F.js.map → pause-CKYjSTGX.js.map} +1 -1
- package/bizar-dash/dist/assets/{pencil-eq5IqBmU.js → pencil-BUJ2DpWs.js} +1 -1
- package/bizar-dash/dist/assets/{pencil-eq5IqBmU.js.map → pencil-BUJ2DpWs.js.map} +1 -1
- package/bizar-dash/dist/assets/{play-BoLrrcBA.js → play-CGxZWqtW.js} +1 -1
- package/bizar-dash/dist/assets/{play-BoLrrcBA.js.map → play-CGxZWqtW.js.map} +1 -1
- package/bizar-dash/dist/assets/{plug-DBrVM9lK.js → plug-CQYGgGSy.js} +1 -1
- package/bizar-dash/dist/assets/{plug-DBrVM9lK.js.map → plug-CQYGgGSy.js.map} +1 -1
- package/bizar-dash/dist/assets/{plus-DENm0hqV.js → plus-fFxt-8z5.js} +1 -1
- package/bizar-dash/dist/assets/{plus-DENm0hqV.js.map → plus-fFxt-8z5.js.map} +1 -1
- package/bizar-dash/dist/assets/{power-DLjXF7zE.js → power-Cjgy2KsI.js} +1 -1
- package/bizar-dash/dist/assets/{power-DLjXF7zE.js.map → power-Cjgy2KsI.js.map} +1 -1
- package/bizar-dash/dist/assets/{power-off-D47cOnG_.js → power-off-B81hLRah.js} +1 -1
- package/bizar-dash/dist/assets/{power-off-D47cOnG_.js.map → power-off-B81hLRah.js.map} +1 -1
- package/bizar-dash/dist/assets/{refresh-ccw-DNrXX9gB.js → refresh-ccw-BCXx86xp.js} +1 -1
- package/bizar-dash/dist/assets/{refresh-ccw-DNrXX9gB.js.map → refresh-ccw-BCXx86xp.js.map} +1 -1
- package/bizar-dash/dist/assets/{refresh-cw-CoAHDpeS.js → refresh-cw-COTg1nZo.js} +1 -1
- package/bizar-dash/dist/assets/{refresh-cw-CoAHDpeS.js.map → refresh-cw-COTg1nZo.js.map} +1 -1
- package/bizar-dash/dist/assets/{rotate-ccw-ObX5awaG.js → rotate-ccw-BZrEVc0Z.js} +1 -1
- package/bizar-dash/dist/assets/{rotate-ccw-ObX5awaG.js.map → rotate-ccw-BZrEVc0Z.js.map} +1 -1
- package/bizar-dash/dist/assets/{rotate-cw-xpPJw9LP.js → rotate-cw-CsTtaLV2.js} +1 -1
- package/bizar-dash/dist/assets/{rotate-cw-xpPJw9LP.js.map → rotate-cw-CsTtaLV2.js.map} +1 -1
- package/bizar-dash/dist/assets/{save-D1iKiJJl.js → save-DtMTge1F.js} +1 -1
- package/bizar-dash/dist/assets/{save-D1iKiJJl.js.map → save-DtMTge1F.js.map} +1 -1
- package/bizar-dash/dist/assets/{send-BRcAhZUm.js → send-DyBhyk8t.js} +1 -1
- package/bizar-dash/dist/assets/{send-BRcAhZUm.js.map → send-DyBhyk8t.js.map} +1 -1
- package/bizar-dash/dist/assets/{shield-alert-C6vEcK-g.js → shield-alert-BPGJlRF8.js} +1 -1
- package/bizar-dash/dist/assets/{shield-alert-C6vEcK-g.js.map → shield-alert-BPGJlRF8.js.map} +1 -1
- package/bizar-dash/dist/assets/{trash-2-DZDjEnNh.js → trash-2-2NsyTU8c.js} +1 -1
- package/bizar-dash/dist/assets/{trash-2-DZDjEnNh.js.map → trash-2-2NsyTU8c.js.map} +1 -1
- package/bizar-dash/dist/assets/{trending-up-DMj-AJVf.js → trending-up-BXwP23VK.js} +1 -1
- package/bizar-dash/dist/assets/{trending-up-DMj-AJVf.js.map → trending-up-BXwP23VK.js.map} +1 -1
- package/bizar-dash/dist/assets/{triangle-alert-_2xe_tl4.js → triangle-alert-DFmQ_RXN.js} +1 -1
- package/bizar-dash/dist/assets/{triangle-alert-_2xe_tl4.js.map → triangle-alert-DFmQ_RXN.js.map} +1 -1
- package/bizar-dash/dist/assets/{upload-DdDljAeV.js → upload-Cj-HYRYV.js} +1 -1
- package/bizar-dash/dist/assets/{upload-DdDljAeV.js.map → upload-Cj-HYRYV.js.map} +1 -1
- package/bizar-dash/dist/assets/{zap-mHsgh0FP.js → zap-BaOiybcl.js} +1 -1
- package/bizar-dash/dist/assets/{zap-mHsgh0FP.js.map → zap-BaOiybcl.js.map} +1 -1
- package/bizar-dash/dist/index.html +1 -1
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/src/server/routes/update.mjs +48 -21
- package/bizar-dash/src/web/v8/App.tsx +0 -4
- package/bizar-dash/src/web/v8/__tests__/new-views.test.tsx +0 -17
- package/bizar-dash/src/web/v8/shell/Sidebar.tsx +0 -1
- package/bizar-dash/src/web/v8/views/Router.tsx +0 -5
- package/bizar-dash/tests/_update-test-helpers.mjs +13 -0
- package/bizar-dash/tests/update-check.test.mjs +18 -13
- package/bizar-dash/tests/update-packages.test.mjs +154 -0
- package/bizar-dash/tests/update-run.test.mjs +17 -80
- package/cli/banner.mjs +1 -1
- package/cli/bin.mjs +8 -1
- package/cli/bootstrap.mjs +1 -1
- package/cli/commands/claude-cmd.mjs +1 -1
- package/cli/commands/deploy/docker.mjs +0 -3
- package/cli/install/banner.mjs +67 -0
- package/cli/install/banner.test.mjs +39 -0
- package/cli/install/index.mjs +32 -0
- package/cli/install/index.test.mjs +61 -0
- package/cli/install/paths.mjs +80 -0
- package/cli/install/paths.test.mjs +77 -0
- package/cli/install/plugin.mjs +161 -0
- package/cli/install/postinstall.mjs +111 -0
- package/cli/install.mjs +13 -600
- package/cli/migrate.mjs +157 -0
- package/cli/migrate.test.mjs +85 -0
- package/cli/provision.mjs +615 -1918
- package/cli/provision.test.mjs +1 -1
- package/cli/service-controller.test.mjs +0 -1
- package/cli/service-env.mjs +0 -1
- package/cli/utils.mjs +0 -1
- package/install.sh +54 -466
- package/package.json +1 -1
- package/packages/sdk/package.json +1 -1
- package/scripts/install-curl.sh +17 -0
- package/bizar-dash/dist/assets/HeadroomView-D1UiTYbt.js +0 -11
- package/bizar-dash/dist/assets/HeadroomView-D1UiTYbt.js.map +0 -1
- package/bizar-dash/dist/assets/MiscView-B8QY82Pm.js +0 -1
- package/bizar-dash/dist/assets/ObsidianView-BCTejEj2.js +0 -1
- package/bizar-dash/dist/assets/main-CokHAXWM.js.map +0 -1
- package/bizar-dash/skills/headroom/SKILL.md +0 -94
- package/bizar-dash/src/server/headroom.mjs +0 -649
- package/bizar-dash/src/server/routes/headroom.mjs +0 -126
- package/bizar-dash/src/web/v8/views/Headroom/HeadroomView.tsx +0 -201
- package/bizar-dash/tests/graphify-mod-spawn.node.test.mjs +0 -90
- package/bizar-dash/tests/headroom-install.test.mjs +0 -173
- package/bizar-dash/tests/headroom-settings.test.mjs +0 -126
- package/bizar-dash/tests/headroom-status.test.mjs +0 -117
- package/bizar-dash/tests/v7-archive/mobile-overview.test.tsx +0 -214
- package/bizar-dash/tests/v7-archive/mobile-settings.test.tsx +0 -181
- package/bizar-dash/tests/v7-archive/navigation/CommandPalette.test.tsx +0 -105
- package/bizar-dash/tests/v7-archive/settings-nav.test.tsx +0 -128
- package/bizar-dash/tests/v7-archive/views/Overview.test.tsx +0 -413
- package/cli/commands/headroom.mjs +0 -204
- package/cli/provision-claude.mjs +0 -1176
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TasksView-BHmpzFCf.js","sources":["../../../node_modules/lucide-react/dist/esm/icons/arrow-right.js","../../src/web/v8/ui/kanban/KanbanToolbar.tsx","../../src/web/v8/ui/kanban/useKanbanSelection.ts","../../src/web/v8/ui/tasks/TaskDetail.tsx","../../src/web/v8/views/Tasks/TasksView.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.460.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ArrowRight = createLucideIcon(\"ArrowRight\", [\n [\"path\", { d: \"M5 12h14\", key: \"1ays0h\" }],\n [\"path\", { d: \"m12 5 7 7-7 7\", key: \"xquz4c\" }]\n]);\n\nexport { ArrowRight as default };\n//# sourceMappingURL=arrow-right.js.map\n","import { useState, type ChangeEvent, type ReactNode } from 'react';\nimport { Plus, Search, Trash2, Archive, ArrowRight, X, Filter } from 'lucide-react';\nimport { Button } from '../controls/Button.js';\nimport { IconButton } from '../controls/IconButton.js';\nimport { cx } from '../utils/cx.js';\n\n/**\n * KanbanToolbar — top-of-board toolbar.\n *\n * Three modes:\n * - normal: search input + filter chips + \"New task\" button.\n * - selecting: replaces the action row with N-selected count +\n * bulk-actions (Move / Archive / Delete).\n * - filtered: shows a \"Clear filters\" pill next to the search.\n *\n * Consumers control query state via callbacks. The toolbar keeps no\n * internal search/filter state of its own — that lives in the view\n * so the board can re-derive visible cards.\n */\n\nexport interface KanbanFilter {\n /** Stable filter id; used as the chip key + for clearing. */\n id: string;\n /** Visible chip label (e.g. \"High priority\"). */\n label: ReactNode;\n /** Optional tone for the chip. */\n tone?: 'neutral' | 'info' | 'success' | 'warning' | 'danger' | 'accent';\n}\n\nexport interface KanbanToolbarProps {\n /** Total number of cards on the board (for \"showing X of Y\"). */\n totalCount: number;\n /** Number of cards currently visible after filtering. */\n visibleCount: number;\n /** Number of selected cards. When >0, the toolbar swaps to bulk mode. */\n selectedCount: number;\n\n /** Free-text search. */\n query: string;\n onQueryChange: (value: string) => void;\n\n /** Active filters. */\n filters: readonly KanbanFilter[];\n onFilterToggle: (filterId: string) => void;\n onClearFilters: () => void;\n\n /** New-task action. Hidden when the toolbar is in bulk mode. */\n onNewTask?: () => void;\n\n /** Bulk actions, shown only when selectedCount > 0. */\n onBulkMove?: (selectedIds: ReadonlySet<string>) => void;\n onBulkArchive?: (selectedIds: ReadonlySet<string>) => void;\n onBulkDelete?: (selectedIds: ReadonlySet<string>) => void;\n onClearSelection?: () => void;\n\n className?: string;\n}\n\nexport function KanbanToolbar(props: KanbanToolbarProps): JSX.Element {\n const {\n totalCount,\n visibleCount,\n selectedCount,\n query,\n onQueryChange,\n filters,\n onFilterToggle,\n onClearFilters,\n onNewTask,\n onBulkMove,\n onBulkArchive,\n onBulkDelete,\n onClearSelection,\n className,\n } = props;\n\n const [searchFocused, setSearchFocused] = useState(false);\n const isBulk = selectedCount > 0;\n\n return (\n <div\n className={cx('v8-kanban-toolbar', className)}\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: 'var(--space-2)',\n padding: 'var(--space-2) var(--space-3)',\n background: 'var(--surface-0)',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius)',\n }}\n >\n {isBulk ? (\n <>\n <span\n style={{\n fontSize: 'var(--fs-13)',\n fontWeight: 600,\n color: 'var(--fg)',\n }}\n >\n {selectedCount} selected\n </span>\n <span style={{ flex: 1 }} />\n {onBulkMove !== undefined && (\n <Button size=\"sm\" variant=\"secondary\" leftIcon={<ArrowRight size={14} aria-hidden=\"true\" />} onClick={() => onBulkMove(new Set())}>\n Move…\n </Button>\n )}\n {onBulkArchive !== undefined && (\n <Button\n size=\"sm\"\n variant=\"secondary\"\n leftIcon={<Archive size={14} aria-hidden=\"true\" />}\n onClick={() => onBulkArchive(new Set())}\n >\n Archive\n </Button>\n )}\n {onBulkDelete !== undefined && (\n <Button\n size=\"sm\"\n variant=\"danger\"\n leftIcon={<Trash2 size={14} aria-hidden=\"true\" />}\n onClick={() => onBulkDelete(new Set())}\n >\n Delete\n </Button>\n )}\n {onClearSelection !== undefined && (\n <IconButton aria-label=\"Clear selection\" onClick={onClearSelection} size=\"sm\">\n <X size={14} aria-hidden=\"true\" />\n </IconButton>\n )}\n </>\n ) : (\n <>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '0 var(--space-2)',\n height: 32,\n background: 'var(--input-bg)',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-sm)',\n minWidth: 220,\n flex: '1 1 220px',\n maxWidth: 360,\n }}\n >\n <Search size={14} aria-hidden=\"true\" style={{ color: 'var(--fg-muted)', flexShrink: 0 }} />\n <input\n type=\"search\"\n value={query}\n placeholder=\"Filter tasks…\"\n onChange={(e: ChangeEvent<HTMLInputElement>) => onQueryChange(e.target.value)}\n onFocus={() => setSearchFocused(true)}\n onBlur={() => setSearchFocused(false)}\n aria-label=\"Filter tasks\"\n style={{\n flex: 1,\n minWidth: 0,\n border: 0,\n outline: 0,\n background: 'transparent',\n color: 'var(--fg)',\n fontSize: 'var(--fs-13)',\n fontFamily: 'inherit',\n }}\n />\n {query !== '' && (\n <button\n type=\"button\"\n onClick={() => onQueryChange('')}\n aria-label=\"Clear search\"\n style={{\n background: 'transparent',\n border: 0,\n padding: 2,\n color: 'var(--fg-muted)',\n cursor: 'pointer',\n display: 'inline-flex',\n }}\n >\n <X size={12} aria-hidden=\"true\" />\n </button>\n )}\n </div>\n {filters.length > 0 && (\n <div\n role=\"toolbar\"\n aria-label=\"Task filters\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n flexWrap: 'wrap',\n }}\n >\n <Filter\n size={12}\n aria-hidden=\"true\"\n style={{ color: 'var(--fg-muted)', marginRight: 2 }}\n />\n {filters.map((f) => {\n const tone = f.tone ?? 'neutral';\n const isActive = f.id.startsWith('active:');\n // Display rule: callers prepend \"active:\" when toggled on.\n const actualId = isActive ? f.id.slice('active:'.length) : f.id;\n const active = isActive;\n return (\n <button\n key={f.id}\n type=\"button\"\n onClick={() => onFilterToggle(actualId)}\n aria-pressed={active}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 4,\n height: 26,\n padding: '0 var(--space-2)',\n borderRadius: 'var(--radius-pill)',\n border: `1px solid var(--${active ? 'accent' : 'border'})`,\n background: active ? 'color-mix(in oklch, var(--accent) 14%, transparent)' : 'transparent',\n color: 'var(--fg-muted)',\n fontSize: 'var(--fs-12)',\n fontWeight: 500,\n cursor: 'pointer',\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n width: 6,\n height: 6,\n borderRadius: 'var(--radius-pill)',\n background:\n tone === 'neutral'\n ? 'var(--fg-muted)'\n : `var(--${tone})`,\n }}\n />\n {f.label}\n </button>\n );\n })}\n {filters.some((f) => f.id.startsWith('active:')) && (\n <button\n type=\"button\"\n onClick={onClearFilters}\n style={{\n background: 'transparent',\n border: 0,\n color: 'var(--fg-muted)',\n fontSize: 'var(--fs-12)',\n cursor: 'pointer',\n padding: '0 var(--space-2)',\n height: 26,\n }}\n >\n Clear\n </button>\n )}\n </div>\n )}\n <span style={{ flex: 1 }} />\n <span\n style={{\n fontSize: 'var(--fs-12)',\n color: 'var(--fg-muted)',\n fontVariantNumeric: 'tabular-nums',\n }}\n >\n {visibleCount === totalCount\n ? `${totalCount} task${totalCount === 1 ? '' : 's'}`\n : `${visibleCount} of ${totalCount}`}\n </span>\n {onNewTask !== undefined && (\n <Button size=\"sm\" variant=\"primary\" leftIcon={<Plus size={14} aria-hidden=\"true\" />} onClick={onNewTask}>\n New task\n </Button>\n )}\n </>\n )}\n </div>\n );\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\n\n/**\n * useKanbanSelection — track a Set<string> of selected card ids with\n * a small set of helpers, plus an Esc-to-clear keyboard shortcut.\n *\n * Designed for the kanban board's multi-select toolbar. Selection is\n * kept in component state so the board can hand it to the toolbar +\n * card checkbox without prop-drilling.\n */\n\nexport interface UseKanbanSelectionApi {\n /** Current selection. Use `.size` for the count. */\n selected: ReadonlySet<string>;\n /** True iff `id` is in the selection. */\n has: (id: string) => boolean;\n /** Add or remove a single id. */\n toggle: (id: string) => void;\n /** Add ids (no-op if already present). */\n add: (ids: readonly string[]) => void;\n /** Remove ids. */\n remove: (ids: readonly string[]) => void;\n /** Replace the whole selection. */\n set: (ids: readonly string[]) => void;\n /** Drop everything. */\n clear: () => void;\n}\n\nexport function useKanbanSelection(): UseKanbanSelectionApi {\n const [selected, setSelected] = useState<ReadonlySet<string>>(() => new Set());\n\n const toggle = useCallback((id: string) => {\n setSelected((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n }, []);\n\n const add = useCallback((ids: readonly string[]) => {\n if (ids.length === 0) return;\n setSelected((prev) => {\n const next = new Set(prev);\n for (const id of ids) next.add(id);\n return next;\n });\n }, []);\n\n const remove = useCallback((ids: readonly string[]) => {\n if (ids.length === 0) return;\n setSelected((prev) => {\n const next = new Set(prev);\n for (const id of ids) next.delete(id);\n return next;\n });\n }, []);\n\n const set = useCallback((ids: readonly string[]) => {\n setSelected(new Set(ids));\n }, []);\n\n const clear = useCallback(() => {\n setSelected((prev) => (prev.size === 0 ? prev : new Set()));\n }, []);\n\n // Esc clears selection, but only when focus is not inside a text\n // input/textarea/contenteditable (so the user can still press Esc\n // inside an editor).\n useEffect(() => {\n const onKey = (ev: KeyboardEvent) => {\n if (ev.key !== 'Escape') return;\n const target = ev.target as HTMLElement | null;\n if (target) {\n const tag = target.tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || target.isContentEditable) return;\n }\n clear();\n };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, [clear]);\n\n const has = useCallback((id: string) => selected.has(id), [selected]);\n\n return useMemo(\n () => ({ selected, has, toggle, add, remove, set, clear }),\n [selected, has, toggle, add, remove, set, clear],\n );\n}\n","import { useEffect, useState } from 'react';\nimport { Plus, Trash2 } from 'lucide-react';\nimport { Sheet, SheetContent } from '../feedback/Sheet.js';\nimport { Stack } from '../primitives/Stack.js';\nimport { Inline } from '../primitives/Inline.js';\nimport { Button } from '../controls/Button.js';\nimport { Input } from '../controls/Input.js';\nimport { Textarea } from '../controls/Textarea.js';\nimport { Select, SelectContent, SelectItem, SelectTrigger } from '../controls/Select.js';\nimport { Skeleton } from '../feedback/Skeleton.js';\nimport { Badge } from '../data/Badge.js';\nimport { fetchJson } from '../../data/fetcher.js';\nimport type { Task } from '../../data/types.js';\n\n/**\n * TaskDetail — right-side Drawer for editing a single task. Sprint S17.\n *\n * Source-of-truth lives on the backend (tasks-store). Each edit PATCHes\n * `/api/tasks/:id` and the server re-broadcasts the canonical state via\n * `tasks:change`. The Drawer stays open while the WS round-trip resolves\n * so optimistic UI + canonical merge feels seamless.\n */\n\nconst PRIORITY_OPTIONS = [\n { value: 'low', label: 'Low' },\n { value: 'medium', label: 'Medium' },\n { value: 'high', label: 'High' },\n { value: 'urgent', label: 'Urgent' },\n];\n\nconst STATUS_OPTIONS = [\n { value: 'queued', label: 'Backlog' },\n { value: 'doing', label: 'In progress' },\n { value: 'blocked', label: 'In review' },\n { value: 'done', label: 'Done' },\n { value: 'archived', label: 'Archived' },\n];\n\nexport interface TaskDetailProps {\n task: Task;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onDeleted?: () => void;\n}\n\nexport function TaskDetail(props: TaskDetailProps): JSX.Element {\n const { task, open, onOpenChange, onDeleted } = props;\n const [title, setTitle] = useState<string>(task.title);\n const [description, setDescription] = useState<string>(task.description || '');\n const [priority, setPriority] = useState<string>(task.priority || 'medium');\n const [status, setStatus] = useState<string>(task.status || 'queued');\n const [assignee, setAssignee] = useState<string>(task.assignee || '');\n const [due, setDue] = useState<string>(task.due || '');\n const [branch, setBranch] = useState<string>(task.branch || '');\n const [comment, setComment] = useState<string>('');\n const [busy, setBusy] = useState<string | null>(null);\n const [message, setMessage] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [deleting, setDeleting] = useState<boolean>(false);\n\n useEffect(() => {\n if (open) {\n setTitle(task.title);\n setDescription(task.description || '');\n setPriority(task.priority || 'medium');\n setStatus(task.status || 'queued');\n setAssignee(task.assignee || '');\n setDue(task.due || '');\n setBranch(task.branch || '');\n setComment('');\n setMessage(null);\n setError(null);\n }\n }, [open, task]);\n\n const patch = async (body: Record<string, unknown>, label: string): Promise<void> => {\n setBusy(label);\n setMessage(null);\n setError(null);\n try {\n await fetchJson(`/api/tasks/${encodeURIComponent(task.id)}`, {\n method: 'PATCH',\n body,\n });\n setMessage(`${label} saved.`);\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setBusy(null);\n }\n };\n\n const saveTitle = (): void => {\n if (title.trim() && title !== task.title) void patch({ title: title.trim() }, 'Title');\n };\n const saveDescription = (): void => {\n if (description !== (task.description || '')) void patch({ description }, 'Description');\n };\n const savePriority = (v: string): void => {\n setPriority(v);\n if (v !== task.priority) void patch({ priority: v }, 'Priority');\n };\n const saveStatus = (v: string): void => {\n setStatus(v);\n if (v !== task.status) void patch({ status: v }, 'Status');\n };\n const saveAssignee = (): void => {\n const v = assignee.trim();\n if (v !== (task.assignee || '')) void patch({ assignee: v }, 'Assignee');\n };\n const saveDue = (): void => {\n const v = due.trim();\n if (v !== (task.due || '')) void patch({ due: v }, 'Due');\n };\n const saveBranch = (): void => {\n const v = branch.trim();\n if (v !== (task.branch || '')) void patch({ branch: v }, 'Branch');\n };\n\n const addComment = async (): Promise<void> => {\n const v = comment.trim();\n if (!v) return;\n setBusy('comment');\n setError(null);\n try {\n await fetchJson(`/api/tasks/${encodeURIComponent(task.id)}/comments`, {\n method: 'POST',\n body: { text: v },\n });\n setComment('');\n setMessage('Comment added.');\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setBusy(null);\n }\n };\n\n const removeTask = async (): Promise<void> => {\n const ok = typeof window !== 'undefined' && typeof window.confirm === 'function'\n ? window.confirm(`Delete task \"${task.title}\"? This is irreversible.`)\n : true;\n if (!ok) return;\n setDeleting(true);\n try {\n await fetchJson(`/api/tasks/${encodeURIComponent(task.id)}`, { method: 'DELETE' });\n onDeleted?.();\n onOpenChange(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n setDeleting(false);\n }\n };\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent side=\"right\" title=\"Edit task\">\n <Stack gap={4} style={{ padding: 'var(--space-4)' }}>\n <Stack gap={2}>\n <label htmlFor=\"task-title\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Title\n </label>\n <Input\n id=\"task-title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n onBlur={saveTitle}\n disabled={busy !== null}\n />\n </Stack>\n\n <Stack gap={2}>\n <label htmlFor=\"task-status\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Status\n </label>\n <Select value={status} onValueChange={saveStatus}>\n <SelectTrigger id=\"task-status\" size=\"sm\" placeholder=\"Status\" />\n <SelectContent>\n {STATUS_OPTIONS.map((opt) => (\n <SelectItem key={opt.value} value={opt.value}>{opt.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Stack>\n\n <Inline gap={2}>\n <Stack gap={2} style={{ flex: 1 }}>\n <label htmlFor=\"task-priority\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Priority\n </label>\n <Select value={priority} onValueChange={savePriority}>\n <SelectTrigger id=\"task-priority\" size=\"sm\" placeholder=\"Priority\" />\n <SelectContent>\n {PRIORITY_OPTIONS.map((opt) => (\n <SelectItem key={opt.value} value={opt.value}>{opt.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Stack>\n <Stack gap={2} style={{ flex: 1 }}>\n <label htmlFor=\"task-due\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Due\n </label>\n <Input\n id=\"task-due\"\n type=\"date\"\n value={due ? due.slice(0, 10) : ''}\n onChange={(e) => setDue(e.target.value)}\n onBlur={saveDue}\n disabled={busy !== null}\n />\n </Stack>\n </Inline>\n\n <Inline gap={2}>\n <Stack gap={2} style={{ flex: 1 }}>\n <label htmlFor=\"task-assignee\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Assignee\n </label>\n <Input\n id=\"task-assignee\"\n value={assignee}\n onChange={(e) => setAssignee(e.target.value)}\n onBlur={saveAssignee}\n placeholder=\"agent name (blank = unassigned)\"\n disabled={busy !== null}\n />\n </Stack>\n <Stack gap={2} style={{ flex: 1 }}>\n <label htmlFor=\"task-branch\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Branch\n </label>\n <Input\n id=\"task-branch\"\n value={branch}\n onChange={(e) => setBranch(e.target.value)}\n onBlur={saveBranch}\n placeholder=\"feature/foo\"\n disabled={busy !== null}\n />\n </Stack>\n </Inline>\n\n <Stack gap={2}>\n <label htmlFor=\"task-description\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Description\n </label>\n <Textarea\n id=\"task-description\"\n rows={5}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n onBlur={saveDescription}\n disabled={busy !== null}\n placeholder=\"What's the work, why, how to verify…\"\n />\n </Stack>\n\n <Stack gap={2}>\n <label htmlFor=\"task-comment\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Add comment\n </label>\n <Inline gap={2} align=\"start\">\n <Textarea\n id=\"task-comment\"\n rows={2}\n value={comment}\n onChange={(e) => setComment(e.target.value)}\n placeholder=\"Leave a progress note…\"\n disabled={busy !== null}\n style={{ flex: 1 }}\n />\n <Button variant=\"secondary\" onClick={() => { void addComment(); }} disabled={!comment.trim() || busy !== null}>\n <Plus size={14} aria-hidden /> Comment\n </Button>\n </Inline>\n </Stack>\n\n <Stack gap={2}>\n <div style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Metadata</div>\n <Inline gap={1} wrap>\n {task.metadata?.goalId !== undefined && typeof task.metadata.goalId === 'string' && (\n <Badge tone=\"info\" title={`Linked to goal ${String(task.metadata.goalId)}`}>\n goal: {String(task.metadata.goalId)}\n </Badge>\n )}\n {task.metadata?.krId !== undefined && typeof task.metadata.krId === 'string' && (\n <Badge tone=\"info\" title={`Linked to KR ${String(task.metadata.krId)}`}>\n kr: {String(task.metadata.krId)}\n </Badge>\n )}\n {task.id && <Badge tone=\"neutral\" title={task.id}>id: {task.id}</Badge>}\n </Inline>\n </Stack>\n\n <div style={{ borderTop: '1px solid var(--border)', paddingTop: 'var(--space-3)' }}>\n <Button variant=\"danger\" onClick={() => { void removeTask(); }} disabled={deleting || busy !== null}>\n <Trash2 size={14} aria-hidden /> {deleting ? 'Deleting…' : 'Delete task'}\n </Button>\n </div>\n\n {message !== null && (\n <div role=\"status\" style={{ fontSize: 'var(--fs-12)', color: 'var(--success)' }}>{message}</div>\n )}\n {error !== null && (\n <div role=\"alert\" style={{ fontSize: 'var(--fs-12)', color: 'var(--danger)' }}>{error}</div>\n )}\n {busy !== null && <Skeleton style={{ height: 12 }} />}\n </Stack>\n </SheetContent>\n </Sheet>\n );\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\nimport { Plus } from 'lucide-react';\nimport { Stack } from '../../ui/primitives/Stack.js';\nimport { Inline } from '../../ui/primitives/Inline.js';\nimport { ViewHeader } from '../../ui/data/ViewHeader.js';\nimport { KanbanBoard } from '../../ui/kanban/KanbanBoard.js';\nimport { KanbanColumn, type KanbanColumnData } from '../../ui/kanban/KanbanColumn.js';\nimport { KanbanCard, useKanbanCardSortable, type KanbanCardData } from '../../ui/kanban/KanbanCard.js';\nimport { KanbanToolbar, useKanbanSelection, type KanbanFilter } from '../../ui/index.js';\nimport { Skeleton } from '../../ui/feedback/Skeleton.js';\nimport { TaskDetail } from '../../ui/tasks/TaskDetail.js';\nimport { Sheet, SheetContent } from '../../ui/feedback/Sheet.js';\nimport { Input } from '../../ui/controls/Input.js';\nimport { Textarea } from '../../ui/controls/Textarea.js';\nimport { Button } from '../../ui/controls/Button.js';\nimport { useFetch } from '../../data/useFetch.js';\nimport { useWsMessage } from '../../data/useWebSocket.js';\nimport { fetchJson, FetchError } from '../../data/fetcher.js';\nimport type { Task, WsMessage } from '../../data/types.js';\n\ntype TaskStatus = NonNullable<Task['status']>;\n\n/**\n * TasksView — Sprint S10. Pulls `/api/tasks` and maps server statuses\n * to v8 kanban columns. Drag a card between columns → PATCH\n * /api/tasks/:id/status. Live updates via `tasks:change`.\n *\n * v10.0.6 — adds KanbanToolbar (search + priority filter chips +\n * bulk-actions row), useKanbanSelection hook (Esc-to-clear), and a\n * 6th \"Backlog\" column from PR #14.\n */\n\nconst COLUMNS: KanbanColumnData[] = [\n { id: 'backlog', title: 'Backlog', accentTone: 'neutral' },\n { id: 'queued', title: 'Queued', accentTone: 'info' },\n { id: 'doing', title: 'In progress', accentTone: 'accent', wipLimit: 5 },\n { id: 'blocked', title: 'In review', accentTone: 'warning' },\n { id: 'done', title: 'Done', accentTone: 'success' },\n { id: 'archived', title: 'Archived', accentTone: 'neutral' },\n];\n\nconst PRIORITY_MAP: Record<string, KanbanCardData['priority']> = {\n low: 'low',\n medium: 'medium',\n high: 'high',\n urgent: 'urgent',\n};\n\ninterface Card extends KanbanCardData {\n taskId: string;\n columnId: TaskStatus;\n}\n\nfunction taskToCard(t: Task): Card {\n return {\n id: t.id,\n taskId: t.id,\n columnId: statusToColumn(t.status),\n title: t.title,\n priority: PRIORITY_MAP[t.priority || 'medium'] || 'medium',\n branch: t.branch,\n due: t.due,\n comments: t.comments,\n attachments: t.attachments,\n };\n}\n\nfunction statusToColumn(status?: TaskStatus): TaskStatus {\n switch (status) {\n case 'backlog':\n case 'queued':\n case 'doing':\n case 'blocked':\n case 'done':\n case 'archived':\n return status;\n default:\n return 'backlog';\n }\n}\n\n/**\n * SortableCard — wraps a single KanbanCard with dnd-kit's useSortable\n * so KanbanBoard.onDragEnd can fire.\n */\nfunction SortableCard({ card }: { card: Card }): JSX.Element {\n const sortable = useKanbanCardSortable(card.id);\n return (\n <KanbanCard\n card={card}\n isDragging={sortable.isDragging}\n dragHandleProps={{ ...sortable.attributes, ...sortable.listeners, ref: sortable.setNodeRef, style: sortable.style }}\n />\n );\n}\n\nexport function TasksView(): JSX.Element {\n const tasks = useFetch<{ tasks?: Task[]; count?: number }>('/api/tasks');\n const [cards, setCards] = useState<Card[]>([]);\n const [error, setError] = useState<string | null>(null);\n const [openTaskId, setOpenTaskId] = useState<string | null>(null);\n const selection = useKanbanSelection();\n const [query, setQuery] = useState<string>('');\n const [activeFilters, setActiveFilters] = useState<ReadonlySet<string>>(new Set());\n const [createDraft, setCreateDraft] = useState<{ title: string; description: string; priority: 'low' | 'medium' | 'high' | 'urgent' } | null>(null);\n const [creating, setCreating] = useState(false);\n\n const saveCreate = async (): Promise<void> => {\n if (createDraft === null || !createDraft.title.trim()) return;\n setCreating(true);\n try {\n await fetchJson('/api/tasks', { method: 'POST', body: { title: createDraft.title.trim(), description: createDraft.description, priority: createDraft.priority, status: 'queued' } });\n setCreateDraft(null);\n tasks.refetch();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n } finally {\n setCreating(false);\n }\n };\n\n const onWsRemove = useCallback((msg: WsMessage) => {\n const m = msg as { type?: string; id?: string };\n if (m.type !== 'tasks:removed' && m.type !== 'task:removed') return;\n if (!m.id) return;\n setCards((prev) => prev.filter((c) => c.taskId !== m.id));\n selection.remove([m.id]);\n if (openTaskId === m.id) setOpenTaskId(null);\n }, [openTaskId, selection]);\n useWsMessage('tasks:removed', onWsRemove);\n useWsMessage('task:removed', onWsRemove);\n\n const toggleSelect = (taskId: string): void => {\n selection.toggle(taskId);\n };\n\n const bulkMove = async (toStatus: TaskStatus): Promise<void> => {\n const ids = Array.from(selection.selected);\n if (ids.length === 0) return;\n setCards((prev) => prev.map((c) => (selection.has(c.taskId) ? { ...c, columnId: toStatus } : c)));\n try {\n await fetchJson('/api/tasks/bulk-status', {\n method: 'PATCH',\n body: { ids, status: toStatus },\n });\n selection.clear();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n }\n };\n\n // Sync fetched list → local state. Effect-driven so we don't setState\n // during render (which React warns about under StrictMode and which\n // can double-render the cards).\n useEffect(() => {\n if (tasks.data?.tasks) {\n setCards(tasks.data.tasks.map(taskToCard));\n }\n }, [tasks.data]);\n\n const onWsChange = useCallback((msg: WsMessage) => {\n if (msg.type !== 'tasks:change') return;\n const t = msg.task as Task | undefined;\n if (!t) return;\n setCards((prev) => {\n const idx = prev.findIndex((c) => c.taskId === t.id);\n const card = taskToCard({ ...t, status: statusToColumn(t.status) });\n if (idx === -1) return [...prev, card];\n const copy = prev.slice();\n copy[idx] = { ...copy[idx], ...card };\n return copy;\n });\n }, []);\n useWsMessage('tasks:change', onWsChange);\n\n const onCardMove = useCallback(async (cardId: string, _from: string, to: string) => {\n const card = cards.find((c) => c.taskId === cardId || c.id === cardId);\n if (!card) return;\n const nextStatus = statusToColumn(to as TaskStatus);\n setCards((prev) =>\n prev.map((c) => (c.taskId === cardId ? { ...c, columnId: nextStatus } : c)),\n );\n try {\n await fetchJson(`/api/tasks/${encodeURIComponent(card.taskId)}/status`, {\n method: 'PATCH',\n body: { status: nextStatus },\n });\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n // Roll back on failure.\n setCards((prev) =>\n prev.map((c) => (c.taskId === cardId ? { ...c, columnId: card.columnId } : c)),\n );\n }\n }, [cards]);\n\n const counts: Record<string, number> = {};\n for (const c of cards) counts[c.columnId] = (counts[c.columnId] || 0) + 1;\n\n const openTask = openTaskId ? tasks.data?.tasks?.find((t) => t.id === openTaskId) ?? null : null;\n const selectedCount = selection.selected.size;\n\n // ── v10.0.6 — search + filter chips (PR #14 toolbar wiring) ──\n const filteredCards = useMemo<Card[]>(() => {\n const q = query.trim().toLowerCase();\n return cards.filter((c) => {\n if (activeFilters.size > 0) {\n if (activeFilters.has(`status:${c.columnId}`) === false) {\n const hasPriority = c.priority !== undefined && activeFilters.has(`priority:${c.priority}`);\n const hasStatus = activeFilters.has(`status:${c.columnId}`);\n if (!hasPriority && !hasStatus) return false;\n }\n }\n if (q !== '') {\n const hay = `${c.title} ${c.description ?? ''}`.toLowerCase();\n if (hay.includes(q) === false) return false;\n }\n return true;\n });\n }, [cards, query, activeFilters]);\n\n const priorityFilters: KanbanFilter[] = [\n { id: 'priority:low', label: 'Low', tone: 'neutral' },\n { id: 'priority:medium', label: 'Medium', tone: 'info' },\n { id: 'priority:high', label: 'High', tone: 'warning' },\n { id: 'priority:urgent', label: 'Urgent', tone: 'danger' },\n ];\n const statusFilters: KanbanFilter[] = COLUMNS.map((c) => ({ id: `status:${c.id}`, label: c.title as string }));\n const allFilters: KanbanFilter[] = [...priorityFilters, ...statusFilters];\n\n const onFilterToggle = useCallback((id: string) => {\n setActiveFilters((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n }, []);\n const onClearFilters = useCallback(() => setActiveFilters(new Set()), []);\n\n return (\n <Stack gap={4} data-testid=\"tasks-view\">\n <ViewHeader\n title=\"Tasks\"\n description=\"Drag cards across columns. Click a card to edit. Use the checkbox to select multiple.\"\n actions={\n <Inline gap={2} align=\"center\">\n {error !== null && <span role=\"alert\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>{error}</span>}\n <Button variant=\"primary\" onClick={() => setCreateDraft({ title: '', description: '', priority: 'medium' })} data-testid=\"task-create-open\">\n <Plus size={14} aria-hidden /> New task\n </Button>\n </Inline>\n }\n />\n {selectedCount > 0 && (\n <KanbanToolbar\n totalCount={cards.length}\n visibleCount={filteredCards.length}\n selectedCount={selectedCount}\n query={query}\n onQueryChange={setQuery}\n filters={allFilters}\n onFilterToggle={onFilterToggle}\n onClearFilters={onClearFilters}\n onNewTask={() => setCreateDraft({ title: '', description: '', priority: 'medium' })}\n onBulkMove={() => void bulkMove('doing')}\n onBulkArchive={() => void bulkMove('archived')}\n onBulkDelete={async () => {\n const ids = Array.from(selection.selected);\n if (ids.length === 0) return;\n if (!window.confirm(`Delete ${ids.length} task${ids.length === 1 ? '' : 's'}? This cannot be undone.`)) return;\n try {\n await fetchJson('/api/tasks/bulk-status', { method: 'PATCH', body: { ids, status: 'archived' } });\n selection.clear();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n }\n }}\n onClearSelection={() => selection.clear()}\n />\n )}\n {tasks.loading && cards.length === 0 ? (\n <Stack gap={3}>\n <Skeleton style={{ height: 120 }} />\n <Skeleton style={{ height: 120 }} />\n </Stack>\n ) : (\n <KanbanBoard columns={COLUMNS} onCardMove={onCardMove}>\n {COLUMNS.map((col) => {\n const inColumn = filteredCards.filter((c) => c.columnId === col.id);\n return (\n <KanbanColumn\n key={col.id}\n column={{ ...col, count: counts[col.id] || 0 }}\n >\n {inColumn.map((card) => (\n <div key={card.id} style={{ position: 'relative' }}>\n <input\n type=\"checkbox\"\n checked={selection.has(card.taskId)}\n onChange={() => toggleSelect(card.taskId)}\n onClick={(e) => e.stopPropagation()}\n aria-label={`Select ${card.title}`}\n style={{ position: 'absolute', top: 8, left: 8, zIndex: 2 }}\n />\n <div onClick={() => setOpenTaskId(card.taskId)} role=\"button\" tabIndex={0} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setOpenTaskId(card.taskId); } }} style={{ cursor: 'pointer' }}>\n <SortableCard card={card} />\n </div>\n </div>\n ))}\n </KanbanColumn>\n );\n })}\n </KanbanBoard>\n )}\n {openTask && (\n <TaskDetail\n task={openTask}\n open={openTaskId !== null}\n onOpenChange={(o) => { if (!o) setOpenTaskId(null); }}\n onDeleted={() => {\n setCards((prev) => prev.filter((c) => c.taskId !== openTask.id));\n setOpenTaskId(null);\n }}\n />\n )}\n\n {/* v9.2.0 — create-task Sheet. Replaces the missing \"new task\"\n action that the audit flagged as a HIGH gap. */}\n <Sheet open={createDraft !== null} onOpenChange={(o) => { if (!o) setCreateDraft(null); }}>\n <SheetContent side=\"right\" title=\"New task\">\n {createDraft !== null && (\n <Stack gap={4} style={{ padding: 'var(--space-4)' }}>\n <Stack gap={2}>\n <label htmlFor=\"task-create-title\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Title</label>\n <Input\n id=\"task-create-title\"\n value={createDraft.title}\n onChange={(e) => setCreateDraft({ ...createDraft, title: e.target.value })}\n placeholder=\"What needs doing?\"\n disabled={creating}\n data-testid=\"task-create-title\"\n />\n </Stack>\n <Stack gap={2}>\n <label htmlFor=\"task-create-desc\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Description (optional)</label>\n <Textarea\n id=\"task-create-desc\"\n value={createDraft.description}\n onChange={(e) => setCreateDraft({ ...createDraft, description: e.target.value })}\n rows={4}\n disabled={creating}\n data-testid=\"task-create-desc\"\n />\n </Stack>\n <Stack gap={2}>\n <label htmlFor=\"task-create-priority\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Priority</label>\n <select\n id=\"task-create-priority\"\n value={createDraft.priority}\n onChange={(e) => setCreateDraft({ ...createDraft, priority: e.target.value as typeof createDraft.priority })}\n disabled={creating}\n data-testid=\"task-create-priority\"\n style={{ height: 32, padding: '0 var(--space-2)', borderRadius: 'var(--radius-sm)', border: '1px solid var(--border)', background: 'var(--surface-0)', color: 'var(--fg)', fontSize: 'var(--fs-13)' }}\n >\n <option value=\"low\">Low</option>\n <option value=\"medium\">Medium</option>\n <option value=\"high\">High</option>\n <option value=\"urgent\">Urgent</option>\n </select>\n </Stack>\n <Inline gap={2}>\n <Button variant=\"primary\" onClick={() => { void saveCreate(); }} disabled={creating || !createDraft.title.trim()} data-testid=\"task-create-submit\">\n Create task\n </Button>\n <Button variant=\"ghost\" onClick={() => setCreateDraft(null)} disabled={creating}>\n Cancel\n </Button>\n </Inline>\n </Stack>\n )}\n </SheetContent>\n </Sheet>\n </Stack>\n );\n}"],"names":["ArrowRight","createLucideIcon","KanbanToolbar","props","totalCount","visibleCount","selectedCount","query","onQueryChange","filters","onFilterToggle","onClearFilters","onNewTask","onBulkMove","onBulkArchive","onBulkDelete","onClearSelection","className","searchFocused","setSearchFocused","useState","isBulk","jsx","cx","jsxs","Fragment","Button","Archive","Trash2","IconButton","X","Search","e","Filter","f","tone","isActive","actualId","active","Plus","useKanbanSelection","selected","setSelected","toggle","useCallback","id","prev","next","add","ids","remove","set","clear","useEffect","onKey","ev","target","tag","has","useMemo","PRIORITY_OPTIONS","STATUS_OPTIONS","TaskDetail","task","open","onOpenChange","onDeleted","title","setTitle","description","setDescription","priority","setPriority","status","setStatus","assignee","setAssignee","due","setDue","branch","setBranch","comment","setComment","busy","setBusy","message","setMessage","error","setError","deleting","setDeleting","patch","body","label","fetchJson","err","saveTitle","saveDescription","savePriority","v","saveStatus","saveAssignee","saveDue","saveBranch","addComment","removeTask","Sheet","SheetContent","Stack","Input","Select","SelectTrigger","SelectContent","opt","SelectItem","Inline","Textarea","_a","Badge","_b","Skeleton","COLUMNS","PRIORITY_MAP","taskToCard","t","statusToColumn","SortableCard","card","sortable","useKanbanCardSortable","KanbanCard","TasksView","tasks","useFetch","cards","setCards","openTaskId","setOpenTaskId","selection","setQuery","activeFilters","setActiveFilters","createDraft","setCreateDraft","creating","setCreating","saveCreate","FetchError","onWsRemove","msg","m","useWsMessage","toggleSelect","taskId","bulkMove","toStatus","onWsChange","idx","c","copy","onCardMove","cardId","_from","to","nextStatus","counts","openTask","filteredCards","q","hasPriority","hasStatus","priorityFilters","statusFilters","allFilters","ViewHeader","KanbanBoard","col","inColumn","KanbanColumn","o"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"TasksView-CT0fPlos.js","sources":["../../../node_modules/lucide-react/dist/esm/icons/arrow-right.js","../../src/web/v8/ui/kanban/KanbanToolbar.tsx","../../src/web/v8/ui/kanban/useKanbanSelection.ts","../../src/web/v8/ui/tasks/TaskDetail.tsx","../../src/web/v8/views/Tasks/TasksView.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.460.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ArrowRight = createLucideIcon(\"ArrowRight\", [\n [\"path\", { d: \"M5 12h14\", key: \"1ays0h\" }],\n [\"path\", { d: \"m12 5 7 7-7 7\", key: \"xquz4c\" }]\n]);\n\nexport { ArrowRight as default };\n//# sourceMappingURL=arrow-right.js.map\n","import { useState, type ChangeEvent, type ReactNode } from 'react';\nimport { Plus, Search, Trash2, Archive, ArrowRight, X, Filter } from 'lucide-react';\nimport { Button } from '../controls/Button.js';\nimport { IconButton } from '../controls/IconButton.js';\nimport { cx } from '../utils/cx.js';\n\n/**\n * KanbanToolbar — top-of-board toolbar.\n *\n * Three modes:\n * - normal: search input + filter chips + \"New task\" button.\n * - selecting: replaces the action row with N-selected count +\n * bulk-actions (Move / Archive / Delete).\n * - filtered: shows a \"Clear filters\" pill next to the search.\n *\n * Consumers control query state via callbacks. The toolbar keeps no\n * internal search/filter state of its own — that lives in the view\n * so the board can re-derive visible cards.\n */\n\nexport interface KanbanFilter {\n /** Stable filter id; used as the chip key + for clearing. */\n id: string;\n /** Visible chip label (e.g. \"High priority\"). */\n label: ReactNode;\n /** Optional tone for the chip. */\n tone?: 'neutral' | 'info' | 'success' | 'warning' | 'danger' | 'accent';\n}\n\nexport interface KanbanToolbarProps {\n /** Total number of cards on the board (for \"showing X of Y\"). */\n totalCount: number;\n /** Number of cards currently visible after filtering. */\n visibleCount: number;\n /** Number of selected cards. When >0, the toolbar swaps to bulk mode. */\n selectedCount: number;\n\n /** Free-text search. */\n query: string;\n onQueryChange: (value: string) => void;\n\n /** Active filters. */\n filters: readonly KanbanFilter[];\n onFilterToggle: (filterId: string) => void;\n onClearFilters: () => void;\n\n /** New-task action. Hidden when the toolbar is in bulk mode. */\n onNewTask?: () => void;\n\n /** Bulk actions, shown only when selectedCount > 0. */\n onBulkMove?: (selectedIds: ReadonlySet<string>) => void;\n onBulkArchive?: (selectedIds: ReadonlySet<string>) => void;\n onBulkDelete?: (selectedIds: ReadonlySet<string>) => void;\n onClearSelection?: () => void;\n\n className?: string;\n}\n\nexport function KanbanToolbar(props: KanbanToolbarProps): JSX.Element {\n const {\n totalCount,\n visibleCount,\n selectedCount,\n query,\n onQueryChange,\n filters,\n onFilterToggle,\n onClearFilters,\n onNewTask,\n onBulkMove,\n onBulkArchive,\n onBulkDelete,\n onClearSelection,\n className,\n } = props;\n\n const [searchFocused, setSearchFocused] = useState(false);\n const isBulk = selectedCount > 0;\n\n return (\n <div\n className={cx('v8-kanban-toolbar', className)}\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: 'var(--space-2)',\n padding: 'var(--space-2) var(--space-3)',\n background: 'var(--surface-0)',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius)',\n }}\n >\n {isBulk ? (\n <>\n <span\n style={{\n fontSize: 'var(--fs-13)',\n fontWeight: 600,\n color: 'var(--fg)',\n }}\n >\n {selectedCount} selected\n </span>\n <span style={{ flex: 1 }} />\n {onBulkMove !== undefined && (\n <Button size=\"sm\" variant=\"secondary\" leftIcon={<ArrowRight size={14} aria-hidden=\"true\" />} onClick={() => onBulkMove(new Set())}>\n Move…\n </Button>\n )}\n {onBulkArchive !== undefined && (\n <Button\n size=\"sm\"\n variant=\"secondary\"\n leftIcon={<Archive size={14} aria-hidden=\"true\" />}\n onClick={() => onBulkArchive(new Set())}\n >\n Archive\n </Button>\n )}\n {onBulkDelete !== undefined && (\n <Button\n size=\"sm\"\n variant=\"danger\"\n leftIcon={<Trash2 size={14} aria-hidden=\"true\" />}\n onClick={() => onBulkDelete(new Set())}\n >\n Delete\n </Button>\n )}\n {onClearSelection !== undefined && (\n <IconButton aria-label=\"Clear selection\" onClick={onClearSelection} size=\"sm\">\n <X size={14} aria-hidden=\"true\" />\n </IconButton>\n )}\n </>\n ) : (\n <>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '0 var(--space-2)',\n height: 32,\n background: 'var(--input-bg)',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-sm)',\n minWidth: 220,\n flex: '1 1 220px',\n maxWidth: 360,\n }}\n >\n <Search size={14} aria-hidden=\"true\" style={{ color: 'var(--fg-muted)', flexShrink: 0 }} />\n <input\n type=\"search\"\n value={query}\n placeholder=\"Filter tasks…\"\n onChange={(e: ChangeEvent<HTMLInputElement>) => onQueryChange(e.target.value)}\n onFocus={() => setSearchFocused(true)}\n onBlur={() => setSearchFocused(false)}\n aria-label=\"Filter tasks\"\n style={{\n flex: 1,\n minWidth: 0,\n border: 0,\n outline: 0,\n background: 'transparent',\n color: 'var(--fg)',\n fontSize: 'var(--fs-13)',\n fontFamily: 'inherit',\n }}\n />\n {query !== '' && (\n <button\n type=\"button\"\n onClick={() => onQueryChange('')}\n aria-label=\"Clear search\"\n style={{\n background: 'transparent',\n border: 0,\n padding: 2,\n color: 'var(--fg-muted)',\n cursor: 'pointer',\n display: 'inline-flex',\n }}\n >\n <X size={12} aria-hidden=\"true\" />\n </button>\n )}\n </div>\n {filters.length > 0 && (\n <div\n role=\"toolbar\"\n aria-label=\"Task filters\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n flexWrap: 'wrap',\n }}\n >\n <Filter\n size={12}\n aria-hidden=\"true\"\n style={{ color: 'var(--fg-muted)', marginRight: 2 }}\n />\n {filters.map((f) => {\n const tone = f.tone ?? 'neutral';\n const isActive = f.id.startsWith('active:');\n // Display rule: callers prepend \"active:\" when toggled on.\n const actualId = isActive ? f.id.slice('active:'.length) : f.id;\n const active = isActive;\n return (\n <button\n key={f.id}\n type=\"button\"\n onClick={() => onFilterToggle(actualId)}\n aria-pressed={active}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 4,\n height: 26,\n padding: '0 var(--space-2)',\n borderRadius: 'var(--radius-pill)',\n border: `1px solid var(--${active ? 'accent' : 'border'})`,\n background: active ? 'color-mix(in oklch, var(--accent) 14%, transparent)' : 'transparent',\n color: 'var(--fg-muted)',\n fontSize: 'var(--fs-12)',\n fontWeight: 500,\n cursor: 'pointer',\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n width: 6,\n height: 6,\n borderRadius: 'var(--radius-pill)',\n background:\n tone === 'neutral'\n ? 'var(--fg-muted)'\n : `var(--${tone})`,\n }}\n />\n {f.label}\n </button>\n );\n })}\n {filters.some((f) => f.id.startsWith('active:')) && (\n <button\n type=\"button\"\n onClick={onClearFilters}\n style={{\n background: 'transparent',\n border: 0,\n color: 'var(--fg-muted)',\n fontSize: 'var(--fs-12)',\n cursor: 'pointer',\n padding: '0 var(--space-2)',\n height: 26,\n }}\n >\n Clear\n </button>\n )}\n </div>\n )}\n <span style={{ flex: 1 }} />\n <span\n style={{\n fontSize: 'var(--fs-12)',\n color: 'var(--fg-muted)',\n fontVariantNumeric: 'tabular-nums',\n }}\n >\n {visibleCount === totalCount\n ? `${totalCount} task${totalCount === 1 ? '' : 's'}`\n : `${visibleCount} of ${totalCount}`}\n </span>\n {onNewTask !== undefined && (\n <Button size=\"sm\" variant=\"primary\" leftIcon={<Plus size={14} aria-hidden=\"true\" />} onClick={onNewTask}>\n New task\n </Button>\n )}\n </>\n )}\n </div>\n );\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\n\n/**\n * useKanbanSelection — track a Set<string> of selected card ids with\n * a small set of helpers, plus an Esc-to-clear keyboard shortcut.\n *\n * Designed for the kanban board's multi-select toolbar. Selection is\n * kept in component state so the board can hand it to the toolbar +\n * card checkbox without prop-drilling.\n */\n\nexport interface UseKanbanSelectionApi {\n /** Current selection. Use `.size` for the count. */\n selected: ReadonlySet<string>;\n /** True iff `id` is in the selection. */\n has: (id: string) => boolean;\n /** Add or remove a single id. */\n toggle: (id: string) => void;\n /** Add ids (no-op if already present). */\n add: (ids: readonly string[]) => void;\n /** Remove ids. */\n remove: (ids: readonly string[]) => void;\n /** Replace the whole selection. */\n set: (ids: readonly string[]) => void;\n /** Drop everything. */\n clear: () => void;\n}\n\nexport function useKanbanSelection(): UseKanbanSelectionApi {\n const [selected, setSelected] = useState<ReadonlySet<string>>(() => new Set());\n\n const toggle = useCallback((id: string) => {\n setSelected((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n }, []);\n\n const add = useCallback((ids: readonly string[]) => {\n if (ids.length === 0) return;\n setSelected((prev) => {\n const next = new Set(prev);\n for (const id of ids) next.add(id);\n return next;\n });\n }, []);\n\n const remove = useCallback((ids: readonly string[]) => {\n if (ids.length === 0) return;\n setSelected((prev) => {\n const next = new Set(prev);\n for (const id of ids) next.delete(id);\n return next;\n });\n }, []);\n\n const set = useCallback((ids: readonly string[]) => {\n setSelected(new Set(ids));\n }, []);\n\n const clear = useCallback(() => {\n setSelected((prev) => (prev.size === 0 ? prev : new Set()));\n }, []);\n\n // Esc clears selection, but only when focus is not inside a text\n // input/textarea/contenteditable (so the user can still press Esc\n // inside an editor).\n useEffect(() => {\n const onKey = (ev: KeyboardEvent) => {\n if (ev.key !== 'Escape') return;\n const target = ev.target as HTMLElement | null;\n if (target) {\n const tag = target.tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || target.isContentEditable) return;\n }\n clear();\n };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, [clear]);\n\n const has = useCallback((id: string) => selected.has(id), [selected]);\n\n return useMemo(\n () => ({ selected, has, toggle, add, remove, set, clear }),\n [selected, has, toggle, add, remove, set, clear],\n );\n}\n","import { useEffect, useState } from 'react';\nimport { Plus, Trash2 } from 'lucide-react';\nimport { Sheet, SheetContent } from '../feedback/Sheet.js';\nimport { Stack } from '../primitives/Stack.js';\nimport { Inline } from '../primitives/Inline.js';\nimport { Button } from '../controls/Button.js';\nimport { Input } from '../controls/Input.js';\nimport { Textarea } from '../controls/Textarea.js';\nimport { Select, SelectContent, SelectItem, SelectTrigger } from '../controls/Select.js';\nimport { Skeleton } from '../feedback/Skeleton.js';\nimport { Badge } from '../data/Badge.js';\nimport { fetchJson } from '../../data/fetcher.js';\nimport type { Task } from '../../data/types.js';\n\n/**\n * TaskDetail — right-side Drawer for editing a single task. Sprint S17.\n *\n * Source-of-truth lives on the backend (tasks-store). Each edit PATCHes\n * `/api/tasks/:id` and the server re-broadcasts the canonical state via\n * `tasks:change`. The Drawer stays open while the WS round-trip resolves\n * so optimistic UI + canonical merge feels seamless.\n */\n\nconst PRIORITY_OPTIONS = [\n { value: 'low', label: 'Low' },\n { value: 'medium', label: 'Medium' },\n { value: 'high', label: 'High' },\n { value: 'urgent', label: 'Urgent' },\n];\n\nconst STATUS_OPTIONS = [\n { value: 'queued', label: 'Backlog' },\n { value: 'doing', label: 'In progress' },\n { value: 'blocked', label: 'In review' },\n { value: 'done', label: 'Done' },\n { value: 'archived', label: 'Archived' },\n];\n\nexport interface TaskDetailProps {\n task: Task;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onDeleted?: () => void;\n}\n\nexport function TaskDetail(props: TaskDetailProps): JSX.Element {\n const { task, open, onOpenChange, onDeleted } = props;\n const [title, setTitle] = useState<string>(task.title);\n const [description, setDescription] = useState<string>(task.description || '');\n const [priority, setPriority] = useState<string>(task.priority || 'medium');\n const [status, setStatus] = useState<string>(task.status || 'queued');\n const [assignee, setAssignee] = useState<string>(task.assignee || '');\n const [due, setDue] = useState<string>(task.due || '');\n const [branch, setBranch] = useState<string>(task.branch || '');\n const [comment, setComment] = useState<string>('');\n const [busy, setBusy] = useState<string | null>(null);\n const [message, setMessage] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [deleting, setDeleting] = useState<boolean>(false);\n\n useEffect(() => {\n if (open) {\n setTitle(task.title);\n setDescription(task.description || '');\n setPriority(task.priority || 'medium');\n setStatus(task.status || 'queued');\n setAssignee(task.assignee || '');\n setDue(task.due || '');\n setBranch(task.branch || '');\n setComment('');\n setMessage(null);\n setError(null);\n }\n }, [open, task]);\n\n const patch = async (body: Record<string, unknown>, label: string): Promise<void> => {\n setBusy(label);\n setMessage(null);\n setError(null);\n try {\n await fetchJson(`/api/tasks/${encodeURIComponent(task.id)}`, {\n method: 'PATCH',\n body,\n });\n setMessage(`${label} saved.`);\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setBusy(null);\n }\n };\n\n const saveTitle = (): void => {\n if (title.trim() && title !== task.title) void patch({ title: title.trim() }, 'Title');\n };\n const saveDescription = (): void => {\n if (description !== (task.description || '')) void patch({ description }, 'Description');\n };\n const savePriority = (v: string): void => {\n setPriority(v);\n if (v !== task.priority) void patch({ priority: v }, 'Priority');\n };\n const saveStatus = (v: string): void => {\n setStatus(v);\n if (v !== task.status) void patch({ status: v }, 'Status');\n };\n const saveAssignee = (): void => {\n const v = assignee.trim();\n if (v !== (task.assignee || '')) void patch({ assignee: v }, 'Assignee');\n };\n const saveDue = (): void => {\n const v = due.trim();\n if (v !== (task.due || '')) void patch({ due: v }, 'Due');\n };\n const saveBranch = (): void => {\n const v = branch.trim();\n if (v !== (task.branch || '')) void patch({ branch: v }, 'Branch');\n };\n\n const addComment = async (): Promise<void> => {\n const v = comment.trim();\n if (!v) return;\n setBusy('comment');\n setError(null);\n try {\n await fetchJson(`/api/tasks/${encodeURIComponent(task.id)}/comments`, {\n method: 'POST',\n body: { text: v },\n });\n setComment('');\n setMessage('Comment added.');\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setBusy(null);\n }\n };\n\n const removeTask = async (): Promise<void> => {\n const ok = typeof window !== 'undefined' && typeof window.confirm === 'function'\n ? window.confirm(`Delete task \"${task.title}\"? This is irreversible.`)\n : true;\n if (!ok) return;\n setDeleting(true);\n try {\n await fetchJson(`/api/tasks/${encodeURIComponent(task.id)}`, { method: 'DELETE' });\n onDeleted?.();\n onOpenChange(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n setDeleting(false);\n }\n };\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent side=\"right\" title=\"Edit task\">\n <Stack gap={4} style={{ padding: 'var(--space-4)' }}>\n <Stack gap={2}>\n <label htmlFor=\"task-title\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Title\n </label>\n <Input\n id=\"task-title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n onBlur={saveTitle}\n disabled={busy !== null}\n />\n </Stack>\n\n <Stack gap={2}>\n <label htmlFor=\"task-status\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Status\n </label>\n <Select value={status} onValueChange={saveStatus}>\n <SelectTrigger id=\"task-status\" size=\"sm\" placeholder=\"Status\" />\n <SelectContent>\n {STATUS_OPTIONS.map((opt) => (\n <SelectItem key={opt.value} value={opt.value}>{opt.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Stack>\n\n <Inline gap={2}>\n <Stack gap={2} style={{ flex: 1 }}>\n <label htmlFor=\"task-priority\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Priority\n </label>\n <Select value={priority} onValueChange={savePriority}>\n <SelectTrigger id=\"task-priority\" size=\"sm\" placeholder=\"Priority\" />\n <SelectContent>\n {PRIORITY_OPTIONS.map((opt) => (\n <SelectItem key={opt.value} value={opt.value}>{opt.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Stack>\n <Stack gap={2} style={{ flex: 1 }}>\n <label htmlFor=\"task-due\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Due\n </label>\n <Input\n id=\"task-due\"\n type=\"date\"\n value={due ? due.slice(0, 10) : ''}\n onChange={(e) => setDue(e.target.value)}\n onBlur={saveDue}\n disabled={busy !== null}\n />\n </Stack>\n </Inline>\n\n <Inline gap={2}>\n <Stack gap={2} style={{ flex: 1 }}>\n <label htmlFor=\"task-assignee\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Assignee\n </label>\n <Input\n id=\"task-assignee\"\n value={assignee}\n onChange={(e) => setAssignee(e.target.value)}\n onBlur={saveAssignee}\n placeholder=\"agent name (blank = unassigned)\"\n disabled={busy !== null}\n />\n </Stack>\n <Stack gap={2} style={{ flex: 1 }}>\n <label htmlFor=\"task-branch\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Branch\n </label>\n <Input\n id=\"task-branch\"\n value={branch}\n onChange={(e) => setBranch(e.target.value)}\n onBlur={saveBranch}\n placeholder=\"feature/foo\"\n disabled={busy !== null}\n />\n </Stack>\n </Inline>\n\n <Stack gap={2}>\n <label htmlFor=\"task-description\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Description\n </label>\n <Textarea\n id=\"task-description\"\n rows={5}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n onBlur={saveDescription}\n disabled={busy !== null}\n placeholder=\"What's the work, why, how to verify…\"\n />\n </Stack>\n\n <Stack gap={2}>\n <label htmlFor=\"task-comment\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n Add comment\n </label>\n <Inline gap={2} align=\"start\">\n <Textarea\n id=\"task-comment\"\n rows={2}\n value={comment}\n onChange={(e) => setComment(e.target.value)}\n placeholder=\"Leave a progress note…\"\n disabled={busy !== null}\n style={{ flex: 1 }}\n />\n <Button variant=\"secondary\" onClick={() => { void addComment(); }} disabled={!comment.trim() || busy !== null}>\n <Plus size={14} aria-hidden /> Comment\n </Button>\n </Inline>\n </Stack>\n\n <Stack gap={2}>\n <div style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Metadata</div>\n <Inline gap={1} wrap>\n {task.metadata?.goalId !== undefined && typeof task.metadata.goalId === 'string' && (\n <Badge tone=\"info\" title={`Linked to goal ${String(task.metadata.goalId)}`}>\n goal: {String(task.metadata.goalId)}\n </Badge>\n )}\n {task.metadata?.krId !== undefined && typeof task.metadata.krId === 'string' && (\n <Badge tone=\"info\" title={`Linked to KR ${String(task.metadata.krId)}`}>\n kr: {String(task.metadata.krId)}\n </Badge>\n )}\n {task.id && <Badge tone=\"neutral\" title={task.id}>id: {task.id}</Badge>}\n </Inline>\n </Stack>\n\n <div style={{ borderTop: '1px solid var(--border)', paddingTop: 'var(--space-3)' }}>\n <Button variant=\"danger\" onClick={() => { void removeTask(); }} disabled={deleting || busy !== null}>\n <Trash2 size={14} aria-hidden /> {deleting ? 'Deleting…' : 'Delete task'}\n </Button>\n </div>\n\n {message !== null && (\n <div role=\"status\" style={{ fontSize: 'var(--fs-12)', color: 'var(--success)' }}>{message}</div>\n )}\n {error !== null && (\n <div role=\"alert\" style={{ fontSize: 'var(--fs-12)', color: 'var(--danger)' }}>{error}</div>\n )}\n {busy !== null && <Skeleton style={{ height: 12 }} />}\n </Stack>\n </SheetContent>\n </Sheet>\n );\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\nimport { Plus } from 'lucide-react';\nimport { Stack } from '../../ui/primitives/Stack.js';\nimport { Inline } from '../../ui/primitives/Inline.js';\nimport { ViewHeader } from '../../ui/data/ViewHeader.js';\nimport { KanbanBoard } from '../../ui/kanban/KanbanBoard.js';\nimport { KanbanColumn, type KanbanColumnData } from '../../ui/kanban/KanbanColumn.js';\nimport { KanbanCard, useKanbanCardSortable, type KanbanCardData } from '../../ui/kanban/KanbanCard.js';\nimport { KanbanToolbar, useKanbanSelection, type KanbanFilter } from '../../ui/index.js';\nimport { Skeleton } from '../../ui/feedback/Skeleton.js';\nimport { TaskDetail } from '../../ui/tasks/TaskDetail.js';\nimport { Sheet, SheetContent } from '../../ui/feedback/Sheet.js';\nimport { Input } from '../../ui/controls/Input.js';\nimport { Textarea } from '../../ui/controls/Textarea.js';\nimport { Button } from '../../ui/controls/Button.js';\nimport { useFetch } from '../../data/useFetch.js';\nimport { useWsMessage } from '../../data/useWebSocket.js';\nimport { fetchJson, FetchError } from '../../data/fetcher.js';\nimport type { Task, WsMessage } from '../../data/types.js';\n\ntype TaskStatus = NonNullable<Task['status']>;\n\n/**\n * TasksView — Sprint S10. Pulls `/api/tasks` and maps server statuses\n * to v8 kanban columns. Drag a card between columns → PATCH\n * /api/tasks/:id/status. Live updates via `tasks:change`.\n *\n * v10.0.6 — adds KanbanToolbar (search + priority filter chips +\n * bulk-actions row), useKanbanSelection hook (Esc-to-clear), and a\n * 6th \"Backlog\" column from PR #14.\n */\n\nconst COLUMNS: KanbanColumnData[] = [\n { id: 'backlog', title: 'Backlog', accentTone: 'neutral' },\n { id: 'queued', title: 'Queued', accentTone: 'info' },\n { id: 'doing', title: 'In progress', accentTone: 'accent', wipLimit: 5 },\n { id: 'blocked', title: 'In review', accentTone: 'warning' },\n { id: 'done', title: 'Done', accentTone: 'success' },\n { id: 'archived', title: 'Archived', accentTone: 'neutral' },\n];\n\nconst PRIORITY_MAP: Record<string, KanbanCardData['priority']> = {\n low: 'low',\n medium: 'medium',\n high: 'high',\n urgent: 'urgent',\n};\n\ninterface Card extends KanbanCardData {\n taskId: string;\n columnId: TaskStatus;\n}\n\nfunction taskToCard(t: Task): Card {\n return {\n id: t.id,\n taskId: t.id,\n columnId: statusToColumn(t.status),\n title: t.title,\n priority: PRIORITY_MAP[t.priority || 'medium'] || 'medium',\n branch: t.branch,\n due: t.due,\n comments: t.comments,\n attachments: t.attachments,\n };\n}\n\nfunction statusToColumn(status?: TaskStatus): TaskStatus {\n switch (status) {\n case 'backlog':\n case 'queued':\n case 'doing':\n case 'blocked':\n case 'done':\n case 'archived':\n return status;\n default:\n return 'backlog';\n }\n}\n\n/**\n * SortableCard — wraps a single KanbanCard with dnd-kit's useSortable\n * so KanbanBoard.onDragEnd can fire.\n */\nfunction SortableCard({ card }: { card: Card }): JSX.Element {\n const sortable = useKanbanCardSortable(card.id);\n return (\n <KanbanCard\n card={card}\n isDragging={sortable.isDragging}\n dragHandleProps={{ ...sortable.attributes, ...sortable.listeners, ref: sortable.setNodeRef, style: sortable.style }}\n />\n );\n}\n\nexport function TasksView(): JSX.Element {\n const tasks = useFetch<{ tasks?: Task[]; count?: number }>('/api/tasks');\n const [cards, setCards] = useState<Card[]>([]);\n const [error, setError] = useState<string | null>(null);\n const [openTaskId, setOpenTaskId] = useState<string | null>(null);\n const selection = useKanbanSelection();\n const [query, setQuery] = useState<string>('');\n const [activeFilters, setActiveFilters] = useState<ReadonlySet<string>>(new Set());\n const [createDraft, setCreateDraft] = useState<{ title: string; description: string; priority: 'low' | 'medium' | 'high' | 'urgent' } | null>(null);\n const [creating, setCreating] = useState(false);\n\n const saveCreate = async (): Promise<void> => {\n if (createDraft === null || !createDraft.title.trim()) return;\n setCreating(true);\n try {\n await fetchJson('/api/tasks', { method: 'POST', body: { title: createDraft.title.trim(), description: createDraft.description, priority: createDraft.priority, status: 'queued' } });\n setCreateDraft(null);\n tasks.refetch();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n } finally {\n setCreating(false);\n }\n };\n\n const onWsRemove = useCallback((msg: WsMessage) => {\n const m = msg as { type?: string; id?: string };\n if (m.type !== 'tasks:removed' && m.type !== 'task:removed') return;\n if (!m.id) return;\n setCards((prev) => prev.filter((c) => c.taskId !== m.id));\n selection.remove([m.id]);\n if (openTaskId === m.id) setOpenTaskId(null);\n }, [openTaskId, selection]);\n useWsMessage('tasks:removed', onWsRemove);\n useWsMessage('task:removed', onWsRemove);\n\n const toggleSelect = (taskId: string): void => {\n selection.toggle(taskId);\n };\n\n const bulkMove = async (toStatus: TaskStatus): Promise<void> => {\n const ids = Array.from(selection.selected);\n if (ids.length === 0) return;\n setCards((prev) => prev.map((c) => (selection.has(c.taskId) ? { ...c, columnId: toStatus } : c)));\n try {\n await fetchJson('/api/tasks/bulk-status', {\n method: 'PATCH',\n body: { ids, status: toStatus },\n });\n selection.clear();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n }\n };\n\n // Sync fetched list → local state. Effect-driven so we don't setState\n // during render (which React warns about under StrictMode and which\n // can double-render the cards).\n useEffect(() => {\n if (tasks.data?.tasks) {\n setCards(tasks.data.tasks.map(taskToCard));\n }\n }, [tasks.data]);\n\n const onWsChange = useCallback((msg: WsMessage) => {\n if (msg.type !== 'tasks:change') return;\n const t = msg.task as Task | undefined;\n if (!t) return;\n setCards((prev) => {\n const idx = prev.findIndex((c) => c.taskId === t.id);\n const card = taskToCard({ ...t, status: statusToColumn(t.status) });\n if (idx === -1) return [...prev, card];\n const copy = prev.slice();\n copy[idx] = { ...copy[idx], ...card };\n return copy;\n });\n }, []);\n useWsMessage('tasks:change', onWsChange);\n\n const onCardMove = useCallback(async (cardId: string, _from: string, to: string) => {\n const card = cards.find((c) => c.taskId === cardId || c.id === cardId);\n if (!card) return;\n const nextStatus = statusToColumn(to as TaskStatus);\n setCards((prev) =>\n prev.map((c) => (c.taskId === cardId ? { ...c, columnId: nextStatus } : c)),\n );\n try {\n await fetchJson(`/api/tasks/${encodeURIComponent(card.taskId)}/status`, {\n method: 'PATCH',\n body: { status: nextStatus },\n });\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n // Roll back on failure.\n setCards((prev) =>\n prev.map((c) => (c.taskId === cardId ? { ...c, columnId: card.columnId } : c)),\n );\n }\n }, [cards]);\n\n const counts: Record<string, number> = {};\n for (const c of cards) counts[c.columnId] = (counts[c.columnId] || 0) + 1;\n\n const openTask = openTaskId ? tasks.data?.tasks?.find((t) => t.id === openTaskId) ?? null : null;\n const selectedCount = selection.selected.size;\n\n // ── v10.0.6 — search + filter chips (PR #14 toolbar wiring) ──\n const filteredCards = useMemo<Card[]>(() => {\n const q = query.trim().toLowerCase();\n return cards.filter((c) => {\n if (activeFilters.size > 0) {\n if (activeFilters.has(`status:${c.columnId}`) === false) {\n const hasPriority = c.priority !== undefined && activeFilters.has(`priority:${c.priority}`);\n const hasStatus = activeFilters.has(`status:${c.columnId}`);\n if (!hasPriority && !hasStatus) return false;\n }\n }\n if (q !== '') {\n const hay = `${c.title} ${c.description ?? ''}`.toLowerCase();\n if (hay.includes(q) === false) return false;\n }\n return true;\n });\n }, [cards, query, activeFilters]);\n\n const priorityFilters: KanbanFilter[] = [\n { id: 'priority:low', label: 'Low', tone: 'neutral' },\n { id: 'priority:medium', label: 'Medium', tone: 'info' },\n { id: 'priority:high', label: 'High', tone: 'warning' },\n { id: 'priority:urgent', label: 'Urgent', tone: 'danger' },\n ];\n const statusFilters: KanbanFilter[] = COLUMNS.map((c) => ({ id: `status:${c.id}`, label: c.title as string }));\n const allFilters: KanbanFilter[] = [...priorityFilters, ...statusFilters];\n\n const onFilterToggle = useCallback((id: string) => {\n setActiveFilters((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n }, []);\n const onClearFilters = useCallback(() => setActiveFilters(new Set()), []);\n\n return (\n <Stack gap={4} data-testid=\"tasks-view\">\n <ViewHeader\n title=\"Tasks\"\n description=\"Drag cards across columns. Click a card to edit. Use the checkbox to select multiple.\"\n actions={\n <Inline gap={2} align=\"center\">\n {error !== null && <span role=\"alert\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>{error}</span>}\n <Button variant=\"primary\" onClick={() => setCreateDraft({ title: '', description: '', priority: 'medium' })} data-testid=\"task-create-open\">\n <Plus size={14} aria-hidden /> New task\n </Button>\n </Inline>\n }\n />\n {selectedCount > 0 && (\n <KanbanToolbar\n totalCount={cards.length}\n visibleCount={filteredCards.length}\n selectedCount={selectedCount}\n query={query}\n onQueryChange={setQuery}\n filters={allFilters}\n onFilterToggle={onFilterToggle}\n onClearFilters={onClearFilters}\n onNewTask={() => setCreateDraft({ title: '', description: '', priority: 'medium' })}\n onBulkMove={() => void bulkMove('doing')}\n onBulkArchive={() => void bulkMove('archived')}\n onBulkDelete={async () => {\n const ids = Array.from(selection.selected);\n if (ids.length === 0) return;\n if (!window.confirm(`Delete ${ids.length} task${ids.length === 1 ? '' : 's'}? This cannot be undone.`)) return;\n try {\n await fetchJson('/api/tasks/bulk-status', { method: 'PATCH', body: { ids, status: 'archived' } });\n selection.clear();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n }\n }}\n onClearSelection={() => selection.clear()}\n />\n )}\n {tasks.loading && cards.length === 0 ? (\n <Stack gap={3}>\n <Skeleton style={{ height: 120 }} />\n <Skeleton style={{ height: 120 }} />\n </Stack>\n ) : (\n <KanbanBoard columns={COLUMNS} onCardMove={onCardMove}>\n {COLUMNS.map((col) => {\n const inColumn = filteredCards.filter((c) => c.columnId === col.id);\n return (\n <KanbanColumn\n key={col.id}\n column={{ ...col, count: counts[col.id] || 0 }}\n >\n {inColumn.map((card) => (\n <div key={card.id} style={{ position: 'relative' }}>\n <input\n type=\"checkbox\"\n checked={selection.has(card.taskId)}\n onChange={() => toggleSelect(card.taskId)}\n onClick={(e) => e.stopPropagation()}\n aria-label={`Select ${card.title}`}\n style={{ position: 'absolute', top: 8, left: 8, zIndex: 2 }}\n />\n <div onClick={() => setOpenTaskId(card.taskId)} role=\"button\" tabIndex={0} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setOpenTaskId(card.taskId); } }} style={{ cursor: 'pointer' }}>\n <SortableCard card={card} />\n </div>\n </div>\n ))}\n </KanbanColumn>\n );\n })}\n </KanbanBoard>\n )}\n {openTask && (\n <TaskDetail\n task={openTask}\n open={openTaskId !== null}\n onOpenChange={(o) => { if (!o) setOpenTaskId(null); }}\n onDeleted={() => {\n setCards((prev) => prev.filter((c) => c.taskId !== openTask.id));\n setOpenTaskId(null);\n }}\n />\n )}\n\n {/* v9.2.0 — create-task Sheet. Replaces the missing \"new task\"\n action that the audit flagged as a HIGH gap. */}\n <Sheet open={createDraft !== null} onOpenChange={(o) => { if (!o) setCreateDraft(null); }}>\n <SheetContent side=\"right\" title=\"New task\">\n {createDraft !== null && (\n <Stack gap={4} style={{ padding: 'var(--space-4)' }}>\n <Stack gap={2}>\n <label htmlFor=\"task-create-title\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Title</label>\n <Input\n id=\"task-create-title\"\n value={createDraft.title}\n onChange={(e) => setCreateDraft({ ...createDraft, title: e.target.value })}\n placeholder=\"What needs doing?\"\n disabled={creating}\n data-testid=\"task-create-title\"\n />\n </Stack>\n <Stack gap={2}>\n <label htmlFor=\"task-create-desc\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Description (optional)</label>\n <Textarea\n id=\"task-create-desc\"\n value={createDraft.description}\n onChange={(e) => setCreateDraft({ ...createDraft, description: e.target.value })}\n rows={4}\n disabled={creating}\n data-testid=\"task-create-desc\"\n />\n </Stack>\n <Stack gap={2}>\n <label htmlFor=\"task-create-priority\" style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Priority</label>\n <select\n id=\"task-create-priority\"\n value={createDraft.priority}\n onChange={(e) => setCreateDraft({ ...createDraft, priority: e.target.value as typeof createDraft.priority })}\n disabled={creating}\n data-testid=\"task-create-priority\"\n style={{ height: 32, padding: '0 var(--space-2)', borderRadius: 'var(--radius-sm)', border: '1px solid var(--border)', background: 'var(--surface-0)', color: 'var(--fg)', fontSize: 'var(--fs-13)' }}\n >\n <option value=\"low\">Low</option>\n <option value=\"medium\">Medium</option>\n <option value=\"high\">High</option>\n <option value=\"urgent\">Urgent</option>\n </select>\n </Stack>\n <Inline gap={2}>\n <Button variant=\"primary\" onClick={() => { void saveCreate(); }} disabled={creating || !createDraft.title.trim()} data-testid=\"task-create-submit\">\n Create task\n </Button>\n <Button variant=\"ghost\" onClick={() => setCreateDraft(null)} disabled={creating}>\n Cancel\n </Button>\n </Inline>\n </Stack>\n )}\n </SheetContent>\n </Sheet>\n </Stack>\n );\n}"],"names":["ArrowRight","createLucideIcon","KanbanToolbar","props","totalCount","visibleCount","selectedCount","query","onQueryChange","filters","onFilterToggle","onClearFilters","onNewTask","onBulkMove","onBulkArchive","onBulkDelete","onClearSelection","className","searchFocused","setSearchFocused","useState","isBulk","jsx","cx","jsxs","Fragment","Button","Archive","Trash2","IconButton","X","Search","e","Filter","f","tone","isActive","actualId","active","Plus","useKanbanSelection","selected","setSelected","toggle","useCallback","id","prev","next","add","ids","remove","set","clear","useEffect","onKey","ev","target","tag","has","useMemo","PRIORITY_OPTIONS","STATUS_OPTIONS","TaskDetail","task","open","onOpenChange","onDeleted","title","setTitle","description","setDescription","priority","setPriority","status","setStatus","assignee","setAssignee","due","setDue","branch","setBranch","comment","setComment","busy","setBusy","message","setMessage","error","setError","deleting","setDeleting","patch","body","label","fetchJson","err","saveTitle","saveDescription","savePriority","v","saveStatus","saveAssignee","saveDue","saveBranch","addComment","removeTask","Sheet","SheetContent","Stack","Input","Select","SelectTrigger","SelectContent","opt","SelectItem","Inline","Textarea","_a","Badge","_b","Skeleton","COLUMNS","PRIORITY_MAP","taskToCard","t","statusToColumn","SortableCard","card","sortable","useKanbanCardSortable","KanbanCard","TasksView","tasks","useFetch","cards","setCards","openTaskId","setOpenTaskId","selection","setQuery","activeFilters","setActiveFilters","createDraft","setCreateDraft","creating","setCreating","saveCreate","FetchError","onWsRemove","msg","m","useWsMessage","toggleSelect","taskId","bulkMove","toStatus","onWsChange","idx","c","copy","onCardMove","cardId","_from","to","nextStatus","counts","openTask","filteredCards","q","hasPriority","hasStatus","priorityFilters","statusFilters","allFilters","ViewHeader","KanbanBoard","col","inColumn","KanbanColumn","o"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as g,j as p}from"./cmdk-DVxytz9i.js";import{g as x}from"./main-
|
|
1
|
+
import{r as g,j as p}from"./cmdk-DVxytz9i.js";import{g as x}from"./main-CyAIirBB.js";const b=g.forwardRef(function(s,n){const{invalid:t,autoResize:a,disabled:i,rows:l=4,className:d,style:u,onInput:r,...c}=s,v={width:"100%",minHeight:64,padding:"var(--space-3)",fontSize:"var(--fs-13)",lineHeight:"var(--lh-base)",color:"var(--fg)",background:"var(--input-bg)",border:"1px solid",borderColor:t===!0?"var(--danger)":"var(--border)",borderRadius:"var(--radius-sm)",outline:0,resize:a===!0?"none":"vertical",opacity:i===!0?.55:1,fontFamily:"inherit",...u};return p.jsx("textarea",{ref:n,rows:l,disabled:i,"aria-invalid":t===!0?"true":void 0,className:x("v8-textarea",d),style:v,onInput:o=>{if(a===!0){const e=o.currentTarget;e.style.height="auto",e.style.height=`${e.scrollHeight}px`}r==null||r(o)},...c})});export{b as T};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Textarea-
|
|
1
|
+
{"version":3,"file":"Textarea-D_TPpVMy.js","sources":["../../src/web/v8/ui/controls/Textarea.tsx"],"sourcesContent":["import { forwardRef, type TextareaHTMLAttributes } from 'react';\nimport { cx } from '../utils/cx.js';\n\n/**\n * Textarea — multi-line input.\n *\n * Use for: descriptions, comments, chat input.\n * Pair with <Field> for label + hint + error.\n */\nexport interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {\n invalid?: boolean;\n autoResize?: boolean;\n}\n\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(function Textarea(props, ref) {\n const {\n invalid,\n autoResize,\n disabled,\n rows = 4,\n className,\n style,\n onInput,\n ...rest\n } = props;\n\n const computedStyle = {\n width: '100%',\n minHeight: 64,\n padding: 'var(--space-3)',\n fontSize: 'var(--fs-13)',\n lineHeight: 'var(--lh-base)',\n color: 'var(--fg)',\n background: 'var(--input-bg)',\n border: '1px solid',\n borderColor: invalid === true ? 'var(--danger)' : 'var(--border)',\n borderRadius: 'var(--radius-sm)',\n outline: 0,\n resize: autoResize === true ? 'none' : 'vertical',\n opacity: disabled === true ? 0.55 : 1,\n fontFamily: 'inherit',\n ...style,\n } as const;\n\n return (\n <textarea\n ref={ref}\n rows={rows}\n disabled={disabled}\n aria-invalid={invalid === true ? 'true' : undefined}\n className={cx('v8-textarea', className)}\n style={computedStyle}\n onInput={(e) => {\n if (autoResize === true) {\n const el = e.currentTarget;\n el.style.height = 'auto';\n el.style.height = `${el.scrollHeight}px`;\n }\n onInput?.(e);\n }}\n {...rest}\n />\n );\n});"],"names":["Textarea","forwardRef","props","ref","invalid","autoResize","disabled","rows","className","style","onInput","rest","computedStyle","jsx","cx","e","el"],"mappings":"qFAcO,MAAMA,EAAWC,EAAAA,WAA+C,SAAkBC,EAAOC,EAAK,CACnG,KAAM,CACJ,QAAAC,EACA,WAAAC,EACA,SAAAC,EACA,KAAAC,EAAO,EACP,UAAAC,EACA,MAAAC,EACA,QAAAC,EACA,GAAGC,CAAA,EACDT,EAEEU,EAAgB,CACpB,MAAO,OACP,UAAW,GACX,QAAS,iBACT,SAAU,eACV,WAAY,iBACZ,MAAO,YACP,WAAY,kBACZ,OAAQ,YACR,YAAaR,IAAY,GAAO,gBAAkB,gBAClD,aAAc,mBACd,QAAS,EACT,OAAQC,IAAe,GAAO,OAAS,WACvC,QAASC,IAAa,GAAO,IAAO,EACpC,WAAY,UACZ,GAAGG,CAAA,EAGL,OACEI,EAAAA,IAAC,WAAA,CACC,IAAAV,EACA,KAAAI,EACA,SAAAD,EACA,eAAcF,IAAY,GAAO,OAAS,OAC1C,UAAWU,EAAG,cAAeN,CAAS,EACtC,MAAOI,EACP,QAAUG,GAAM,CACd,GAAIV,IAAe,GAAM,CACvB,MAAMW,EAAKD,EAAE,cACbC,EAAG,MAAM,OAAS,OAClBA,EAAG,MAAM,OAAS,GAAGA,EAAG,YAAY,IACtC,CACAN,GAAA,MAAAA,EAAUK,EACZ,EACC,GAAGJ,CAAA,CAAA,CAGV,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r,j as e}from"./cmdk-DVxytz9i.js";import{c as V,u as B,a as g,S as c,I as t,d as i,h as f,J as F,i as w,F as A}from"./main-
|
|
1
|
+
import{r,j as e}from"./cmdk-DVxytz9i.js";import{c as V,u as B,a as g,S as c,I as t,d as i,h as f,J as F,i as w,F as A}from"./main-CyAIirBB.js";import{V as I}from"./ViewHeader-V_SzbUpw.js";import{C as x,b as j}from"./Card-D9019JOD.js";import{E as M}from"./EmptyState-DLmtBX_6.js";import{R as T}from"./refresh-ccw-BCXx86xp.js";import{D as $}from"./download-CW4DmtRe.js";import{C as D}from"./circle-check-COtVgsWw.js";import{C as H}from"./circle-alert-CQ9MLygI.js";/**
|
|
2
2
|
* @license lucide-react v0.460.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UpdateView-CSmX9NN0.js","sources":["../../../node_modules/lucide-react/dist/esm/icons/package.js","../../src/web/v8/views/Update/UpdateView.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.460.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Package = createLucideIcon(\"Package\", [\n [\n \"path\",\n {\n d: \"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z\",\n key: \"1a0edw\"\n }\n ],\n [\"path\", { d: \"M12 22V12\", key: \"d0xqtd\" }],\n [\"path\", { d: \"m3.3 7 7.703 4.734a2 2 0 0 0 1.994 0L20.7 7\", key: \"yx3hmr\" }],\n [\"path\", { d: \"m7.5 4.27 9 5.15\", key: \"1c824w\" }]\n]);\n\nexport { Package as default };\n//# sourceMappingURL=package.js.map\n","/**\n * v8/views/Update/UpdateView.tsx — Sprint S42, v9.3.0.\n *\n * Package update status + Check + Apply:\n * - GET /api/updates/status — installed versions\n * - GET /api/updates/check — installed + latest + hasUpdates\n * - POST /api/updates/apply — kick install, streams via\n * `update:progress` / `update:log` / `update:complete` WS events.\n *\n * Per-package Apply (inline-confirm) + global Apply All button. Live\n * progress list rendered from a useWsMessage subscription.\n */\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { Package, RefreshCcw, Download, CheckCircle2, AlertCircle, Loader2 } from 'lucide-react';\nimport { Stack } from '../../ui/primitives/Stack.js';\nimport { Inline } from '../../ui/primitives/Inline.js';\nimport { ViewHeader } from '../../ui/data/ViewHeader.js';\nimport { Card, CardBody } from '../../ui/data/Card.js';\nimport { Button } from '../../ui/controls/Button.js';\nimport { Skeleton } from '../../ui/feedback/Skeleton.js';\nimport { EmptyState } from '../../ui/feedback/EmptyState.js';\nimport { useFetch } from '../../data/useFetch.js';\nimport { useWsMessage } from '../../data/useWebSocket.js';\nimport { fetchJson, FetchError } from '../../data/fetcher.js';\n\ninterface UpdateEntry {\n id: string;\n installed?: string;\n latest?: string | null;\n hasUpdate?: boolean;\n label?: string;\n}\n\ninterface StatusResponse {\n packages: UpdateEntry[];\n}\n\ninterface CheckResponse {\n packages: UpdateEntry[];\n hasUpdates?: boolean;\n}\n\ninterface ProgressEvent {\n type: 'update:progress' | 'update:log' | 'update:complete';\n pkg?: string;\n status?: string;\n line?: string;\n newVersion?: string;\n error?: string;\n}\n\nexport function UpdateView(): JSX.Element {\n const statusPayload = useFetch<StatusResponse>('/api/updates/status');\n const [check, setCheck] = useState<CheckResponse | null>(null);\n const [checking, setChecking] = useState<boolean>(false);\n const [applying, setApplying] = useState<boolean>(false);\n const [confirmApply, setConfirmApply] = useState<string | null>(null);\n const [log, setLog] = useState<ProgressEvent[]>([]);\n const [error, setError] = useState<string | null>(null);\n\n const installed = useMemo<UpdateEntry[]>(() => statusPayload.data?.packages ?? [], [statusPayload.data]);\n const refresh = useCallback(() => { void statusPayload.refetch(); }, [statusPayload]);\n\n // Subscribe to live progress events. `msg.type` is the discriminator\n // (e.g. 'update:progress'); spreading first then narrowing via the\n // cast avoids the TS2783 duplicate-key error we'd hit if we tried to\n // also set `type: 'update:progress'` literally.\n useWsMessage('update:progress', (msg) => {\n setLog((l) => [...l, { ...msg, type: 'update:progress' } as ProgressEvent]);\n });\n useWsMessage('update:log', (msg) => {\n setLog((l) => [...l, { ...msg, type: 'update:log' } as ProgressEvent]);\n });\n useWsMessage('update:complete', (msg) => {\n setLog((l) => [...l, { ...msg, type: 'update:complete' } as ProgressEvent]);\n setApplying(false);\n refresh();\n });\n\n const runCheck = async (): Promise<void> => {\n setChecking(true);\n setError(null);\n try {\n const r = await fetchJson<CheckResponse>('/api/updates/check');\n setCheck(r);\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n } finally {\n setChecking(false);\n }\n };\n\n const apply = async (ids: string[]): Promise<void> => {\n setApplying(true);\n setError(null);\n setConfirmApply(null);\n try {\n await fetchJson('/api/updates/apply', { method: 'POST', body: { packages: ids } });\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n setApplying(false);\n }\n };\n\n const rows: UpdateEntry[] = check?.packages ?? installed.map((p) => ({ ...p, hasUpdate: false }));\n\n return (\n <Stack gap={4} data-testid=\"update-view\">\n <ViewHeader\n title=\"Update\"\n description=\"Bizar package updates. Apply restarts on next launch.\"\n actions={\n <Inline align=\"center\" gap={2}>\n {error !== null && (\n <span role=\"alert\" data-testid=\"update-error\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>\n {error}\n </span>\n )}\n <Button variant=\"ghost\" onClick={() => void refresh()} data-testid=\"update-refresh\">\n <RefreshCcw size={14} aria-hidden /> Refresh\n </Button>\n <Button variant=\"ghost\" onClick={() => void runCheck()} disabled={checking} data-testid=\"update-check\">\n <Download size={14} aria-hidden /> {checking ? 'Checking…' : 'Check'}\n </Button>\n <Button\n variant=\"primary\"\n onClick={() => setConfirmApply('all')}\n disabled={applying || !(check?.hasUpdates ?? false)}\n data-testid=\"update-apply-all\"\n >\n <Package size={14} aria-hidden /> Apply all\n </Button>\n </Inline>\n }\n />\n\n <Card variant=\"default\">\n <CardBody>\n {statusPayload.loading && rows.length === 0 ? (\n <Stack gap={1}>\n <Skeleton style={{ height: 40 }} />\n <Skeleton style={{ height: 40 }} />\n <Skeleton style={{ height: 40 }} />\n </Stack>\n ) : rows.length === 0 ? (\n <EmptyState icon={<Package size={28} aria-hidden />} title=\"No packages\" description=\"Update status endpoint returned no packages.\" />\n ) : (\n <Stack gap={1}>\n {rows.map((p) => {\n const isConfirming = confirmApply === p.id;\n return (\n <div\n key={p.id}\n data-testid={`update-row-${p.id}`}\n style={{\n padding: 'var(--space-2)',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-sm)',\n background: 'var(--surface-0)',\n }}\n >\n <Inline align=\"center\" justify=\"between\" gap={2}>\n <Stack gap={0}>\n <Inline align=\"center\" gap={2}>\n <strong>{p.label || p.id}</strong>\n <code style={{ fontSize: 'var(--fs-11)', color: 'var(--fg-subtle)' }}>{p.id}</code>\n </Inline>\n <Inline align=\"center\" gap={2}>\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n installed: <code>{p.installed ?? '?'}</code>\n </span>\n {p.latest !== undefined && p.latest !== null && (\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n latest: <code>{p.latest}</code>\n </span>\n )}\n {p.hasUpdate && (\n <span data-testid={`update-available-${p.id}`} style={{ fontSize: 'var(--fs-11)', color: 'var(--accent)', fontWeight: 600 }}>\n UPDATE AVAILABLE\n </span>\n )}\n </Inline>\n </Stack>\n <Inline gap={1}>\n {p.hasUpdate && (\n <Button\n variant=\"ghost\"\n onClick={() => setConfirmApply((cur) => (cur === p.id ? null : p.id))}\n data-testid={`update-apply-${p.id}`}\n disabled={applying}\n >\n Apply\n </Button>\n )}\n </Inline>\n </Inline>\n {isConfirming && (\n <Inline gap={1} style={{ marginTop: 'var(--space-1)' }}>\n <Button variant=\"primary\" onClick={() => void apply([p.id])} data-testid={`update-confirm-apply-${p.id}`}>\n Confirm apply\n </Button>\n <Button variant=\"ghost\" onClick={() => setConfirmApply(null)}>Cancel</Button>\n </Inline>\n )}\n </div>\n );\n })}\n </Stack>\n )}\n </CardBody>\n </Card>\n\n {confirmApply === 'all' && (\n <Card variant=\"default\">\n <CardBody>\n <Stack gap={2}>\n <strong>Apply all updates?</strong>\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n {rows.filter((p) => p.hasUpdate).length} package(s) will update on next launch.\n </span>\n <Inline gap={1}>\n <Button variant=\"primary\" onClick={() => void apply(rows.filter((p) => p.hasUpdate).map((p) => p.id))} data-testid=\"update-confirm-apply-all\">\n Confirm apply all\n </Button>\n <Button variant=\"ghost\" onClick={() => setConfirmApply(null)}>Cancel</Button>\n </Inline>\n </Stack>\n </CardBody>\n </Card>\n )}\n\n {log.length > 0 && (\n <Card variant=\"default\">\n <CardBody>\n <strong style={{ fontSize: 'var(--fs-13)' }}>Progress</strong>\n <div\n data-testid=\"update-log\"\n style={{\n marginTop: 'var(--space-2)',\n padding: 'var(--space-2)',\n background: 'var(--surface-1)',\n borderRadius: 'var(--radius-sm)',\n fontFamily: 'var(--font-mono)',\n fontSize: 'var(--fs-12)',\n maxHeight: 240,\n overflow: 'auto',\n }}\n >\n {log.slice(-100).map((l, i) => (\n <div key={i} style={{ color: l.error ? 'var(--danger)' : l.status === 'done' ? 'var(--success)' : 'var(--fg)' }}>\n {l.type === 'update:complete' ? (\n <Inline align=\"center\" gap={1}><CheckCircle2 size={12} aria-hidden style={{ color: 'var(--success)' }} /> complete</Inline>\n ) : l.error ? (\n <Inline align=\"center\" gap={1}><AlertCircle size={12} aria-hidden style={{ color: 'var(--danger)' }} /> {l.pkg ?? '?'} · {l.error}</Inline>\n ) : (\n <Inline align=\"center\" gap={1}>\n {l.status === 'installing' ? <Loader2 size={12} aria-hidden style={{ animation: 'spin 1s linear infinite' }} /> : null}\n {l.pkg ?? '?'} · {l.status ?? l.line ?? ''}\n </Inline>\n )}\n </div>\n ))}\n </div>\n </CardBody>\n </Card>\n )}\n </Stack>\n );\n}"],"names":["Package","createLucideIcon","UpdateView","statusPayload","useFetch","check","setCheck","useState","checking","setChecking","applying","setApplying","confirmApply","setConfirmApply","log","setLog","error","setError","installed","useMemo","_a","refresh","useCallback","useWsMessage","msg","l","runCheck","r","fetchJson","err","FetchError","apply","ids","rows","p","jsxs","Stack","jsx","ViewHeader","Inline","Button","RefreshCcw","Download","Card","CardBody","Skeleton","EmptyState","isConfirming","cur","i","CheckCircle2","AlertCircle","Loader2"],"mappings":"8cAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASA,MAAMA,EAAUC,EAAiB,UAAW,CAC1C,CACE,OACA,CACE,EAAG,2HACH,IAAK,QACX,CACA,EACE,CAAC,OAAQ,CAAE,EAAG,YAAa,IAAK,QAAQ,CAAE,EAC1C,CAAC,OAAQ,CAAE,EAAG,8CAA+C,IAAK,QAAQ,CAAE,EAC5E,CAAC,OAAQ,CAAE,EAAG,mBAAoB,IAAK,QAAQ,CAAE,CACnD,CAAC,ECgCM,SAASC,GAA0B,CACxC,MAAMC,EAAgBC,EAAyB,qBAAqB,EAC9D,CAACC,EAAOC,CAAQ,EAAIC,EAAAA,SAA+B,IAAI,EACvD,CAACC,EAAUC,CAAW,EAAIF,EAAAA,SAAkB,EAAK,EACjD,CAACG,EAAUC,CAAW,EAAIJ,EAAAA,SAAkB,EAAK,EACjD,CAACK,EAAcC,CAAe,EAAIN,EAAAA,SAAwB,IAAI,EAC9D,CAACO,EAAKC,CAAM,EAAIR,EAAAA,SAA0B,CAAA,CAAE,EAC5C,CAACS,EAAOC,CAAQ,EAAIV,EAAAA,SAAwB,IAAI,EAEhDW,EAAYC,UAAuB,IAAA,OAAM,QAAAC,EAAAjB,EAAc,OAAd,YAAAiB,EAAoB,WAAY,IAAI,CAACjB,EAAc,IAAI,CAAC,EACjGkB,EAAUC,EAAAA,YAAY,IAAM,CAAOnB,EAAc,QAAA,CAAW,EAAG,CAACA,CAAa,CAAC,EAMpFoB,EAAa,kBAAoBC,GAAQ,CACvCT,EAAQU,GAAM,CAAC,GAAGA,EAAG,CAAE,GAAGD,EAAK,KAAM,iBAAA,CAAoC,CAAC,CAC5E,CAAC,EACDD,EAAa,aAAeC,GAAQ,CAClCT,EAAQU,GAAM,CAAC,GAAGA,EAAG,CAAE,GAAGD,EAAK,KAAM,YAAA,CAA+B,CAAC,CACvE,CAAC,EACDD,EAAa,kBAAoBC,GAAQ,CACvCT,EAAQU,GAAM,CAAC,GAAGA,EAAG,CAAE,GAAGD,EAAK,KAAM,iBAAA,CAAoC,CAAC,EAC1Eb,EAAY,EAAK,EACjBU,EAAA,CACF,CAAC,EAED,MAAMK,EAAW,SAA2B,CAC1CjB,EAAY,EAAI,EAChBQ,EAAS,IAAI,EACb,GAAI,CACF,MAAMU,EAAI,MAAMC,EAAyB,oBAAoB,EAC7DtB,EAASqB,CAAC,CACZ,OAASE,EAAK,CACZZ,GAASY,aAAeC,EAAaD,EAAI,QAAgC,CAC3E,QAAA,CACEpB,EAAY,EAAK,CACnB,CACF,EAEMsB,EAAQ,MAAOC,GAAiC,CACpDrB,EAAY,EAAI,EAChBM,EAAS,IAAI,EACbJ,EAAgB,IAAI,EACpB,GAAI,CACF,MAAMe,EAAU,qBAAsB,CAAE,OAAQ,OAAQ,KAAM,CAAE,SAAUI,CAAA,EAAO,CACnF,OAASH,EAAK,CACZZ,GAASY,aAAeC,EAAaD,EAAI,QAAgC,EACzElB,EAAY,EAAK,CACnB,CACF,EAEMsB,GAAsB5B,GAAA,YAAAA,EAAO,WAAYa,EAAU,IAAKgB,IAAO,CAAE,GAAGA,EAAG,UAAW,EAAA,EAAQ,EAEhG,OACEC,EAAAA,KAACC,EAAA,CAAM,IAAK,EAAG,cAAY,cACzB,SAAA,CAAAC,EAAAA,IAACC,EAAA,CACC,MAAM,SACN,YAAY,wDACZ,QACEH,EAAAA,KAACI,EAAA,CAAO,MAAM,SAAS,IAAK,EACzB,SAAA,CAAAvB,IAAU,MACTqB,MAAC,OAAA,CAAK,KAAK,QAAQ,cAAY,eAAe,MAAO,CAAE,MAAO,gBAAiB,SAAU,gBACtF,SAAArB,EACH,EAEFmB,EAAAA,KAACK,EAAA,CAAO,QAAQ,QAAQ,QAAS,IAAM,KAAKnB,EAAA,EAAW,cAAY,iBACjE,SAAA,CAAAgB,EAAAA,IAACI,EAAA,CAAW,KAAM,GAAI,cAAW,GAAC,EAAE,UAAA,EACtC,EACAN,EAAAA,KAACK,EAAA,CAAO,QAAQ,QAAQ,QAAS,IAAM,KAAKd,EAAA,EAAY,SAAUlB,EAAU,cAAY,eACtF,SAAA,CAAA6B,EAAAA,IAACK,EAAA,CAAS,KAAM,GAAI,cAAW,GAAC,EAAE,IAAElC,EAAW,YAAc,OAAA,EAC/D,EACA2B,EAAAA,KAACK,EAAA,CACC,QAAQ,UACR,QAAS,IAAM3B,EAAgB,KAAK,EACpC,SAAUH,GAAY,GAAEL,GAAA,YAAAA,EAAO,aAAc,IAC7C,cAAY,mBAEZ,SAAA,CAAAgC,EAAAA,IAACrC,EAAA,CAAQ,KAAM,GAAI,cAAW,GAAC,EAAE,YAAA,CAAA,CAAA,CACnC,CAAA,CACF,CAAA,CAAA,EAIJqC,MAACM,EAAA,CAAK,QAAQ,UACZ,eAACC,EAAA,CACE,SAAAzC,EAAc,SAAW8B,EAAK,SAAW,EACxCE,EAAAA,KAACC,EAAA,CAAM,IAAK,EACV,SAAA,CAAAC,EAAAA,IAACQ,EAAA,CAAS,MAAO,CAAE,OAAQ,IAAM,QAChCA,EAAA,CAAS,MAAO,CAAE,OAAQ,IAAM,QAChCA,EAAA,CAAS,MAAO,CAAE,OAAQ,GAAG,CAAG,CAAA,CAAA,CACnC,EACEZ,EAAK,SAAW,EAClBI,EAAAA,IAACS,EAAA,CAAW,KAAMT,EAAAA,IAACrC,EAAA,CAAQ,KAAM,GAAI,cAAW,EAAA,CAAC,EAAI,MAAM,cAAc,YAAY,8CAAA,CAA+C,EAEpIqC,EAAAA,IAACD,EAAA,CAAM,IAAK,EACT,SAAAH,EAAK,IAAKC,GAAM,CACf,MAAMa,EAAenC,IAAiBsB,EAAE,GACxC,OACEC,EAAAA,KAAC,MAAA,CAEC,cAAa,cAAcD,EAAE,EAAE,GAC/B,MAAO,CACL,QAAS,iBACT,OAAQ,0BACR,aAAc,mBACd,WAAY,kBAAA,EAGd,SAAA,CAAAC,OAACI,GAAO,MAAM,SAAS,QAAQ,UAAU,IAAK,EAC5C,SAAA,CAAAJ,EAAAA,KAACC,EAAA,CAAM,IAAK,EACV,SAAA,CAAAD,EAAAA,KAACI,EAAA,CAAO,MAAM,SAAS,IAAK,EAC1B,SAAA,CAAAF,EAAAA,IAAC,SAAA,CAAQ,SAAAH,EAAE,OAASA,EAAE,GAAG,EACzBG,EAAAA,IAAC,OAAA,CAAK,MAAO,CAAE,SAAU,eAAgB,MAAO,kBAAA,EAAuB,SAAAH,EAAE,EAAA,CAAG,CAAA,EAC9E,EACAC,EAAAA,KAACI,EAAA,CAAO,MAAM,SAAS,IAAK,EAC1B,SAAA,CAAAJ,OAAC,QAAK,MAAO,CAAE,SAAU,eAAgB,MAAO,mBAAqB,SAAA,CAAA,cACxDE,EAAAA,IAAC,OAAA,CAAM,SAAAH,EAAE,WAAa,GAAA,CAAI,CAAA,EACvC,EACCA,EAAE,SAAW,QAAaA,EAAE,SAAW,MACtCC,OAAC,OAAA,CAAK,MAAO,CAAE,SAAU,eAAgB,MAAO,mBAAqB,SAAA,CAAA,WAC3DE,EAAAA,IAAC,OAAA,CAAM,SAAAH,EAAE,MAAA,CAAO,CAAA,EAC1B,EAEDA,EAAE,WACDG,EAAAA,IAAC,QAAK,cAAa,oBAAoBH,EAAE,EAAE,GAAI,MAAO,CAAE,SAAU,eAAgB,MAAO,gBAAiB,WAAY,GAAA,EAAO,SAAA,kBAAA,CAE7H,CAAA,CAAA,CAEJ,CAAA,EACF,EACAG,EAAAA,IAACE,EAAA,CAAO,IAAK,EACV,WAAE,WACDF,EAAAA,IAACG,EAAA,CACC,QAAQ,QACR,QAAS,IAAM3B,EAAiBmC,GAASA,IAAQd,EAAE,GAAK,KAAOA,EAAE,EAAG,EACpE,cAAa,gBAAgBA,EAAE,EAAE,GACjC,SAAUxB,EACX,SAAA,OAAA,CAAA,CAED,CAEJ,CAAA,EACF,EACCqC,UACER,EAAA,CAAO,IAAK,EAAG,MAAO,CAAE,UAAW,gBAAA,EAClC,SAAA,CAAAF,MAACG,GAAO,QAAQ,UAAU,QAAS,IAAM,KAAKT,EAAM,CAACG,EAAE,EAAE,CAAC,EAAG,cAAa,wBAAwBA,EAAE,EAAE,GAAI,SAAA,gBAE1G,EACAG,EAAAA,IAACG,GAAO,QAAQ,QAAQ,QAAS,IAAM3B,EAAgB,IAAI,EAAG,SAAA,QAAA,CAAM,CAAA,CAAA,CACtE,CAAA,CAAA,EAlDGqB,EAAE,EAAA,CAsDb,CAAC,CAAA,CACH,CAAA,CAEJ,EACF,EAECtB,IAAiB,OAChByB,MAACM,EAAA,CAAK,QAAQ,UACZ,SAAAN,EAAAA,IAACO,EAAA,CACC,SAAAT,OAACC,EAAA,CAAM,IAAK,EACV,SAAA,CAAAC,EAAAA,IAAC,UAAO,SAAA,oBAAA,CAAkB,EAC1BF,OAAC,QAAK,MAAO,CAAE,SAAU,eAAgB,MAAO,mBAC7C,SAAA,CAAAF,EAAK,OAAQC,GAAMA,EAAE,SAAS,EAAE,OAAO,yCAAA,EAC1C,EACAC,EAAAA,KAACI,EAAA,CAAO,IAAK,EACX,SAAA,CAAAF,EAAAA,IAACG,EAAA,CAAO,QAAQ,UAAU,QAAS,IAAM,KAAKT,EAAME,EAAK,OAAQC,GAAMA,EAAE,SAAS,EAAE,IAAKA,GAAMA,EAAE,EAAE,CAAC,EAAG,cAAY,2BAA2B,SAAA,mBAAA,CAE9I,EACAG,EAAAA,IAACG,GAAO,QAAQ,QAAQ,QAAS,IAAM3B,EAAgB,IAAI,EAAG,SAAA,QAAA,CAAM,CAAA,CAAA,CACtE,CAAA,CAAA,CACF,EACF,EACF,EAGDC,EAAI,OAAS,GACZuB,EAAAA,IAACM,GAAK,QAAQ,UACZ,gBAACC,EAAA,CACC,SAAA,CAAAP,MAAC,UAAO,MAAO,CAAE,SAAU,cAAA,EAAkB,SAAA,WAAQ,EACrDA,EAAAA,IAAC,MAAA,CACC,cAAY,aACZ,MAAO,CACL,UAAW,iBACX,QAAS,iBACT,WAAY,mBACZ,aAAc,mBACd,WAAY,mBACZ,SAAU,eACV,UAAW,IACX,SAAU,MAAA,EAGX,SAAAvB,EAAI,MAAM,IAAI,EAAE,IAAI,CAACW,EAAGwB,IACvBZ,EAAAA,IAAC,MAAA,CAAY,MAAO,CAAE,MAAOZ,EAAE,MAAQ,gBAAkBA,EAAE,SAAW,OAAS,iBAAmB,WAAA,EAC/F,SAAAA,EAAE,OAAS,kBACVU,EAAAA,KAACI,EAAA,CAAO,MAAM,SAAS,IAAK,EAAG,SAAA,CAAAF,EAAAA,IAACa,EAAA,CAAa,KAAM,GAAI,cAAW,GAAC,MAAO,CAAE,MAAO,gBAAA,CAAiB,CAAG,EAAE,WAAA,CAAA,CAAS,EAChHzB,EAAE,MACJU,OAACI,GAAO,MAAM,SAAS,IAAK,EAAG,SAAA,CAAAF,EAAAA,IAACc,EAAA,CAAY,KAAM,GAAI,cAAW,GAAC,MAAO,CAAE,MAAO,eAAA,CAAgB,CAAG,EAAE,IAAE1B,EAAE,KAAO,IAAI,MAAIA,EAAE,KAAA,EAAM,EAElIU,EAAAA,KAACI,EAAA,CAAO,MAAM,SAAS,IAAK,EACzB,SAAA,CAAAd,EAAE,SAAW,aAAeY,EAAAA,IAACe,EAAA,CAAQ,KAAM,GAAI,cAAW,GAAC,MAAO,CAAE,UAAW,yBAAA,EAA6B,EAAK,KACjH3B,EAAE,KAAO,IAAI,MAAIA,EAAE,QAAUA,EAAE,MAAQ,EAAA,CAAA,CAC1C,CAAA,EATMwB,CAWV,CACD,CAAA,CAAA,CACH,CAAA,CACF,CAAA,CACF,CAAA,EAEJ,CAEJ","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"UpdateView-tD2q2OhW.js","sources":["../../../node_modules/lucide-react/dist/esm/icons/package.js","../../src/web/v8/views/Update/UpdateView.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.460.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Package = createLucideIcon(\"Package\", [\n [\n \"path\",\n {\n d: \"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z\",\n key: \"1a0edw\"\n }\n ],\n [\"path\", { d: \"M12 22V12\", key: \"d0xqtd\" }],\n [\"path\", { d: \"m3.3 7 7.703 4.734a2 2 0 0 0 1.994 0L20.7 7\", key: \"yx3hmr\" }],\n [\"path\", { d: \"m7.5 4.27 9 5.15\", key: \"1c824w\" }]\n]);\n\nexport { Package as default };\n//# sourceMappingURL=package.js.map\n","/**\n * v8/views/Update/UpdateView.tsx — Sprint S42, v9.3.0.\n *\n * Package update status + Check + Apply:\n * - GET /api/updates/status — installed versions\n * - GET /api/updates/check — installed + latest + hasUpdates\n * - POST /api/updates/apply — kick install, streams via\n * `update:progress` / `update:log` / `update:complete` WS events.\n *\n * Per-package Apply (inline-confirm) + global Apply All button. Live\n * progress list rendered from a useWsMessage subscription.\n */\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { Package, RefreshCcw, Download, CheckCircle2, AlertCircle, Loader2 } from 'lucide-react';\nimport { Stack } from '../../ui/primitives/Stack.js';\nimport { Inline } from '../../ui/primitives/Inline.js';\nimport { ViewHeader } from '../../ui/data/ViewHeader.js';\nimport { Card, CardBody } from '../../ui/data/Card.js';\nimport { Button } from '../../ui/controls/Button.js';\nimport { Skeleton } from '../../ui/feedback/Skeleton.js';\nimport { EmptyState } from '../../ui/feedback/EmptyState.js';\nimport { useFetch } from '../../data/useFetch.js';\nimport { useWsMessage } from '../../data/useWebSocket.js';\nimport { fetchJson, FetchError } from '../../data/fetcher.js';\n\ninterface UpdateEntry {\n id: string;\n installed?: string;\n latest?: string | null;\n hasUpdate?: boolean;\n label?: string;\n}\n\ninterface StatusResponse {\n packages: UpdateEntry[];\n}\n\ninterface CheckResponse {\n packages: UpdateEntry[];\n hasUpdates?: boolean;\n}\n\ninterface ProgressEvent {\n type: 'update:progress' | 'update:log' | 'update:complete';\n pkg?: string;\n status?: string;\n line?: string;\n newVersion?: string;\n error?: string;\n}\n\nexport function UpdateView(): JSX.Element {\n const statusPayload = useFetch<StatusResponse>('/api/updates/status');\n const [check, setCheck] = useState<CheckResponse | null>(null);\n const [checking, setChecking] = useState<boolean>(false);\n const [applying, setApplying] = useState<boolean>(false);\n const [confirmApply, setConfirmApply] = useState<string | null>(null);\n const [log, setLog] = useState<ProgressEvent[]>([]);\n const [error, setError] = useState<string | null>(null);\n\n const installed = useMemo<UpdateEntry[]>(() => statusPayload.data?.packages ?? [], [statusPayload.data]);\n const refresh = useCallback(() => { void statusPayload.refetch(); }, [statusPayload]);\n\n // Subscribe to live progress events. `msg.type` is the discriminator\n // (e.g. 'update:progress'); spreading first then narrowing via the\n // cast avoids the TS2783 duplicate-key error we'd hit if we tried to\n // also set `type: 'update:progress'` literally.\n useWsMessage('update:progress', (msg) => {\n setLog((l) => [...l, { ...msg, type: 'update:progress' } as ProgressEvent]);\n });\n useWsMessage('update:log', (msg) => {\n setLog((l) => [...l, { ...msg, type: 'update:log' } as ProgressEvent]);\n });\n useWsMessage('update:complete', (msg) => {\n setLog((l) => [...l, { ...msg, type: 'update:complete' } as ProgressEvent]);\n setApplying(false);\n refresh();\n });\n\n const runCheck = async (): Promise<void> => {\n setChecking(true);\n setError(null);\n try {\n const r = await fetchJson<CheckResponse>('/api/updates/check');\n setCheck(r);\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n } finally {\n setChecking(false);\n }\n };\n\n const apply = async (ids: string[]): Promise<void> => {\n setApplying(true);\n setError(null);\n setConfirmApply(null);\n try {\n await fetchJson('/api/updates/apply', { method: 'POST', body: { packages: ids } });\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n setApplying(false);\n }\n };\n\n const rows: UpdateEntry[] = check?.packages ?? installed.map((p) => ({ ...p, hasUpdate: false }));\n\n return (\n <Stack gap={4} data-testid=\"update-view\">\n <ViewHeader\n title=\"Update\"\n description=\"Bizar package updates. Apply restarts on next launch.\"\n actions={\n <Inline align=\"center\" gap={2}>\n {error !== null && (\n <span role=\"alert\" data-testid=\"update-error\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>\n {error}\n </span>\n )}\n <Button variant=\"ghost\" onClick={() => void refresh()} data-testid=\"update-refresh\">\n <RefreshCcw size={14} aria-hidden /> Refresh\n </Button>\n <Button variant=\"ghost\" onClick={() => void runCheck()} disabled={checking} data-testid=\"update-check\">\n <Download size={14} aria-hidden /> {checking ? 'Checking…' : 'Check'}\n </Button>\n <Button\n variant=\"primary\"\n onClick={() => setConfirmApply('all')}\n disabled={applying || !(check?.hasUpdates ?? false)}\n data-testid=\"update-apply-all\"\n >\n <Package size={14} aria-hidden /> Apply all\n </Button>\n </Inline>\n }\n />\n\n <Card variant=\"default\">\n <CardBody>\n {statusPayload.loading && rows.length === 0 ? (\n <Stack gap={1}>\n <Skeleton style={{ height: 40 }} />\n <Skeleton style={{ height: 40 }} />\n <Skeleton style={{ height: 40 }} />\n </Stack>\n ) : rows.length === 0 ? (\n <EmptyState icon={<Package size={28} aria-hidden />} title=\"No packages\" description=\"Update status endpoint returned no packages.\" />\n ) : (\n <Stack gap={1}>\n {rows.map((p) => {\n const isConfirming = confirmApply === p.id;\n return (\n <div\n key={p.id}\n data-testid={`update-row-${p.id}`}\n style={{\n padding: 'var(--space-2)',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-sm)',\n background: 'var(--surface-0)',\n }}\n >\n <Inline align=\"center\" justify=\"between\" gap={2}>\n <Stack gap={0}>\n <Inline align=\"center\" gap={2}>\n <strong>{p.label || p.id}</strong>\n <code style={{ fontSize: 'var(--fs-11)', color: 'var(--fg-subtle)' }}>{p.id}</code>\n </Inline>\n <Inline align=\"center\" gap={2}>\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n installed: <code>{p.installed ?? '?'}</code>\n </span>\n {p.latest !== undefined && p.latest !== null && (\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n latest: <code>{p.latest}</code>\n </span>\n )}\n {p.hasUpdate && (\n <span data-testid={`update-available-${p.id}`} style={{ fontSize: 'var(--fs-11)', color: 'var(--accent)', fontWeight: 600 }}>\n UPDATE AVAILABLE\n </span>\n )}\n </Inline>\n </Stack>\n <Inline gap={1}>\n {p.hasUpdate && (\n <Button\n variant=\"ghost\"\n onClick={() => setConfirmApply((cur) => (cur === p.id ? null : p.id))}\n data-testid={`update-apply-${p.id}`}\n disabled={applying}\n >\n Apply\n </Button>\n )}\n </Inline>\n </Inline>\n {isConfirming && (\n <Inline gap={1} style={{ marginTop: 'var(--space-1)' }}>\n <Button variant=\"primary\" onClick={() => void apply([p.id])} data-testid={`update-confirm-apply-${p.id}`}>\n Confirm apply\n </Button>\n <Button variant=\"ghost\" onClick={() => setConfirmApply(null)}>Cancel</Button>\n </Inline>\n )}\n </div>\n );\n })}\n </Stack>\n )}\n </CardBody>\n </Card>\n\n {confirmApply === 'all' && (\n <Card variant=\"default\">\n <CardBody>\n <Stack gap={2}>\n <strong>Apply all updates?</strong>\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n {rows.filter((p) => p.hasUpdate).length} package(s) will update on next launch.\n </span>\n <Inline gap={1}>\n <Button variant=\"primary\" onClick={() => void apply(rows.filter((p) => p.hasUpdate).map((p) => p.id))} data-testid=\"update-confirm-apply-all\">\n Confirm apply all\n </Button>\n <Button variant=\"ghost\" onClick={() => setConfirmApply(null)}>Cancel</Button>\n </Inline>\n </Stack>\n </CardBody>\n </Card>\n )}\n\n {log.length > 0 && (\n <Card variant=\"default\">\n <CardBody>\n <strong style={{ fontSize: 'var(--fs-13)' }}>Progress</strong>\n <div\n data-testid=\"update-log\"\n style={{\n marginTop: 'var(--space-2)',\n padding: 'var(--space-2)',\n background: 'var(--surface-1)',\n borderRadius: 'var(--radius-sm)',\n fontFamily: 'var(--font-mono)',\n fontSize: 'var(--fs-12)',\n maxHeight: 240,\n overflow: 'auto',\n }}\n >\n {log.slice(-100).map((l, i) => (\n <div key={i} style={{ color: l.error ? 'var(--danger)' : l.status === 'done' ? 'var(--success)' : 'var(--fg)' }}>\n {l.type === 'update:complete' ? (\n <Inline align=\"center\" gap={1}><CheckCircle2 size={12} aria-hidden style={{ color: 'var(--success)' }} /> complete</Inline>\n ) : l.error ? (\n <Inline align=\"center\" gap={1}><AlertCircle size={12} aria-hidden style={{ color: 'var(--danger)' }} /> {l.pkg ?? '?'} · {l.error}</Inline>\n ) : (\n <Inline align=\"center\" gap={1}>\n {l.status === 'installing' ? <Loader2 size={12} aria-hidden style={{ animation: 'spin 1s linear infinite' }} /> : null}\n {l.pkg ?? '?'} · {l.status ?? l.line ?? ''}\n </Inline>\n )}\n </div>\n ))}\n </div>\n </CardBody>\n </Card>\n )}\n </Stack>\n );\n}"],"names":["Package","createLucideIcon","UpdateView","statusPayload","useFetch","check","setCheck","useState","checking","setChecking","applying","setApplying","confirmApply","setConfirmApply","log","setLog","error","setError","installed","useMemo","_a","refresh","useCallback","useWsMessage","msg","l","runCheck","r","fetchJson","err","FetchError","apply","ids","rows","p","jsxs","Stack","jsx","ViewHeader","Inline","Button","RefreshCcw","Download","Card","CardBody","Skeleton","EmptyState","isConfirming","cur","i","CheckCircle2","AlertCircle","Loader2"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as b,j as e}from"./cmdk-DVxytz9i.js";import{u as k,S as a,I as l,K as z,h as C}from"./main-
|
|
1
|
+
import{r as b,j as e}from"./cmdk-DVxytz9i.js";import{u as k,S as a,I as l,K as z,h as C}from"./main-CyAIirBB.js";import{G as T}from"./Grid-dEnoGGws.js";import{V as w}from"./ViewHeader-V_SzbUpw.js";import{C as g,b as h}from"./Card-D9019JOD.js";import{E as F}from"./ErrorState-Bump8diE.js";import{T as I}from"./trending-up-BXwP23VK.js";import{Z as R}from"./zap-BaOiybcl.js";import{C as q}from"./clock-C0GlM4qp.js";import"./Alert-Dg_Vwxh5.js";import"./circle-alert-CQ9MLygI.js";import"./triangle-alert-DFmQ_RXN.js";import"./circle-check-COtVgsWw.js";import"./refresh-ccw-BCXx86xp.js";const E=[{id:"24h",label:"24 hours"},{id:"7d",label:"7 days"},{id:"30d",label:"30 days"}];function u(s){return s<1e3?String(s):s<1e6?`${(s/1e3).toFixed(1)}k`:`${(s/1e6).toFixed(2)}M`}function f({label:s,value:d,sub:t,icon:n}){return e.jsx(g,{variant:"default",children:e.jsx(h,{children:e.jsxs(a,{gap:1,children:[e.jsxs(l,{align:"center",gap:2,children:[e.jsx(n,{size:14,"aria-hidden":!0}),e.jsx("span",{style:{fontSize:"var(--fs-12)",color:"var(--fg-muted)"},children:s})]}),e.jsx("strong",{style:{fontSize:"var(--fs-18)",fontFamily:"var(--font-mono)"},children:d}),t&&e.jsx("span",{style:{fontSize:"var(--fs-12)",color:"var(--fg-muted)"},children:t})]})})})}function J(){var p,x,v,j,y;const[s,d]=b.useState("24h"),t=k(`/api/usage?range=${s}`),n=k("/api/usage/limits");b.useEffect(()=>{},[s]);const i=(p=t.data)==null?void 0:p.totals,o=((x=t.data)==null?void 0:x.byProvider)??[],m=((v=t.data)==null?void 0:v.byModel)??[],c=o.reduce((r,S)=>Math.max(r,S.tokens),0);return e.jsxs(a,{gap:5,"data-testid":"usage-view",children:[e.jsx(w,{title:"Usage",description:"Token consumption + quota limits from the rolling JSONL log.",actions:e.jsx(l,{gap:1,children:E.map(r=>e.jsx("button",{type:"button",onClick:()=>d(r.id),"aria-pressed":s===r.id,"data-testid":`usage-range-${r.id}`,style:{padding:"4px 10px",border:"1px solid var(--border)",borderRadius:"var(--radius-sm)",background:s===r.id?"var(--accent)":"var(--surface-1)",color:s===r.id?"var(--accent-fg)":"var(--fg)",fontSize:"var(--fs-12)",cursor:"pointer"},children:r.label},r.id))})}),e.jsxs(T,{cols:3,children:[e.jsx(f,{label:"Total tokens",icon:z,value:t.loading?"…":u((i==null?void 0:i.tokens)??0),sub:i?`${i.requests} requests`:""}),e.jsx(f,{label:"Distinct providers",icon:I,value:t.loading?"…":String(o.length)}),e.jsx(f,{label:"Live limits",icon:R,value:n.loading?"…":String(((y=(j=n.data)==null?void 0:j.models)==null?void 0:y.length)??0),sub:"active quotas"})]}),t.loading?e.jsx(C,{style:{height:200}}):t.error&&o.length===0?e.jsx(F,{block:!0,title:"Couldn't load usage",description:"Token analytics failed to fetch. Retry to refetch.",error:t.error,onRetry:()=>void t.refetch(),testid:"usage-error"}):o.length===0?e.jsx(g,{variant:"default",children:e.jsx(h,{children:e.jsxs(a,{gap:1,align:"center",style:{padding:"var(--space-4)"},children:[e.jsx(q,{size:24,"aria-hidden":!0}),e.jsxs("span",{style:{color:"var(--fg-muted)"},children:["No usage records for the last ",s,"."]})]})})}):e.jsx(g,{variant:"default",children:e.jsx(h,{children:e.jsxs(a,{gap:3,children:[e.jsx("strong",{children:"By provider"}),e.jsx(a,{gap:2,children:o.map(r=>e.jsxs(a,{gap:1,children:[e.jsxs(l,{align:"center",justify:"between",children:[e.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:"var(--fs-12)"},children:r.providerId}),e.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontSize:"var(--fs-12)",color:"var(--fg-muted)"},children:[u(r.tokens)," · ",r.requests," req"]})]}),e.jsx("div",{role:"progressbar","aria-valuemin":0,"aria-valuemax":c||1,"aria-valuenow":r.tokens,style:{height:6,background:"var(--surface-1)",borderRadius:"var(--radius-pill)",overflow:"hidden"},children:e.jsx("div",{style:{width:`${c>0?r.tokens/c*100:0}%`,height:"100%",background:"var(--accent)"}})})]},r.providerId))}),m.length>0&&e.jsxs(a,{gap:2,children:[e.jsx("strong",{children:"Top models"}),m.slice(0,5).map(r=>e.jsxs(l,{align:"center",justify:"between",style:{fontSize:"var(--fs-12)"},children:[e.jsx("code",{style:{fontFamily:"var(--font-mono)"},children:r.modelId}),e.jsx("span",{style:{color:"var(--fg-muted)"},children:u(r.tokens)})]},r.modelId))]})]})})})]})}export{J as UsageView};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UsageView-COyr_Gfi.js","sources":["../../src/web/v8/views/Usage/UsageView.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { BarChart3, TrendingUp, Clock, Zap } from 'lucide-react';\nimport { Stack } from '../../ui/primitives/Stack.js';\nimport { Inline } from '../../ui/primitives/Inline.js';\nimport { Grid } from '../../ui/primitives/Grid.js';\nimport { ViewHeader } from '../../ui/data/ViewHeader.js';\nimport { Card, CardBody } from '../../ui/data/Card.js';\nimport { Skeleton } from '../../ui/feedback/Skeleton.js';\nimport { ErrorState } from '../../ui/feedback/ErrorState.js';\nimport { useFetch } from '../../data/useFetch.js';\n\n/**\n * UsageView — Sprint S35. Token usage analytics from JSONL logs.\n */\n\ntype Range = '24h' | '7d' | '30d';\n\ninterface UsageTotals {\n tokens: number;\n cost?: number;\n requests: number;\n}\n\ninterface UsageByProvider {\n providerId: string;\n tokens: number;\n requests: number;\n}\n\ninterface UsageResponse {\n totals: UsageTotals;\n byProvider?: UsageByProvider[];\n byModel?: Array<{ modelId: string; tokens: number; requests: number }>;\n series?: Array<{ ts: number; tokens: number }>;\n}\n\ninterface LimitEntry {\n providerId?: string;\n modelId?: string;\n remaining?: number;\n limit?: number;\n}\n\ninterface LimitsResponse {\n models: LimitEntry[];\n}\n\nconst RANGE_OPTIONS: Array<{ id: Range; label: string }> = [\n { id: '24h', label: '24 hours' },\n { id: '7d', label: '7 days' },\n { id: '30d', label: '30 days' },\n];\n\nfunction fmtTokens(n: number): string {\n if (n < 1000) return String(n);\n if (n < 1_000_000) return `${(n / 1000).toFixed(1)}k`;\n return `${(n / 1_000_000).toFixed(2)}M`;\n}\n\nfunction StatTile({ label, value, sub, icon: Icon }: { label: string; value: string; sub?: string; icon: typeof BarChart3 }): JSX.Element {\n return (\n <Card variant=\"default\">\n <CardBody>\n <Stack gap={1}>\n <Inline align=\"center\" gap={2}>\n <Icon size={14} aria-hidden />\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>{label}</span>\n </Inline>\n <strong style={{ fontSize: 'var(--fs-18)', fontFamily: 'var(--font-mono)' }}>{value}</strong>\n {sub && <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>{sub}</span>}\n </Stack>\n </CardBody>\n </Card>\n );\n}\n\nexport function UsageView(): JSX.Element {\n const [range, setRange] = useState<Range>('24h');\n const res = useFetch<UsageResponse>(`/api/usage?range=${range}`);\n const limits = useFetch<LimitsResponse>('/api/usage/limits');\n\n useEffect(() => {\n // refetch on range change is implicit (useFetch re-keys on URL change).\n }, [range]);\n\n const totals = res.data?.totals;\n const byProvider = res.data?.byProvider ?? [];\n const byModel = res.data?.byModel ?? [];\n const maxProvider = byProvider.reduce((m, p) => Math.max(m, p.tokens), 0);\n\n return (\n <Stack gap={5} data-testid=\"usage-view\">\n <ViewHeader\n title=\"Usage\"\n description=\"Token consumption + quota limits from the rolling JSONL log.\"\n actions={\n <Inline gap={1}>\n {RANGE_OPTIONS.map((r) => (\n <button\n key={r.id}\n type=\"button\"\n onClick={() => setRange(r.id)}\n aria-pressed={range === r.id}\n data-testid={`usage-range-${r.id}`}\n style={{\n padding: '4px 10px',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-sm)',\n background: range === r.id ? 'var(--accent)' : 'var(--surface-1)',\n color: range === r.id ? 'var(--accent-fg)' : 'var(--fg)',\n fontSize: 'var(--fs-12)',\n cursor: 'pointer',\n }}\n >\n {r.label}\n </button>\n ))}\n </Inline>\n }\n />\n\n <Grid cols={3}>\n <StatTile\n label=\"Total tokens\"\n icon={BarChart3}\n value={res.loading ? '…' : fmtTokens(totals?.tokens ?? 0)}\n sub={totals ? `${totals.requests} requests` : ''}\n />\n <StatTile\n label=\"Distinct providers\"\n icon={TrendingUp}\n value={res.loading ? '…' : String(byProvider.length)}\n />\n <StatTile\n label=\"Live limits\"\n icon={Zap}\n value={limits.loading ? '…' : String(limits.data?.models?.length ?? 0)}\n sub=\"active quotas\"\n />\n </Grid>\n\n {res.loading ? (\n <Skeleton style={{ height: 200 }} />\n ) : res.error && byProvider.length === 0 ? (\n <ErrorState\n block\n title=\"Couldn't load usage\"\n description=\"Token analytics failed to fetch. Retry to refetch.\"\n error={res.error}\n onRetry={() => void res.refetch()}\n testid=\"usage-error\"\n />\n ) : byProvider.length === 0 ? (\n <Card variant=\"default\">\n <CardBody>\n <Stack gap={1} align=\"center\" style={{ padding: 'var(--space-4)' }}>\n <Clock size={24} aria-hidden />\n <span style={{ color: 'var(--fg-muted)' }}>No usage records for the last {range}.</span>\n </Stack>\n </CardBody>\n </Card>\n ) : (\n <Card variant=\"default\">\n <CardBody>\n <Stack gap={3}>\n <strong>By provider</strong>\n <Stack gap={2}>\n {byProvider.map((p) => (\n <Stack key={p.providerId} gap={1}>\n <Inline align=\"center\" justify=\"between\">\n <span style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--fs-12)' }}>{p.providerId}</span>\n <span style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n {fmtTokens(p.tokens)} · {p.requests} req\n </span>\n </Inline>\n <div\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={maxProvider || 1}\n aria-valuenow={p.tokens}\n style={{\n height: 6,\n background: 'var(--surface-1)',\n borderRadius: 'var(--radius-pill)',\n overflow: 'hidden',\n }}\n >\n <div style={{ width: `${maxProvider > 0 ? (p.tokens / maxProvider) * 100 : 0}%`, height: '100%', background: 'var(--accent)' }} />\n </div>\n </Stack>\n ))}\n </Stack>\n {byModel.length > 0 && (\n <Stack gap={2}>\n <strong>Top models</strong>\n {byModel.slice(0, 5).map((m) => (\n <Inline key={m.modelId} align=\"center\" justify=\"between\" style={{ fontSize: 'var(--fs-12)' }}>\n <code style={{ fontFamily: 'var(--font-mono)' }}>{m.modelId}</code>\n <span style={{ color: 'var(--fg-muted)' }}>{fmtTokens(m.tokens)}</span>\n </Inline>\n ))}\n </Stack>\n )}\n </Stack>\n </CardBody>\n </Card>\n )}\n </Stack>\n );\n}"],"names":["RANGE_OPTIONS","fmtTokens","n","StatTile","label","value","sub","Icon","jsx","Card","CardBody","jsxs","Stack","Inline","UsageView","range","setRange","useState","res","useFetch","limits","useEffect","totals","_a","byProvider","_b","byModel","_c","maxProvider","m","p","ViewHeader","Grid","BarChart3","TrendingUp","Zap","_e","_d","Skeleton","ErrorState","Clock"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"UsageView-B4BuAFKA.js","sources":["../../src/web/v8/views/Usage/UsageView.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { BarChart3, TrendingUp, Clock, Zap } from 'lucide-react';\nimport { Stack } from '../../ui/primitives/Stack.js';\nimport { Inline } from '../../ui/primitives/Inline.js';\nimport { Grid } from '../../ui/primitives/Grid.js';\nimport { ViewHeader } from '../../ui/data/ViewHeader.js';\nimport { Card, CardBody } from '../../ui/data/Card.js';\nimport { Skeleton } from '../../ui/feedback/Skeleton.js';\nimport { ErrorState } from '../../ui/feedback/ErrorState.js';\nimport { useFetch } from '../../data/useFetch.js';\n\n/**\n * UsageView — Sprint S35. Token usage analytics from JSONL logs.\n */\n\ntype Range = '24h' | '7d' | '30d';\n\ninterface UsageTotals {\n tokens: number;\n cost?: number;\n requests: number;\n}\n\ninterface UsageByProvider {\n providerId: string;\n tokens: number;\n requests: number;\n}\n\ninterface UsageResponse {\n totals: UsageTotals;\n byProvider?: UsageByProvider[];\n byModel?: Array<{ modelId: string; tokens: number; requests: number }>;\n series?: Array<{ ts: number; tokens: number }>;\n}\n\ninterface LimitEntry {\n providerId?: string;\n modelId?: string;\n remaining?: number;\n limit?: number;\n}\n\ninterface LimitsResponse {\n models: LimitEntry[];\n}\n\nconst RANGE_OPTIONS: Array<{ id: Range; label: string }> = [\n { id: '24h', label: '24 hours' },\n { id: '7d', label: '7 days' },\n { id: '30d', label: '30 days' },\n];\n\nfunction fmtTokens(n: number): string {\n if (n < 1000) return String(n);\n if (n < 1_000_000) return `${(n / 1000).toFixed(1)}k`;\n return `${(n / 1_000_000).toFixed(2)}M`;\n}\n\nfunction StatTile({ label, value, sub, icon: Icon }: { label: string; value: string; sub?: string; icon: typeof BarChart3 }): JSX.Element {\n return (\n <Card variant=\"default\">\n <CardBody>\n <Stack gap={1}>\n <Inline align=\"center\" gap={2}>\n <Icon size={14} aria-hidden />\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>{label}</span>\n </Inline>\n <strong style={{ fontSize: 'var(--fs-18)', fontFamily: 'var(--font-mono)' }}>{value}</strong>\n {sub && <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>{sub}</span>}\n </Stack>\n </CardBody>\n </Card>\n );\n}\n\nexport function UsageView(): JSX.Element {\n const [range, setRange] = useState<Range>('24h');\n const res = useFetch<UsageResponse>(`/api/usage?range=${range}`);\n const limits = useFetch<LimitsResponse>('/api/usage/limits');\n\n useEffect(() => {\n // refetch on range change is implicit (useFetch re-keys on URL change).\n }, [range]);\n\n const totals = res.data?.totals;\n const byProvider = res.data?.byProvider ?? [];\n const byModel = res.data?.byModel ?? [];\n const maxProvider = byProvider.reduce((m, p) => Math.max(m, p.tokens), 0);\n\n return (\n <Stack gap={5} data-testid=\"usage-view\">\n <ViewHeader\n title=\"Usage\"\n description=\"Token consumption + quota limits from the rolling JSONL log.\"\n actions={\n <Inline gap={1}>\n {RANGE_OPTIONS.map((r) => (\n <button\n key={r.id}\n type=\"button\"\n onClick={() => setRange(r.id)}\n aria-pressed={range === r.id}\n data-testid={`usage-range-${r.id}`}\n style={{\n padding: '4px 10px',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-sm)',\n background: range === r.id ? 'var(--accent)' : 'var(--surface-1)',\n color: range === r.id ? 'var(--accent-fg)' : 'var(--fg)',\n fontSize: 'var(--fs-12)',\n cursor: 'pointer',\n }}\n >\n {r.label}\n </button>\n ))}\n </Inline>\n }\n />\n\n <Grid cols={3}>\n <StatTile\n label=\"Total tokens\"\n icon={BarChart3}\n value={res.loading ? '…' : fmtTokens(totals?.tokens ?? 0)}\n sub={totals ? `${totals.requests} requests` : ''}\n />\n <StatTile\n label=\"Distinct providers\"\n icon={TrendingUp}\n value={res.loading ? '…' : String(byProvider.length)}\n />\n <StatTile\n label=\"Live limits\"\n icon={Zap}\n value={limits.loading ? '…' : String(limits.data?.models?.length ?? 0)}\n sub=\"active quotas\"\n />\n </Grid>\n\n {res.loading ? (\n <Skeleton style={{ height: 200 }} />\n ) : res.error && byProvider.length === 0 ? (\n <ErrorState\n block\n title=\"Couldn't load usage\"\n description=\"Token analytics failed to fetch. Retry to refetch.\"\n error={res.error}\n onRetry={() => void res.refetch()}\n testid=\"usage-error\"\n />\n ) : byProvider.length === 0 ? (\n <Card variant=\"default\">\n <CardBody>\n <Stack gap={1} align=\"center\" style={{ padding: 'var(--space-4)' }}>\n <Clock size={24} aria-hidden />\n <span style={{ color: 'var(--fg-muted)' }}>No usage records for the last {range}.</span>\n </Stack>\n </CardBody>\n </Card>\n ) : (\n <Card variant=\"default\">\n <CardBody>\n <Stack gap={3}>\n <strong>By provider</strong>\n <Stack gap={2}>\n {byProvider.map((p) => (\n <Stack key={p.providerId} gap={1}>\n <Inline align=\"center\" justify=\"between\">\n <span style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--fs-12)' }}>{p.providerId}</span>\n <span style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n {fmtTokens(p.tokens)} · {p.requests} req\n </span>\n </Inline>\n <div\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={maxProvider || 1}\n aria-valuenow={p.tokens}\n style={{\n height: 6,\n background: 'var(--surface-1)',\n borderRadius: 'var(--radius-pill)',\n overflow: 'hidden',\n }}\n >\n <div style={{ width: `${maxProvider > 0 ? (p.tokens / maxProvider) * 100 : 0}%`, height: '100%', background: 'var(--accent)' }} />\n </div>\n </Stack>\n ))}\n </Stack>\n {byModel.length > 0 && (\n <Stack gap={2}>\n <strong>Top models</strong>\n {byModel.slice(0, 5).map((m) => (\n <Inline key={m.modelId} align=\"center\" justify=\"between\" style={{ fontSize: 'var(--fs-12)' }}>\n <code style={{ fontFamily: 'var(--font-mono)' }}>{m.modelId}</code>\n <span style={{ color: 'var(--fg-muted)' }}>{fmtTokens(m.tokens)}</span>\n </Inline>\n ))}\n </Stack>\n )}\n </Stack>\n </CardBody>\n </Card>\n )}\n </Stack>\n );\n}"],"names":["RANGE_OPTIONS","fmtTokens","n","StatTile","label","value","sub","Icon","jsx","Card","CardBody","jsxs","Stack","Inline","UsageView","range","setRange","useState","res","useFetch","limits","useEffect","totals","_a","byProvider","_b","byModel","_c","maxProvider","m","p","ViewHeader","Grid","BarChart3","TrendingUp","Zap","_e","_d","Skeleton","ErrorState","Clock"],"mappings":"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"}
|