agim-cli 1.4.3 → 1.4.8
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/dist/cli.js +10 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/llm/registry.d.ts +1 -1
- package/dist/core/llm/registry.d.ts.map +1 -1
- package/dist/core/memory-distill.d.ts +22 -5
- package/dist/core/memory-distill.d.ts.map +1 -1
- package/dist/core/memory-distill.js +153 -133
- package/dist/core/memory-distill.js.map +1 -1
- package/dist/core/memory-distiller.d.ts +23 -0
- package/dist/core/memory-distiller.d.ts.map +1 -0
- package/dist/core/memory-distiller.js +124 -0
- package/dist/core/memory-distiller.js.map +1 -0
- package/dist/core/memory.d.ts +31 -0
- package/dist/core/memory.d.ts.map +1 -1
- package/dist/core/memory.js +102 -3
- package/dist/core/memory.js.map +1 -1
- package/dist/core/persona.d.ts +2 -2
- package/dist/core/persona.d.ts.map +1 -1
- package/dist/core/persona.js +4 -2
- package/dist/core/persona.js.map +1 -1
- package/dist/web/public/assets/{a2a-DWibx2v1.js → a2a-Dnc-MHI-.js} +2 -2
- package/dist/web/public/assets/{a2a-DWibx2v1.js.map → a2a-Dnc-MHI-.js.map} +1 -1
- package/dist/web/public/assets/{activity-CSppRQoj.js → activity-CKQwfSVC.js} +2 -2
- package/dist/web/public/assets/{activity-CSppRQoj.js.map → activity-CKQwfSVC.js.map} +1 -1
- package/dist/web/public/assets/{admins-C9uvJ-ek.js → admins-C7MdDEF0.js} +2 -2
- package/dist/web/public/assets/{admins-C9uvJ-ek.js.map → admins-C7MdDEF0.js.map} +1 -1
- package/dist/web/public/assets/{agents-rbtxCOzD.js → agents-Be4IUCYz.js} +2 -2
- package/dist/web/public/assets/{agents-rbtxCOzD.js.map → agents-Be4IUCYz.js.map} +1 -1
- package/dist/web/public/assets/{approvals-CgRDzZZP.js → approvals-KCd1BSvN.js} +2 -2
- package/dist/web/public/assets/{approvals-CgRDzZZP.js.map → approvals-KCd1BSvN.js.map} +1 -1
- package/dist/web/public/assets/{arrow-down-DfVXLyJ6.js → arrow-down-NRUr_gzg.js} +2 -2
- package/dist/web/public/assets/{arrow-down-DfVXLyJ6.js.map → arrow-down-NRUr_gzg.js.map} +1 -1
- package/dist/web/public/assets/{arrow-up-CMHA89ux.js → arrow-up-4KyqPaSd.js} +2 -2
- package/dist/web/public/assets/{arrow-up-CMHA89ux.js.map → arrow-up-4KyqPaSd.js.map} +1 -1
- package/dist/web/public/assets/{asks-9JCznWEb.js → asks-nKwuDJpD.js} +2 -2
- package/dist/web/public/assets/{asks-9JCznWEb.js.map → asks-nKwuDJpD.js.map} +1 -1
- package/dist/web/public/assets/{audit-DM5sKNA4.js → audit-Bf4Yv1or.js} +2 -2
- package/dist/web/public/assets/{audit-DM5sKNA4.js.map → audit-Bf4Yv1or.js.map} +1 -1
- package/dist/web/public/assets/{bell-BzG0tUiv.js → bell--lSOhH-X.js} +2 -2
- package/dist/web/public/assets/{bell-BzG0tUiv.js.map → bell--lSOhH-X.js.map} +1 -1
- package/dist/web/public/assets/{bgjobs-dLxHKjQK.js → bgjobs-Daya2BMh.js} +2 -2
- package/dist/web/public/assets/{bgjobs-dLxHKjQK.js.map → bgjobs-Daya2BMh.js.map} +1 -1
- package/dist/web/public/assets/{brain-9QmMQ6Ap.js → brain-DF90t0yo.js} +2 -2
- package/dist/web/public/assets/{brain-9QmMQ6Ap.js.map → brain-DF90t0yo.js.map} +1 -1
- package/dist/web/public/assets/{briefcase-BehkRQvT.js → briefcase-aRM_fCrr.js} +2 -2
- package/dist/web/public/assets/{briefcase-BehkRQvT.js.map → briefcase-aRM_fCrr.js.map} +1 -1
- package/dist/web/public/assets/{chat-nfyoGDVp.js → chat-BhnNXkIJ.js} +2 -2
- package/dist/web/public/assets/{chat-nfyoGDVp.js.map → chat-BhnNXkIJ.js.map} +1 -1
- package/dist/web/public/assets/{chevron-left-DHpm5XR1.js → chevron-left-DK-fhgiL.js} +2 -2
- package/dist/web/public/assets/{chevron-left-DHpm5XR1.js.map → chevron-left-DK-fhgiL.js.map} +1 -1
- package/dist/web/public/assets/{chevron-right-BIKADdPm.js → chevron-right-BGhMfCcE.js} +2 -2
- package/dist/web/public/assets/{chevron-right-BIKADdPm.js.map → chevron-right-BGhMfCcE.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-BbAeV_k2.js → circle-check-BWBI4Qhk.js} +2 -2
- package/dist/web/public/assets/{circle-check-BbAeV_k2.js.map → circle-check-BWBI4Qhk.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-big-Cd4Eyz41.js → circle-check-big-BppjBT7j.js} +2 -2
- package/dist/web/public/assets/{circle-check-big-Cd4Eyz41.js.map → circle-check-big-BppjBT7j.js.map} +1 -1
- package/dist/web/public/assets/{circle-x-CrmHcrAS.js → circle-x-BZ3UUhcm.js} +2 -2
- package/dist/web/public/assets/{circle-x-CrmHcrAS.js.map → circle-x-BZ3UUhcm.js.map} +1 -1
- package/dist/web/public/assets/{clock-jJtwqx8f.js → clock-ChP0IxI4.js} +2 -2
- package/dist/web/public/assets/{clock-jJtwqx8f.js.map → clock-ChP0IxI4.js.map} +1 -1
- package/dist/web/public/assets/{confirm-dialog-D4JCDxHT.js → confirm-dialog-DrP5Lfwx.js} +2 -2
- package/dist/web/public/assets/{confirm-dialog-D4JCDxHT.js.map → confirm-dialog-DrP5Lfwx.js.map} +1 -1
- package/dist/web/public/assets/{copy-D9ljWg7b.js → copy-CR2c0pyG.js} +2 -2
- package/dist/web/public/assets/{copy-D9ljWg7b.js.map → copy-CR2c0pyG.js.map} +1 -1
- package/dist/web/public/assets/{data-table-yUuGHUSG.js → data-table-DElP7TJm.js} +2 -2
- package/dist/web/public/assets/{data-table-yUuGHUSG.js.map → data-table-DElP7TJm.js.map} +1 -1
- package/dist/web/public/assets/distill-DxSq7g_8.js +7 -0
- package/dist/web/public/assets/distill-DxSq7g_8.js.map +1 -0
- package/dist/web/public/assets/{download-9zxV6ejH.js → download-DO4Kw3Fi.js} +2 -2
- package/dist/web/public/assets/{download-9zxV6ejH.js.map → download-DO4Kw3Fi.js.map} +1 -1
- package/dist/web/public/assets/{email-C8Fx7GcZ.js → email-Dkqwudqq.js} +2 -2
- package/dist/web/public/assets/{email-C8Fx7GcZ.js.map → email-Dkqwudqq.js.map} +1 -1
- package/dist/web/public/assets/{empty-state-B0sJBvsG.js → empty-state-DGH3i5i2.js} +2 -2
- package/dist/web/public/assets/{empty-state-B0sJBvsG.js.map → empty-state-DGH3i5i2.js.map} +1 -1
- package/dist/web/public/assets/{external-link-C3fHPbrL.js → external-link-B6aOBfUG.js} +2 -2
- package/dist/web/public/assets/{external-link-C3fHPbrL.js.map → external-link-B6aOBfUG.js.map} +1 -1
- package/dist/web/public/assets/{eye-BrcGR1Ln.js → eye-BMxHZFil.js} +2 -2
- package/dist/web/public/assets/{eye-BrcGR1Ln.js.map → eye-BMxHZFil.js.map} +1 -1
- package/dist/web/public/assets/{facts-DNcekpR_.js → facts-B9PlO3xo.js} +2 -2
- package/dist/web/public/assets/{facts-DNcekpR_.js.map → facts-B9PlO3xo.js.map} +1 -1
- package/dist/web/public/assets/{goals-BJ0I0rVU.js → goals-DX_RjDAM.js} +2 -2
- package/dist/web/public/assets/{goals-BJ0I0rVU.js.map → goals-DX_RjDAM.js.map} +1 -1
- package/dist/web/public/assets/{health-DCFAQ615.js → health-BAcwcy02.js} +2 -2
- package/dist/web/public/assets/{health-DCFAQ615.js.map → health-BAcwcy02.js.map} +1 -1
- package/dist/web/public/assets/{heart-pulse-CiwiVY1D.js → heart-pulse-Cl-tJTJY.js} +2 -2
- package/dist/web/public/assets/{heart-pulse-CiwiVY1D.js.map → heart-pulse-Cl-tJTJY.js.map} +1 -1
- package/dist/web/public/assets/{heartbeat-CYIIkyqM.js → heartbeat-BF_rPcKb.js} +2 -2
- package/dist/web/public/assets/{heartbeat-CYIIkyqM.js.map → heartbeat-BF_rPcKb.js.map} +1 -1
- package/dist/web/public/assets/{hot-SjwVKjTN.js → hot-XOCA1xAY.js} +2 -2
- package/dist/web/public/assets/{hot-SjwVKjTN.js.map → hot-XOCA1xAY.js.map} +1 -1
- package/dist/web/public/assets/{index-BiXaJRfQ.js → index-CzlhMSb2.js} +32 -32
- package/dist/web/public/assets/index-CzlhMSb2.js.map +1 -0
- package/dist/web/public/assets/{injection-rK-nXEck.js → injection-ecvQ-6Ya.js} +2 -2
- package/dist/web/public/assets/{injection-rK-nXEck.js.map → injection-ecvQ-6Ya.js.map} +1 -1
- package/dist/web/public/assets/{installed-C3GsWhFt.js → installed-D8VzYRBe.js} +2 -2
- package/dist/web/public/assets/{installed-C3GsWhFt.js.map → installed-D8VzYRBe.js.map} +1 -1
- package/dist/web/public/assets/{jobs-Bu20ae1w.js → jobs-CpuY6G8D.js} +2 -2
- package/dist/web/public/assets/{jobs-Bu20ae1w.js.map → jobs-CpuY6G8D.js.map} +1 -1
- package/dist/web/public/assets/{layout-B4AOR7bx.js → layout--XsfZzpI.js} +2 -2
- package/dist/web/public/assets/{layout-B4AOR7bx.js.map → layout--XsfZzpI.js.map} +1 -1
- package/dist/web/public/assets/{layout-C0eeaex1.js → layout-BROGs5wv.js} +2 -2
- package/dist/web/public/assets/{layout-C0eeaex1.js.map → layout-BROGs5wv.js.map} +1 -1
- package/dist/web/public/assets/{layout-BjiHbubM.js → layout-BezPqRLV.js} +2 -2
- package/dist/web/public/assets/{layout-BjiHbubM.js.map → layout-BezPqRLV.js.map} +1 -1
- package/dist/web/public/assets/layout-DdbuRh8P.js +2 -0
- package/dist/web/public/assets/layout-DdbuRh8P.js.map +1 -0
- package/dist/web/public/assets/{layout-e2mh2uBC.js → layout-Pxfmfh_2.js} +2 -2
- package/dist/web/public/assets/{layout-e2mh2uBC.js.map → layout-Pxfmfh_2.js.map} +1 -1
- package/dist/web/public/assets/{llm-CgMGyAjF.js → llm-IXFv_MMM.js} +2 -2
- package/dist/web/public/assets/{llm-CgMGyAjF.js.map → llm-IXFv_MMM.js.map} +1 -1
- package/dist/web/public/assets/{loader-circle-D_dW2RUZ.js → loader-circle-AgQ2XO06.js} +2 -2
- package/dist/web/public/assets/{loader-circle-D_dW2RUZ.js.map → loader-circle-AgQ2XO06.js.map} +1 -1
- package/dist/web/public/assets/{map-pin-jOOaGCmo.js → map-pin-C6sGB9SZ.js} +2 -2
- package/dist/web/public/assets/{map-pin-jOOaGCmo.js.map → map-pin-C6sGB9SZ.js.map} +1 -1
- package/dist/web/public/assets/{mcp-Ip_omrap.js → mcp-jqsjSumH.js} +2 -2
- package/dist/web/public/assets/{mcp-Ip_omrap.js.map → mcp-jqsjSumH.js.map} +1 -1
- package/dist/web/public/assets/{memos-yOmAURiM.js → memos-C38YN2Rf.js} +2 -2
- package/dist/web/public/assets/{memos-yOmAURiM.js.map → memos-C38YN2Rf.js.map} +1 -1
- package/dist/web/public/assets/{messengers-DdS6Tv_H.js → messengers-l74nqYZF.js} +2 -2
- package/dist/web/public/assets/{messengers-DdS6Tv_H.js.map → messengers-l74nqYZF.js.map} +1 -1
- package/dist/web/public/assets/{mobile-7gRnqslc.js → mobile-CHhYS0Tw.js} +2 -2
- package/dist/web/public/assets/{mobile-7gRnqslc.js.map → mobile-CHhYS0Tw.js.map} +1 -1
- package/dist/web/public/assets/{network-ClaA9iUg.js → network-CIrcKaZn.js} +2 -2
- package/dist/web/public/assets/{network-ClaA9iUg.js.map → network-CIrcKaZn.js.map} +1 -1
- package/dist/web/public/assets/{outbox-YtiqLz-u.js → outbox-O1lzMZPk.js} +2 -2
- package/dist/web/public/assets/{outbox-YtiqLz-u.js.map → outbox-O1lzMZPk.js.map} +1 -1
- package/dist/web/public/assets/{pagination-DU9Lf0rD.js → pagination-CXBUSf6r.js} +2 -2
- package/dist/web/public/assets/{pagination-DU9Lf0rD.js.map → pagination-CXBUSf6r.js.map} +1 -1
- package/dist/web/public/assets/{persona-C9vZYuJJ.js → persona-CI4tkm_n.js} +2 -2
- package/dist/web/public/assets/{persona-C9vZYuJJ.js.map → persona-CI4tkm_n.js.map} +1 -1
- package/dist/web/public/assets/{plans-doYYvgG_.js → plans-D8RZ9aXq.js} +2 -2
- package/dist/web/public/assets/{plans-doYYvgG_.js.map → plans-D8RZ9aXq.js.map} +1 -1
- package/dist/web/public/assets/{play-C5MgP1qM.js → play-DQ3P_XWl.js} +2 -2
- package/dist/web/public/assets/{play-C5MgP1qM.js.map → play-DQ3P_XWl.js.map} +1 -1
- package/dist/web/public/assets/{plus-BFi9eVCl.js → plus-Zai0UXKL.js} +2 -2
- package/dist/web/public/assets/{plus-BFi9eVCl.js.map → plus-Zai0UXKL.js.map} +1 -1
- package/dist/web/public/assets/{policy-DS3IIL78.js → policy-BodrOHl5.js} +2 -2
- package/dist/web/public/assets/{policy-DS3IIL78.js.map → policy-BodrOHl5.js.map} +1 -1
- package/dist/web/public/assets/{qr-code-BL039OK7.js → qr-code-zcjicWRK.js} +2 -2
- package/dist/web/public/assets/{qr-code-BL039OK7.js.map → qr-code-zcjicWRK.js.map} +1 -1
- package/dist/web/public/assets/{refresh-ccw-DBNikooZ.js → refresh-ccw-CM-Cjwud.js} +2 -2
- package/dist/web/public/assets/{refresh-ccw-DBNikooZ.js.map → refresh-ccw-CM-Cjwud.js.map} +1 -1
- package/dist/web/public/assets/{reminders-BcymTbK9.js → reminders-BR6noe6I.js} +2 -2
- package/dist/web/public/assets/{reminders-BcymTbK9.js.map → reminders-BR6noe6I.js.map} +1 -1
- package/dist/web/public/assets/{save-DZiTNYpH.js → save-xBMgs6Bd.js} +2 -2
- package/dist/web/public/assets/{save-DZiTNYpH.js.map → save-xBMgs6Bd.js.map} +1 -1
- package/dist/web/public/assets/{schedules-C47XYMM0.js → schedules-Brp1Fomd.js} +2 -2
- package/dist/web/public/assets/{schedules-C47XYMM0.js.map → schedules-Brp1Fomd.js.map} +1 -1
- package/dist/web/public/assets/{search-DSXC_EYz.js → search-CIc8bWW1.js} +2 -2
- package/dist/web/public/assets/{search-DSXC_EYz.js.map → search-CIc8bWW1.js.map} +1 -1
- package/dist/web/public/assets/{search-DbPfPYg8.js → search-nk8nyLFI.js} +2 -2
- package/dist/web/public/assets/{search-DbPfPYg8.js.map → search-nk8nyLFI.js.map} +1 -1
- package/dist/web/public/assets/{security-D7z1GPFd.js → security-DWxWfpuX.js} +2 -2
- package/dist/web/public/assets/{security-D7z1GPFd.js.map → security-DWxWfpuX.js.map} +1 -1
- package/dist/web/public/assets/{service-7mISPUwf.js → service-Bo9rkfQX.js} +2 -2
- package/dist/web/public/assets/{service-7mISPUwf.js.map → service-Bo9rkfQX.js.map} +1 -1
- package/dist/web/public/assets/{shield-alert-C3F8izo0.js → shield-alert-bg0_ILjD.js} +2 -2
- package/dist/web/public/assets/{shield-alert-C3F8izo0.js.map → shield-alert-bg0_ILjD.js.map} +1 -1
- package/dist/web/public/assets/{status-badge-CvmA1Y93.js → status-badge-Bw4TDDCb.js} +2 -2
- package/dist/web/public/assets/{status-badge-CvmA1Y93.js.map → status-badge-Bw4TDDCb.js.map} +1 -1
- package/dist/web/public/assets/{subtasks-Bkgb9Pkm.js → subtasks-D58R9C_Z.js} +2 -2
- package/dist/web/public/assets/{subtasks-Bkgb9Pkm.js.map → subtasks-D58R9C_Z.js.map} +1 -1
- package/dist/web/public/assets/{table-z7CVpKMe.js → table-D4S5FCk_.js} +2 -2
- package/dist/web/public/assets/{table-z7CVpKMe.js.map → table-D4S5FCk_.js.map} +1 -1
- package/dist/web/public/assets/{topn-B7GHdOiE.js → topn-DDxDNIZf.js} +2 -2
- package/dist/web/public/assets/{topn-B7GHdOiE.js.map → topn-DDxDNIZf.js.map} +1 -1
- package/dist/web/public/assets/{trash-2-DdjC6QH7.js → trash-2-CB7X8tay.js} +2 -2
- package/dist/web/public/assets/{trash-2-DdjC6QH7.js.map → trash-2-CB7X8tay.js.map} +1 -1
- package/dist/web/public/assets/{use-agim-skills-CZkKns-g.js → use-agim-skills-BV2IJPlc.js} +2 -2
- package/dist/web/public/assets/{use-agim-skills-CZkKns-g.js.map → use-agim-skills-BV2IJPlc.js.map} +1 -1
- package/dist/web/public/assets/{use-background-tasks-CVdojnmx.js → use-background-tasks-Dk9S55ip.js} +2 -2
- package/dist/web/public/assets/{use-background-tasks-CVdojnmx.js.map → use-background-tasks-Dk9S55ip.js.map} +1 -1
- package/dist/web/public/assets/use-memory-DncmZXGJ.js +2 -0
- package/dist/web/public/assets/use-memory-DncmZXGJ.js.map +1 -0
- package/dist/web/public/assets/{use-observability-BtZPZLvB.js → use-observability-CcDO7PdN.js} +2 -2
- package/dist/web/public/assets/{use-observability-BtZPZLvB.js.map → use-observability-CcDO7PdN.js.map} +1 -1
- package/dist/web/public/assets/{use-settings-DHEiuHAv.js → use-settings-DZhfMpNR.js} +2 -2
- package/dist/web/public/assets/{use-settings-DHEiuHAv.js.map → use-settings-DZhfMpNR.js.map} +1 -1
- package/dist/web/public/assets/{use-workspace-C1gInLvF.js → use-workspace-ywkrT7Aj.js} +2 -2
- package/dist/web/public/assets/{use-workspace-C1gInLvF.js.map → use-workspace-ywkrT7Aj.js.map} +1 -1
- package/dist/web/public/assets/{vector-CLlo9px7.js → vector-B3h4iyfn.js} +2 -2
- package/dist/web/public/assets/{vector-CLlo9px7.js.map → vector-B3h4iyfn.js.map} +1 -1
- package/dist/web/public/assets/{viewer-BGdrQoJC.js → viewer-Bz3wL-99.js} +2 -2
- package/dist/web/public/assets/{viewer-BGdrQoJC.js.map → viewer-Bz3wL-99.js.map} +1 -1
- package/dist/web/public/assets/{workspace-zG8AgTev.js → workspace-BvrXvliN.js} +2 -2
- package/dist/web/public/assets/{workspace-zG8AgTev.js.map → workspace-BvrXvliN.js.map} +1 -1
- package/dist/web/public/assets/{workspaces-DT2xLs5G.js → workspaces-0H6Dzz6N.js} +2 -2
- package/dist/web/public/assets/{workspaces-DT2xLs5G.js.map → workspaces-0H6Dzz6N.js.map} +1 -1
- package/dist/web/public/index.html +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +42 -0
- package/dist/web/server.js.map +1 -1
- package/package.json +2 -1
- package/dist/web/public/assets/index-BiXaJRfQ.js.map +0 -1
- package/dist/web/public/assets/layout-CHFdMCNs.js +0 -2
- package/dist/web/public/assets/layout-CHFdMCNs.js.map +0 -1
- package/dist/web/public/assets/use-memory-CHARtjQ-.js +0 -2
- package/dist/web/public/assets/use-memory-CHARtjQ-.js.map +0 -1
package/dist/web/public/assets/{circle-check-BbAeV_k2.js.map → circle-check-BWBI4Qhk.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"circle-check-
|
|
1
|
+
{"version":3,"file":"circle-check-BWBI4Qhk.js","sources":["../../node_modules/lucide-react/dist/esm/icons/circle-check.js"],"sourcesContent":["/**\n * @license lucide-react v0.469.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 CircleCheck = createLucideIcon(\"CircleCheck\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"m9 12 2 2 4-4\", key: \"dzmm74\" }]\n]);\n\nexport { CircleCheck as default };\n//# sourceMappingURL=circle-check.js.map\n"],"names":["CircleCheck","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAcC,EAAiB,cAAe,CAClD,CAAC,SAAU,CAAE,GAAI,KAAM,GAAI,KAAM,EAAG,KAAM,IAAK,SAAU,EACzD,CAAC,OAAQ,CAAE,EAAG,gBAAiB,IAAK,QAAQ,CAAE,CAChD,CAAC","x_google_ignoreList":[0]}
|
package/dist/web/public/assets/{circle-check-big-Cd4Eyz41.js → circle-check-big-BppjBT7j.js}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{o as e}from"./index-
|
|
1
|
+
import{o as e}from"./index-CzlhMSb2.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
5
5
|
* See the LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/const t=e("CircleCheckBig",[["path",{d:"M21.801 10A10 10 0 1 1 17 3.335",key:"yps3ct"}],["path",{d:"m9 11 3 3L22 4",key:"1pflzl"}]]);export{t as C};
|
|
7
|
-
//# sourceMappingURL=circle-check-big-
|
|
7
|
+
//# sourceMappingURL=circle-check-big-BppjBT7j.js.map
|
package/dist/web/public/assets/{circle-check-big-Cd4Eyz41.js.map → circle-check-big-BppjBT7j.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"circle-check-big-
|
|
1
|
+
{"version":3,"file":"circle-check-big-BppjBT7j.js","sources":["../../node_modules/lucide-react/dist/esm/icons/circle-check-big.js"],"sourcesContent":["/**\n * @license lucide-react v0.469.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 CircleCheckBig = createLucideIcon(\"CircleCheckBig\", [\n [\"path\", { d: \"M21.801 10A10 10 0 1 1 17 3.335\", key: \"yps3ct\" }],\n [\"path\", { d: \"m9 11 3 3L22 4\", key: \"1pflzl\" }]\n]);\n\nexport { CircleCheckBig as default };\n//# sourceMappingURL=circle-check-big.js.map\n"],"names":["CircleCheckBig","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAiBC,EAAiB,iBAAkB,CACxD,CAAC,OAAQ,CAAE,EAAG,kCAAmC,IAAK,QAAQ,CAAE,EAChE,CAAC,OAAQ,CAAE,EAAG,iBAAkB,IAAK,QAAQ,CAAE,CACjD,CAAC","x_google_ignoreList":[0]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{o as c}from"./index-
|
|
1
|
+
import{o as c}from"./index-CzlhMSb2.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
5
5
|
* See the LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/const r=c("CircleX",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m15 9-6 6",key:"1uzhvr"}],["path",{d:"m9 9 6 6",key:"z0biqf"}]]);export{r as C};
|
|
7
|
-
//# sourceMappingURL=circle-x-
|
|
7
|
+
//# sourceMappingURL=circle-x-BZ3UUhcm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"circle-x-
|
|
1
|
+
{"version":3,"file":"circle-x-BZ3UUhcm.js","sources":["../../node_modules/lucide-react/dist/esm/icons/circle-x.js"],"sourcesContent":["/**\n * @license lucide-react v0.469.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 CircleX = createLucideIcon(\"CircleX\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"m15 9-6 6\", key: \"1uzhvr\" }],\n [\"path\", { d: \"m9 9 6 6\", key: \"z0biqf\" }]\n]);\n\nexport { CircleX as default };\n//# sourceMappingURL=circle-x.js.map\n"],"names":["CircleX","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAUC,EAAiB,UAAW,CAC1C,CAAC,SAAU,CAAE,GAAI,KAAM,GAAI,KAAM,EAAG,KAAM,IAAK,SAAU,EACzD,CAAC,OAAQ,CAAE,EAAG,YAAa,IAAK,QAAQ,CAAE,EAC1C,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAQ,CAAE,CAC3C,CAAC","x_google_ignoreList":[0]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{o as c}from"./index-
|
|
1
|
+
import{o as c}from"./index-CzlhMSb2.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
5
5
|
* See the LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/const e=c("Clock",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["polyline",{points:"12 6 12 12 16 14",key:"68esgv"}]]);export{e as C};
|
|
7
|
-
//# sourceMappingURL=clock-
|
|
7
|
+
//# sourceMappingURL=clock-ChP0IxI4.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clock-
|
|
1
|
+
{"version":3,"file":"clock-ChP0IxI4.js","sources":["../../node_modules/lucide-react/dist/esm/icons/clock.js"],"sourcesContent":["/**\n * @license lucide-react v0.469.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 Clock = createLucideIcon(\"Clock\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"polyline\", { points: \"12 6 12 12 16 14\", key: \"68esgv\" }]\n]);\n\nexport { Clock as default };\n//# sourceMappingURL=clock.js.map\n"],"names":["Clock","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAQC,EAAiB,QAAS,CACtC,CAAC,SAAU,CAAE,GAAI,KAAM,GAAI,KAAM,EAAG,KAAM,IAAK,SAAU,EACzD,CAAC,WAAY,CAAE,OAAQ,mBAAoB,IAAK,QAAQ,CAAE,CAC5D,CAAC","x_google_ignoreList":[0]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{u as y,j as a,D as j,t as D,v as g,w as h,x as b,y as p,B as r}from"./index-
|
|
2
|
-
//# sourceMappingURL=confirm-dialog-
|
|
1
|
+
import{u as y,j as a,D as j,t as D,v as g,w as h,x as b,y as p,B as r}from"./index-CzlhMSb2.js";import{r as n}from"./react-DlP5eolq.js";function v({open:c,onOpenChange:t,title:d,description:e,confirmLabel:u,cancelLabel:f,intent:x="default",onConfirm:l}){const{t:i}=y("common"),[s,o]=n.useState(!1),m=n.useCallback(async()=>{o(!0);try{await l(),t(!1)}catch{}finally{o(!1)}},[l,t]);return a.jsx(j,{open:c,onOpenChange:s?()=>{}:t,children:a.jsxs(D,{children:[a.jsxs(g,{children:[a.jsx(h,{children:d}),e&&a.jsx(b,{children:e})]}),a.jsxs(p,{children:[a.jsx(r,{type:"button",variant:"secondary",onClick:()=>t(!1),disabled:s,children:f??i("actions.cancel")}),a.jsx(r,{type:"button",variant:x==="danger"?"destructive":"default",onClick:m,disabled:s,"aria-busy":s,children:s?i("states.saving"):u??i("actions.confirm")})]})]})})}v.displayName="ConfirmDialog";export{v as C};
|
|
2
|
+
//# sourceMappingURL=confirm-dialog-DrP5Lfwx.js.map
|
package/dist/web/public/assets/{confirm-dialog-D4JCDxHT.js.map → confirm-dialog-DrP5Lfwx.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"confirm-dialog-
|
|
1
|
+
{"version":3,"file":"confirm-dialog-DrP5Lfwx.js","sources":["../../src/components/common/confirm-dialog.tsx"],"sourcesContent":["/**\n * ConfirmDialog — unified secondary-confirmation for destructive /\n * irreversible actions: delete fact, cancel job, revoke approval,\n * drop reminder, prune memos, etc.\n *\n * Why a wrapper: the v1 web admin had 3+ near-duplicate confirm\n * patterns (alert(), inline ▼ \"Are you sure?\" links, raw Dialog\n * uses). They each phrased the title / button differently and the\n * destructive variant was inconsistent. This component is the single\n * legal way to ask \"are you sure\" in v2.\n *\n * Controlled-only: caller owns the `open` state. That makes it\n * trivial to compose into a row action menu (open the dialog when\n * user clicks \"Delete\" in a DropdownMenu) without needing a\n * uncontrolled / `asChild` Trigger.\n *\n * `intent=\"danger\"` swaps the confirm button to the destructive\n * variant. `intent=\"default\"` (the implicit fallback) keeps the\n * primary blue — for non-destructive confirms like \"Submit anyway?\"\n *\n * Async confirm: the `onConfirm` callback may return a Promise; the\n * confirm button shows a busy state and stays disabled until the\n * promise settles. On error the dialog stays open so the caller can\n * surface the error via toast.\n */\n\nimport * as React from 'react'\nimport { useTranslation } from 'react-i18next'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/dialog'\nimport { Button } from '@/components/ui/button'\n\nexport type ConfirmDialogIntent = 'default' | 'danger'\n\nexport interface ConfirmDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n title: React.ReactNode\n description?: React.ReactNode\n /** Label for the confirm button. Defaults to t('common.actions.confirm'). */\n confirmLabel?: React.ReactNode\n /** Label for the cancel button. Defaults to t('common.actions.cancel'). */\n cancelLabel?: React.ReactNode\n /** Default: \"default\". `danger` styles the confirm button as destructive. */\n intent?: ConfirmDialogIntent\n /** Called when the user clicks confirm. May return a Promise; the\n * button shows busy state until the promise settles. The dialog\n * closes on success; on rejection it stays open. */\n onConfirm: () => void | Promise<void>\n}\n\nfunction ConfirmDialog({\n open,\n onOpenChange,\n title,\n description,\n confirmLabel,\n cancelLabel,\n intent = 'default',\n onConfirm,\n}: ConfirmDialogProps): JSX.Element {\n const { t } = useTranslation('common')\n const [busy, setBusy] = React.useState(false)\n\n const handleConfirm = React.useCallback(async () => {\n setBusy(true)\n try {\n await onConfirm()\n onOpenChange(false)\n } catch {\n // Keep dialog open; caller surfaces the failure via toast.\n } finally {\n setBusy(false)\n }\n }, [onConfirm, onOpenChange])\n\n return (\n <Dialog open={open} onOpenChange={busy ? () => {} : onOpenChange}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{title}</DialogTitle>\n {description && <DialogDescription>{description}</DialogDescription>}\n </DialogHeader>\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={() => onOpenChange(false)}\n disabled={busy}\n >\n {cancelLabel ?? t('actions.cancel')}\n </Button>\n <Button\n type=\"button\"\n variant={intent === 'danger' ? 'destructive' : 'default'}\n onClick={handleConfirm}\n disabled={busy}\n aria-busy={busy}\n >\n {busy ? t('states.saving') : (confirmLabel ?? t('actions.confirm'))}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\nConfirmDialog.displayName = 'ConfirmDialog'\n\nexport { ConfirmDialog }\n"],"names":["ConfirmDialog","open","onOpenChange","title","description","confirmLabel","cancelLabel","intent","onConfirm","t","useTranslation","busy","setBusy","React.useState","handleConfirm","React.useCallback","jsx","Dialog","jsxs","DialogContent","DialogHeader","DialogTitle","DialogDescription","DialogFooter","Button"],"mappings":"wIAyDA,SAASA,EAAc,CACrB,KAAAC,EACA,aAAAC,EACA,MAAAC,EACA,YAAAC,EACA,aAAAC,EACA,YAAAC,EACA,OAAAC,EAAS,UACT,UAAAC,CACF,EAAoC,CAClC,KAAM,CAAE,EAAAC,CAAA,EAAMC,EAAe,QAAQ,EAC/B,CAACC,EAAMC,CAAO,EAAIC,EAAAA,SAAe,EAAK,EAEtCC,EAAgBC,EAAAA,YAAkB,SAAY,CAClDH,EAAQ,EAAI,EACZ,GAAI,CACF,MAAMJ,EAAA,EACNN,EAAa,EAAK,CACpB,MAAQ,CAER,QAAA,CACEU,EAAQ,EAAK,CACf,CACF,EAAG,CAACJ,EAAWN,CAAY,CAAC,EAE5B,OACEc,EAAAA,IAACC,EAAA,CAAO,KAAAhB,EAAY,aAAcU,EAAO,IAAM,CAAC,EAAIT,EAClD,SAAAgB,EAAAA,KAACC,EAAA,CACC,SAAA,CAAAD,OAACE,EAAA,CACC,SAAA,CAAAJ,EAAAA,IAACK,GAAa,SAAAlB,CAAA,CAAM,EACnBC,GAAeY,EAAAA,IAACM,EAAA,CAAmB,SAAAlB,CAAA,CAAY,CAAA,EAClD,SACCmB,EAAA,CACC,SAAA,CAAAP,EAAAA,IAACQ,EAAA,CACC,KAAK,SACL,QAAQ,YACR,QAAS,IAAMtB,EAAa,EAAK,EACjC,SAAUS,EAET,SAAAL,GAAeG,EAAE,gBAAgB,CAAA,CAAA,EAEpCO,EAAAA,IAACQ,EAAA,CACC,KAAK,SACL,QAASjB,IAAW,SAAW,cAAgB,UAC/C,QAASO,EACT,SAAUH,EACV,YAAWA,EAEV,WAAOF,EAAE,eAAe,EAAKJ,GAAgBI,EAAE,iBAAiB,CAAA,CAAA,CACnE,CAAA,CACF,CAAA,CAAA,CACF,CAAA,CACF,CAEJ,CACAT,EAAc,YAAc"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{o as e}from"./index-
|
|
1
|
+
import{o as e}from"./index-CzlhMSb2.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
5
5
|
* See the LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/const o=e("Copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]);export{o as C};
|
|
7
|
-
//# sourceMappingURL=copy-
|
|
7
|
+
//# sourceMappingURL=copy-CR2c0pyG.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy-
|
|
1
|
+
{"version":3,"file":"copy-CR2c0pyG.js","sources":["../../node_modules/lucide-react/dist/esm/icons/copy.js"],"sourcesContent":["/**\n * @license lucide-react v0.469.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 Copy = createLucideIcon(\"Copy\", [\n [\"rect\", { width: \"14\", height: \"14\", x: \"8\", y: \"8\", rx: \"2\", ry: \"2\", key: \"17jyea\" }],\n [\"path\", { d: \"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\", key: \"zix9uf\" }]\n]);\n\nexport { Copy as default };\n//# sourceMappingURL=copy.js.map\n"],"names":["Copy","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAOC,EAAiB,OAAQ,CACpC,CAAC,OAAQ,CAAE,MAAO,KAAM,OAAQ,KAAM,EAAG,IAAK,EAAG,IAAK,GAAI,IAAK,GAAI,IAAK,IAAK,SAAU,EACvF,CAAC,OAAQ,CAAE,EAAG,0DAA2D,IAAK,QAAQ,CAAE,CAC1F,CAAC","x_google_ignoreList":[0]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{o as _,u as H,j as e,c as g}from"./index-
|
|
1
|
+
import{o as _,u as H,j as e,c as g}from"./index-CzlhMSb2.js";import{r as P}from"./react-DlP5eolq.js";import{T as $,a as q,b as u,c as D,d as B,e as b}from"./table-D4S5FCk_.js";import{E}from"./empty-state-DGH3i5i2.js";import{A as F}from"./arrow-up-4KyqPaSd.js";import{A as L}from"./arrow-down-NRUr_gzg.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
5
5
|
* See the LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/const O=_("ArrowUpDown",[["path",{d:"m21 16-4 4-4-4",key:"f6ql7i"}],["path",{d:"M17 20V4",key:"1ejh1v"}],["path",{d:"m3 8 4-4 4 4",key:"11wl7u"}],["path",{d:"M7 4v16",key:"1glfcx"}]]);function V({columns:i,rows:r,getRowId:m,loading:N=!1,loadingRows:k=5,emptyState:y,onRowClick:h,selection:n,onSelectionChange:v,sort:x,onSortChange:p,className:M}){const{t:f}=H("common"),t=n!==void 0&&v!==void 0,j=t&&r.length>0&&r.every(a=>n.has(m(a))),T=t&&r.some(a=>n.has(m(a)))&&!j;function w(){if(!t)return;const a=new Set(n);if(j)for(const s of r)a.delete(m(s));else for(const s of r)a.add(m(s));v(a)}function A(a){if(!t)return;const s=new Set(n);s.has(a)?s.delete(a):s.add(a),v(s)}function U(a){p&&(!x||x.id!==a?p({id:a,dir:"asc"}):x.dir==="asc"?p({id:a,dir:"desc"}):p(null))}return e.jsxs("div",{className:g("w-full",M),children:[e.jsx("div",{className:"hidden md:block",children:e.jsxs($,{children:[e.jsx(q,{children:e.jsxs(u,{children:[t&&e.jsx(D,{className:"w-10",children:e.jsx("input",{type:"checkbox",role:"checkbox","aria-label":f("table.selectAll"),"aria-checked":T?"mixed":j,checked:j,ref:a=>{a&&(a.indeterminate=T)},onChange:w,disabled:N||r.length===0,className:"h-4 w-4 accent-accent cursor-pointer"})}),i.map(a=>e.jsx(D,{className:a.headClassName,children:a.sortable&&p?e.jsxs("button",{type:"button",onClick:()=>U(a.id),className:g("inline-flex items-center gap-1","uppercase tracking-wide","hover:text-text transition-colors"),children:[a.header,x?.id===a.id?x.dir==="asc"?e.jsx(F,{className:"h-3 w-3"}):e.jsx(L,{className:"h-3 w-3"}):e.jsx(O,{className:"h-3 w-3 opacity-50"})]}):a.header},a.id))]})}),e.jsx(B,{children:N?Array.from({length:k}).map((a,s)=>e.jsxs(u,{children:[t&&e.jsx(b,{}),i.map(c=>e.jsx(b,{className:c.cellClassName,children:e.jsx("div",{className:"h-4 w-3/4 rounded bg-surface-2 animate-pulse"})},c.id))]},`skeleton-${s}`)):r.length===0?e.jsx(u,{children:e.jsx(b,{colSpan:i.length+(t?1:0),className:"p-0",children:y??e.jsx(E,{title:f("states.empty")})})}):r.map((a,s)=>{const c=m(a),o=t&&n.has(c);return e.jsxs(u,{"data-state":o?"selected":void 0,onClick:h?()=>h(a):void 0,className:h?"cursor-pointer":void 0,children:[t&&e.jsx(b,{onClick:d=>d.stopPropagation(),children:e.jsx("input",{type:"checkbox",role:"checkbox","aria-label":f("table.selectRow"),checked:o,onChange:()=>A(c),className:"h-4 w-4 accent-accent cursor-pointer"})}),i.map(d=>e.jsx(b,{className:d.cellClassName,children:d.cell(a,s)},d.id))]},c)})})]})}),e.jsx("div",{className:"md:hidden flex flex-col gap-2",children:N?Array.from({length:Math.min(3,k)}).map((a,s)=>e.jsxs("div",{className:"rounded-md border border-border bg-surface p-3 space-y-2",children:[e.jsx("div",{className:"h-4 w-1/2 rounded bg-surface-2 animate-pulse"}),e.jsx("div",{className:"h-3 w-3/4 rounded bg-surface-2 animate-pulse"}),e.jsx("div",{className:"h-3 w-2/3 rounded bg-surface-2 animate-pulse"})]},`mskel-${s}`)):r.length===0?y??e.jsx(E,{title:f("states.empty")}):r.map((a,s)=>{const c=m(a),o=t&&n.has(c),d=i.find(l=>l.asCardTitle)??i[0],C=i.filter(l=>!l.asCardTitle&&!l.hideOnMobile&&l.id!==d?.id);return e.jsxs("div",{"data-state":o?"selected":void 0,onClick:h?()=>h(a):void 0,className:g("rounded-md border bg-surface p-3",o?"border-accent":"border-border",h&&"cursor-pointer active:bg-surface-hover"),children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[d&&e.jsx("div",{className:"font-medium text-text",children:d.cell(a,s)}),t&&e.jsx("input",{type:"checkbox",role:"checkbox","aria-label":f("table.selectRow"),checked:!!o,onChange:()=>A(c),onClick:l=>l.stopPropagation(),className:"h-4 w-4 accent-accent cursor-pointer mt-0.5"})]}),C.length>0&&e.jsx("dl",{className:"mt-2 grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 text-sm",children:C.map(l=>e.jsxs(P.Fragment,{children:[e.jsx("dt",{className:"text-text-dim",children:l.header}),e.jsx("dd",{className:"text-text",children:l.cell(a,s)})]},l.id))})]},c)})})]})}V.displayName="DataTable";export{V as D};
|
|
7
|
-
//# sourceMappingURL=data-table-
|
|
7
|
+
//# sourceMappingURL=data-table-DElP7TJm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table-yUuGHUSG.js","sources":["../../node_modules/lucide-react/dist/esm/icons/arrow-up-down.js","../../src/components/common/data-table.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.469.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 ArrowUpDown = createLucideIcon(\"ArrowUpDown\", [\n [\"path\", { d: \"m21 16-4 4-4-4\", key: \"f6ql7i\" }],\n [\"path\", { d: \"M17 20V4\", key: \"1ejh1v\" }],\n [\"path\", { d: \"m3 8 4-4 4 4\", key: \"11wl7u\" }],\n [\"path\", { d: \"M7 4v16\", key: \"1glfcx\" }]\n]);\n\nexport { ArrowUpDown as default };\n//# sourceMappingURL=arrow-up-down.js.map\n","/**\n * DataTable<T> — generic table for the M2 list pages (jobs /\n * approvals / reminders / memos). Wraps the primitive Table with:\n *\n * * Type-safe `columns` definition — header label, cell renderer,\n * optional sortable flag, optional className for both header / cell.\n * * Loading state — N skeleton rows so layout doesn't jump.\n * * Empty state — drops in <EmptyState> below the header.\n * * Row selection (optional) — `selection` + `onSelectionChange`;\n * caller manages the Set so it can be URL-state or zustand.\n * * Sort — controlled `sort: { id, dir }` + `onSortChange`. Same\n * rationale as Pagination: the URL is the source of truth.\n * * Mobile fallback — below `md` the table swaps to a vertical card\n * list. Card view uses the same column definitions but stacks\n * label / value pairs instead of a row.\n *\n * What this deliberately does NOT do:\n * * No virtualization. Expected row counts at M2 are ≤ 200; if a\n * page outgrows that, swap the render to react-window from inside\n * here without changing callers.\n * * No column resizing / hiding UX. shadcn columns are static.\n * * No filters. Filters live above the table in a dedicated\n * FilterBar (next-PR concern).\n *\n * Why hand-rolled instead of @tanstack/table-core:\n * For the M2 surface area (4 flat-data pages, ≤ 200 rows each),\n * pulling in a 13 KB head-table dep would add abstraction we don't\n * use. If virtualisation or column-pinning becomes a need, the\n * columns prop here maps 1:1 to tanstack's ColumnDef and we can\n * migrate without changing call sites.\n */\n\nimport * as React from 'react'\nimport { ArrowDown, ArrowUp, ArrowUpDown } from 'lucide-react'\nimport { useTranslation } from 'react-i18next'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@/components/ui/table'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { cn } from '@/lib/utils'\n\nexport type SortDir = 'asc' | 'desc'\n\nexport interface SortState {\n id: string\n dir: SortDir\n}\n\nexport interface DataTableColumn<T> {\n /** Stable id for sort + selection. Usually matches the row key. */\n id: string\n /** Header label. ReactNode so callers can pass <Tooltip> etc. */\n header: React.ReactNode\n /** Cell renderer. Receives the row and its index. */\n cell: (row: T, index: number) => React.ReactNode\n /** When true, the header becomes a sort button. */\n sortable?: boolean\n /** Optional className applied to the <th>. */\n headClassName?: string\n /** Optional className applied to every <td> in this column. */\n cellClassName?: string\n /** Mobile-card variant: when set, this column's value renders\n * prominently as the card's title row. Only one column should\n * use this; the rest become label/value pairs. */\n asCardTitle?: boolean\n /** Hide this column on the mobile card view. */\n hideOnMobile?: boolean\n}\n\nexport interface DataTableProps<T> {\n columns: DataTableColumn<T>[]\n rows: T[]\n /** Stable per-row id. Used for selection + React keys. */\n getRowId: (row: T) => string\n loading?: boolean\n /** Number of skeleton rows to show during loading. Default 5. */\n loadingRows?: number\n /** Empty-state slot. When omitted a default EmptyState renders. */\n emptyState?: React.ReactNode\n /** Click handler for the whole row — opens detail drawer, navigates, etc. */\n onRowClick?: (row: T) => void\n /** Controlled selection. When defined, a checkbox column auto-renders. */\n selection?: Set<string>\n onSelectionChange?: (next: Set<string>) => void\n /** Controlled sort. When omitted, sortable headers stay inert. */\n sort?: SortState | null\n onSortChange?: (next: SortState | null) => void\n className?: string\n}\n\nfunction DataTable<T>({\n columns,\n rows,\n getRowId,\n loading = false,\n loadingRows = 5,\n emptyState,\n onRowClick,\n selection,\n onSelectionChange,\n sort,\n onSortChange,\n className,\n}: DataTableProps<T>): JSX.Element {\n const { t } = useTranslation('common')\n const selectable = selection !== undefined && onSelectionChange !== undefined\n\n const allChecked = selectable && rows.length > 0 && rows.every((r) => selection.has(getRowId(r)))\n const someChecked = selectable && rows.some((r) => selection.has(getRowId(r))) && !allChecked\n\n function toggleAll(): void {\n if (!selectable) return\n const next = new Set(selection)\n if (allChecked) {\n for (const r of rows) next.delete(getRowId(r))\n } else {\n for (const r of rows) next.add(getRowId(r))\n }\n onSelectionChange(next)\n }\n\n function toggleRow(id: string): void {\n if (!selectable) return\n const next = new Set(selection)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n onSelectionChange(next)\n }\n\n function toggleSort(colId: string): void {\n if (!onSortChange) return\n if (!sort || sort.id !== colId) {\n onSortChange({ id: colId, dir: 'asc' })\n } else if (sort.dir === 'asc') {\n onSortChange({ id: colId, dir: 'desc' })\n } else {\n onSortChange(null)\n }\n }\n\n return (\n <div className={cn('w-full', className)}>\n {/* Desktop / tablet — table view */}\n <div className=\"hidden md:block\">\n <Table>\n <TableHeader>\n <TableRow>\n {selectable && (\n <TableHead className=\"w-10\">\n <input\n type=\"checkbox\"\n role=\"checkbox\"\n aria-label={t('table.selectAll')}\n aria-checked={someChecked ? 'mixed' : allChecked}\n checked={allChecked}\n ref={(el) => {\n if (el) el.indeterminate = someChecked\n }}\n onChange={toggleAll}\n disabled={loading || rows.length === 0}\n className=\"h-4 w-4 accent-accent cursor-pointer\"\n />\n </TableHead>\n )}\n {columns.map((c) => (\n <TableHead key={c.id} className={c.headClassName}>\n {c.sortable && onSortChange ? (\n <button\n type=\"button\"\n onClick={() => toggleSort(c.id)}\n className={cn(\n 'inline-flex items-center gap-1',\n 'uppercase tracking-wide',\n 'hover:text-text transition-colors',\n )}\n >\n {c.header}\n {sort?.id === c.id ? (\n sort.dir === 'asc' ? <ArrowUp className=\"h-3 w-3\" /> : <ArrowDown className=\"h-3 w-3\" />\n ) : (\n <ArrowUpDown className=\"h-3 w-3 opacity-50\" />\n )}\n </button>\n ) : (\n c.header\n )}\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {loading\n ? Array.from({ length: loadingRows }).map((_, i) => (\n <TableRow key={`skeleton-${i}`}>\n {selectable && <TableCell />}\n {columns.map((c) => (\n <TableCell key={c.id} className={c.cellClassName}>\n <div className=\"h-4 w-3/4 rounded bg-surface-2 animate-pulse\" />\n </TableCell>\n ))}\n </TableRow>\n ))\n : rows.length === 0\n ? (\n <TableRow>\n <TableCell\n colSpan={columns.length + (selectable ? 1 : 0)}\n className=\"p-0\"\n >\n {emptyState ?? <EmptyState title={t('states.empty')} />}\n </TableCell>\n </TableRow>\n )\n : rows.map((row, i) => {\n const id = getRowId(row)\n const isSelected = selectable && selection.has(id)\n return (\n <TableRow\n key={id}\n data-state={isSelected ? 'selected' : undefined}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n className={onRowClick ? 'cursor-pointer' : undefined}\n >\n {selectable && (\n <TableCell onClick={(e) => e.stopPropagation()}>\n <input\n type=\"checkbox\"\n role=\"checkbox\"\n aria-label={t('table.selectRow')}\n checked={isSelected}\n onChange={() => toggleRow(id)}\n className=\"h-4 w-4 accent-accent cursor-pointer\"\n />\n </TableCell>\n )}\n {columns.map((c) => (\n <TableCell key={c.id} className={c.cellClassName}>\n {c.cell(row, i)}\n </TableCell>\n ))}\n </TableRow>\n )\n })}\n </TableBody>\n </Table>\n </div>\n\n {/* Mobile — card view */}\n <div className=\"md:hidden flex flex-col gap-2\">\n {loading\n ? Array.from({ length: Math.min(3, loadingRows) }).map((_, i) => (\n <div\n key={`mskel-${i}`}\n className=\"rounded-md border border-border bg-surface p-3 space-y-2\"\n >\n <div className=\"h-4 w-1/2 rounded bg-surface-2 animate-pulse\" />\n <div className=\"h-3 w-3/4 rounded bg-surface-2 animate-pulse\" />\n <div className=\"h-3 w-2/3 rounded bg-surface-2 animate-pulse\" />\n </div>\n ))\n : rows.length === 0\n ? (emptyState ?? <EmptyState title={t('states.empty')} />)\n : rows.map((row, i) => {\n const id = getRowId(row)\n const isSelected = selectable && selection.has(id)\n const titleCol = columns.find((c) => c.asCardTitle) ?? columns[0]\n const fieldCols = columns.filter((c) => !c.asCardTitle && !c.hideOnMobile && c.id !== titleCol?.id)\n return (\n <div\n key={id}\n data-state={isSelected ? 'selected' : undefined}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n className={cn(\n 'rounded-md border bg-surface p-3',\n isSelected ? 'border-accent' : 'border-border',\n onRowClick && 'cursor-pointer active:bg-surface-hover',\n )}\n >\n <div className=\"flex items-start justify-between gap-2\">\n {titleCol && (\n <div className=\"font-medium text-text\">{titleCol.cell(row, i)}</div>\n )}\n {selectable && (\n <input\n type=\"checkbox\"\n role=\"checkbox\"\n aria-label={t('table.selectRow')}\n checked={!!isSelected}\n onChange={() => toggleRow(id)}\n onClick={(e) => e.stopPropagation()}\n className=\"h-4 w-4 accent-accent cursor-pointer mt-0.5\"\n />\n )}\n </div>\n {fieldCols.length > 0 && (\n <dl className=\"mt-2 grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 text-sm\">\n {fieldCols.map((c) => (\n <React.Fragment key={c.id}>\n <dt className=\"text-text-dim\">{c.header}</dt>\n <dd className=\"text-text\">{c.cell(row, i)}</dd>\n </React.Fragment>\n ))}\n </dl>\n )}\n </div>\n )\n })}\n </div>\n </div>\n )\n}\nDataTable.displayName = 'DataTable'\n\nexport { DataTable }\n"],"names":["ArrowUpDown","createLucideIcon","DataTable","columns","rows","getRowId","loading","loadingRows","emptyState","onRowClick","selection","onSelectionChange","sort","onSortChange","className","t","useTranslation","selectable","allChecked","r","someChecked","toggleAll","next","toggleRow","id","toggleSort","colId","cn","jsx","jsxs","Table","TableHeader","TableRow","TableHead","el","c","ArrowUp","ArrowDown","TableBody","_","i","TableCell","EmptyState","row","isSelected","e","titleCol","fieldCols","React.Fragment"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"data-table-DElP7TJm.js","sources":["../../node_modules/lucide-react/dist/esm/icons/arrow-up-down.js","../../src/components/common/data-table.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.469.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 ArrowUpDown = createLucideIcon(\"ArrowUpDown\", [\n [\"path\", { d: \"m21 16-4 4-4-4\", key: \"f6ql7i\" }],\n [\"path\", { d: \"M17 20V4\", key: \"1ejh1v\" }],\n [\"path\", { d: \"m3 8 4-4 4 4\", key: \"11wl7u\" }],\n [\"path\", { d: \"M7 4v16\", key: \"1glfcx\" }]\n]);\n\nexport { ArrowUpDown as default };\n//# sourceMappingURL=arrow-up-down.js.map\n","/**\n * DataTable<T> — generic table for the M2 list pages (jobs /\n * approvals / reminders / memos). Wraps the primitive Table with:\n *\n * * Type-safe `columns` definition — header label, cell renderer,\n * optional sortable flag, optional className for both header / cell.\n * * Loading state — N skeleton rows so layout doesn't jump.\n * * Empty state — drops in <EmptyState> below the header.\n * * Row selection (optional) — `selection` + `onSelectionChange`;\n * caller manages the Set so it can be URL-state or zustand.\n * * Sort — controlled `sort: { id, dir }` + `onSortChange`. Same\n * rationale as Pagination: the URL is the source of truth.\n * * Mobile fallback — below `md` the table swaps to a vertical card\n * list. Card view uses the same column definitions but stacks\n * label / value pairs instead of a row.\n *\n * What this deliberately does NOT do:\n * * No virtualization. Expected row counts at M2 are ≤ 200; if a\n * page outgrows that, swap the render to react-window from inside\n * here without changing callers.\n * * No column resizing / hiding UX. shadcn columns are static.\n * * No filters. Filters live above the table in a dedicated\n * FilterBar (next-PR concern).\n *\n * Why hand-rolled instead of @tanstack/table-core:\n * For the M2 surface area (4 flat-data pages, ≤ 200 rows each),\n * pulling in a 13 KB head-table dep would add abstraction we don't\n * use. If virtualisation or column-pinning becomes a need, the\n * columns prop here maps 1:1 to tanstack's ColumnDef and we can\n * migrate without changing call sites.\n */\n\nimport * as React from 'react'\nimport { ArrowDown, ArrowUp, ArrowUpDown } from 'lucide-react'\nimport { useTranslation } from 'react-i18next'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@/components/ui/table'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { cn } from '@/lib/utils'\n\nexport type SortDir = 'asc' | 'desc'\n\nexport interface SortState {\n id: string\n dir: SortDir\n}\n\nexport interface DataTableColumn<T> {\n /** Stable id for sort + selection. Usually matches the row key. */\n id: string\n /** Header label. ReactNode so callers can pass <Tooltip> etc. */\n header: React.ReactNode\n /** Cell renderer. Receives the row and its index. */\n cell: (row: T, index: number) => React.ReactNode\n /** When true, the header becomes a sort button. */\n sortable?: boolean\n /** Optional className applied to the <th>. */\n headClassName?: string\n /** Optional className applied to every <td> in this column. */\n cellClassName?: string\n /** Mobile-card variant: when set, this column's value renders\n * prominently as the card's title row. Only one column should\n * use this; the rest become label/value pairs. */\n asCardTitle?: boolean\n /** Hide this column on the mobile card view. */\n hideOnMobile?: boolean\n}\n\nexport interface DataTableProps<T> {\n columns: DataTableColumn<T>[]\n rows: T[]\n /** Stable per-row id. Used for selection + React keys. */\n getRowId: (row: T) => string\n loading?: boolean\n /** Number of skeleton rows to show during loading. Default 5. */\n loadingRows?: number\n /** Empty-state slot. When omitted a default EmptyState renders. */\n emptyState?: React.ReactNode\n /** Click handler for the whole row — opens detail drawer, navigates, etc. */\n onRowClick?: (row: T) => void\n /** Controlled selection. When defined, a checkbox column auto-renders. */\n selection?: Set<string>\n onSelectionChange?: (next: Set<string>) => void\n /** Controlled sort. When omitted, sortable headers stay inert. */\n sort?: SortState | null\n onSortChange?: (next: SortState | null) => void\n className?: string\n}\n\nfunction DataTable<T>({\n columns,\n rows,\n getRowId,\n loading = false,\n loadingRows = 5,\n emptyState,\n onRowClick,\n selection,\n onSelectionChange,\n sort,\n onSortChange,\n className,\n}: DataTableProps<T>): JSX.Element {\n const { t } = useTranslation('common')\n const selectable = selection !== undefined && onSelectionChange !== undefined\n\n const allChecked = selectable && rows.length > 0 && rows.every((r) => selection.has(getRowId(r)))\n const someChecked = selectable && rows.some((r) => selection.has(getRowId(r))) && !allChecked\n\n function toggleAll(): void {\n if (!selectable) return\n const next = new Set(selection)\n if (allChecked) {\n for (const r of rows) next.delete(getRowId(r))\n } else {\n for (const r of rows) next.add(getRowId(r))\n }\n onSelectionChange(next)\n }\n\n function toggleRow(id: string): void {\n if (!selectable) return\n const next = new Set(selection)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n onSelectionChange(next)\n }\n\n function toggleSort(colId: string): void {\n if (!onSortChange) return\n if (!sort || sort.id !== colId) {\n onSortChange({ id: colId, dir: 'asc' })\n } else if (sort.dir === 'asc') {\n onSortChange({ id: colId, dir: 'desc' })\n } else {\n onSortChange(null)\n }\n }\n\n return (\n <div className={cn('w-full', className)}>\n {/* Desktop / tablet — table view */}\n <div className=\"hidden md:block\">\n <Table>\n <TableHeader>\n <TableRow>\n {selectable && (\n <TableHead className=\"w-10\">\n <input\n type=\"checkbox\"\n role=\"checkbox\"\n aria-label={t('table.selectAll')}\n aria-checked={someChecked ? 'mixed' : allChecked}\n checked={allChecked}\n ref={(el) => {\n if (el) el.indeterminate = someChecked\n }}\n onChange={toggleAll}\n disabled={loading || rows.length === 0}\n className=\"h-4 w-4 accent-accent cursor-pointer\"\n />\n </TableHead>\n )}\n {columns.map((c) => (\n <TableHead key={c.id} className={c.headClassName}>\n {c.sortable && onSortChange ? (\n <button\n type=\"button\"\n onClick={() => toggleSort(c.id)}\n className={cn(\n 'inline-flex items-center gap-1',\n 'uppercase tracking-wide',\n 'hover:text-text transition-colors',\n )}\n >\n {c.header}\n {sort?.id === c.id ? (\n sort.dir === 'asc' ? <ArrowUp className=\"h-3 w-3\" /> : <ArrowDown className=\"h-3 w-3\" />\n ) : (\n <ArrowUpDown className=\"h-3 w-3 opacity-50\" />\n )}\n </button>\n ) : (\n c.header\n )}\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {loading\n ? Array.from({ length: loadingRows }).map((_, i) => (\n <TableRow key={`skeleton-${i}`}>\n {selectable && <TableCell />}\n {columns.map((c) => (\n <TableCell key={c.id} className={c.cellClassName}>\n <div className=\"h-4 w-3/4 rounded bg-surface-2 animate-pulse\" />\n </TableCell>\n ))}\n </TableRow>\n ))\n : rows.length === 0\n ? (\n <TableRow>\n <TableCell\n colSpan={columns.length + (selectable ? 1 : 0)}\n className=\"p-0\"\n >\n {emptyState ?? <EmptyState title={t('states.empty')} />}\n </TableCell>\n </TableRow>\n )\n : rows.map((row, i) => {\n const id = getRowId(row)\n const isSelected = selectable && selection.has(id)\n return (\n <TableRow\n key={id}\n data-state={isSelected ? 'selected' : undefined}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n className={onRowClick ? 'cursor-pointer' : undefined}\n >\n {selectable && (\n <TableCell onClick={(e) => e.stopPropagation()}>\n <input\n type=\"checkbox\"\n role=\"checkbox\"\n aria-label={t('table.selectRow')}\n checked={isSelected}\n onChange={() => toggleRow(id)}\n className=\"h-4 w-4 accent-accent cursor-pointer\"\n />\n </TableCell>\n )}\n {columns.map((c) => (\n <TableCell key={c.id} className={c.cellClassName}>\n {c.cell(row, i)}\n </TableCell>\n ))}\n </TableRow>\n )\n })}\n </TableBody>\n </Table>\n </div>\n\n {/* Mobile — card view */}\n <div className=\"md:hidden flex flex-col gap-2\">\n {loading\n ? Array.from({ length: Math.min(3, loadingRows) }).map((_, i) => (\n <div\n key={`mskel-${i}`}\n className=\"rounded-md border border-border bg-surface p-3 space-y-2\"\n >\n <div className=\"h-4 w-1/2 rounded bg-surface-2 animate-pulse\" />\n <div className=\"h-3 w-3/4 rounded bg-surface-2 animate-pulse\" />\n <div className=\"h-3 w-2/3 rounded bg-surface-2 animate-pulse\" />\n </div>\n ))\n : rows.length === 0\n ? (emptyState ?? <EmptyState title={t('states.empty')} />)\n : rows.map((row, i) => {\n const id = getRowId(row)\n const isSelected = selectable && selection.has(id)\n const titleCol = columns.find((c) => c.asCardTitle) ?? columns[0]\n const fieldCols = columns.filter((c) => !c.asCardTitle && !c.hideOnMobile && c.id !== titleCol?.id)\n return (\n <div\n key={id}\n data-state={isSelected ? 'selected' : undefined}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n className={cn(\n 'rounded-md border bg-surface p-3',\n isSelected ? 'border-accent' : 'border-border',\n onRowClick && 'cursor-pointer active:bg-surface-hover',\n )}\n >\n <div className=\"flex items-start justify-between gap-2\">\n {titleCol && (\n <div className=\"font-medium text-text\">{titleCol.cell(row, i)}</div>\n )}\n {selectable && (\n <input\n type=\"checkbox\"\n role=\"checkbox\"\n aria-label={t('table.selectRow')}\n checked={!!isSelected}\n onChange={() => toggleRow(id)}\n onClick={(e) => e.stopPropagation()}\n className=\"h-4 w-4 accent-accent cursor-pointer mt-0.5\"\n />\n )}\n </div>\n {fieldCols.length > 0 && (\n <dl className=\"mt-2 grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 text-sm\">\n {fieldCols.map((c) => (\n <React.Fragment key={c.id}>\n <dt className=\"text-text-dim\">{c.header}</dt>\n <dd className=\"text-text\">{c.cell(row, i)}</dd>\n </React.Fragment>\n ))}\n </dl>\n )}\n </div>\n )\n })}\n </div>\n </div>\n )\n}\nDataTable.displayName = 'DataTable'\n\nexport { DataTable }\n"],"names":["ArrowUpDown","createLucideIcon","DataTable","columns","rows","getRowId","loading","loadingRows","emptyState","onRowClick","selection","onSelectionChange","sort","onSortChange","className","t","useTranslation","selectable","allChecked","r","someChecked","toggleAll","next","toggleRow","id","toggleSort","colId","cn","jsx","jsxs","Table","TableHeader","TableRow","TableHead","el","c","ArrowUp","ArrowDown","TableBody","_","i","TableCell","EmptyState","row","isSelected","e","titleCol","fieldCols","React.Fragment"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import{o as q,u as P,a6 as J,a7 as K,j as e,l as O,B,S as I,g as _,h as L,i as E,k as u,a8 as W,m as g,n as U,L as Z,I as $,c as ee}from"./index-CzlhMSb2.js";import{r as h}from"./react-DlP5eolq.js";import{u as se,a as te,b as le}from"./use-settings-DZhfMpNR.js";import{L as R}from"./loader-circle-AgQ2XO06.js";import{S as ne}from"./save-xBMgs6Bd.js";import{i as ae,j as ie}from"./use-memory-DncmZXGJ.js";import{R as re}from"./refresh-ccw-CM-Cjwud.js";import{P as oe}from"./play-DQ3P_XWl.js";/**
|
|
2
|
+
* @license lucide-react v0.469.0 - ISC
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the ISC license.
|
|
5
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/const de=q("AlarmClockCheck",[["circle",{cx:"12",cy:"13",r:"8",key:"3y4lt7"}],["path",{d:"M5 3 2 6",key:"18tl5t"}],["path",{d:"m22 6-3-3",key:"1opdir"}],["path",{d:"M6.38 18.7 4 21",key:"17xu3x"}],["path",{d:"M17.64 18.67 20 21",key:"kv2oe2"}],["path",{d:"m9 13 2 2 4-4",key:"6343dt"}]]),S={intervalMs:"300000",floorMin:"30",batchMax:"20",maxPending:"200"};function ce(n){const s=(n??"1").trim().toLowerCase();return s!=="0"&&s!=="false"&&s!=="no"&&s!=="off"}function me(n){const s=(n||"auto").toLowerCase();return s==="agent"||s==="llm"?s:"auto"}function ue({onSaved:n}){const{t:s}=P(["memory","common"]),a=se({reveal:!1}),r=h.useMemo(()=>a.data?.env??{},[a.data?.env]),p=te(),m=J(),d=p.data?.agents??[],x=m.data?.backends??[],v=m.data?.roles?.distill??"",k=h.useMemo(()=>()=>({source:me(r.IMHUB_MEMORY_DISTILL_SOURCE),agent:r.IMHUB_MEMORY_DISTILL_AGENT||"",llmBackend:v,enabled:ce(r.IMHUB_MEMORY_DISTILL_ENABLED),intervalMs:r.IMHUB_MEMORY_DISTILL_INTERVAL_MS||"",floorMin:r.IMHUB_MEMORY_DISTILL_FLOOR_MIN||"",batchMax:r.IMHUB_MEMORY_DISTILL_BATCH_MAX||"",maxPending:r.IMHUB_MEMORY_DISTILL_MAX_PENDING||""}),[r,v]),[l,T]=h.useState(k),j=h.useRef(l);h.useEffect(()=>{if(!a.data)return;const t=k();T(t),j.current=t},[a.data,k]);const A=le(),H=K(),w=h.useMemo(()=>{const t=j.current;return Object.keys(l).some(i=>l[i]!==t[i])},[l]);function c(t,i){T(o=>({...o,[t]:i}))}function N(t,i,o){if(!t.trim())return null;const f=Number(t);return!Number.isFinite(f)||f<i?s("distill.form.errors.numRange",{field:o,min:i}):null}function Y(){return l.source==="agent"&&!l.agent.trim()?s("distill.form.errors.agentRequired"):l.source==="llm"&&!l.llmBackend.trim()?s("distill.form.errors.llmRequired"):N(l.intervalMs,1e4,s("distill.form.intervalMs"))??N(l.floorMin,0,s("distill.form.floorMin"))??N(l.batchMax,1,s("distill.form.batchMax"))??N(l.maxPending,1,s("distill.form.maxPending"))}function F(){const t=j.current,i={},o=(f,M,X)=>{M!==X&&(i[f]=M.trim()===""?null:M.trim())};return l.source!==t.source&&(i.IMHUB_MEMORY_DISTILL_SOURCE=l.source==="auto"?null:l.source),l.enabled!==t.enabled&&(i.IMHUB_MEMORY_DISTILL_ENABLED=l.enabled?"1":"0"),l.source==="agent"?o("IMHUB_MEMORY_DISTILL_AGENT",l.agent,t.agent):t.agent&&(i.IMHUB_MEMORY_DISTILL_AGENT=null),o("IMHUB_MEMORY_DISTILL_INTERVAL_MS",l.intervalMs,t.intervalMs),o("IMHUB_MEMORY_DISTILL_FLOOR_MIN",l.floorMin,t.floorMin),o("IMHUB_MEMORY_DISTILL_BATCH_MAX",l.batchMax,t.batchMax),o("IMHUB_MEMORY_DISTILL_MAX_PENDING",l.maxPending,t.maxPending),i}async function V(){const t=Y();if(t){g.error(t);return}const i=F(),o=l.source==="llm"&&l.llmBackend.trim()!==""&&l.llmBackend!==j.current.llmBackend;if(Object.keys(i).length===0&&!o){g.info(s("distill.form.nothingChanged"));return}try{Object.keys(i).length>0&&await A.mutateAsync({updates:i}),o&&await H.mutateAsync({distill:l.llmBackend.trim()}),g.success(s("distill.form.savedToast")),n?.()}catch(f){const{message:M}=U(f,s);g.error(M)}}function G(){T(j.current)}const C=A.isPending||H.isPending,z=x.length===0,Q=d.length===0;return e.jsxs("div",{className:"rounded-md border border-border bg-surface p-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("h2",{className:"text-sm font-medium",children:s("distill.form.title")}),w&&e.jsx(O,{variant:"info",children:s("distill.form.dirty")}),e.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[w&&e.jsx(B,{type:"button",variant:"secondary",size:"sm",onClick:G,disabled:C,children:s("distill.form.discard")}),e.jsxs(B,{type:"button",size:"sm",onClick:()=>void V(),disabled:!w||C,children:[C?e.jsx(R,{className:"h-4 w-4 animate-spin"}):e.jsx(ne,{className:"h-4 w-4"}),s("distill.form.save")]})]})]}),e.jsx("p",{className:"mt-1 text-xs text-text-dim",children:s("distill.form.hint")}),a.isLoading?e.jsx("div",{className:"mt-3 h-32 w-full rounded-md bg-surface-2 animate-pulse"}):e.jsxs("div",{className:"mt-3 flex flex-col gap-4",children:[e.jsxs("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsx(b,{label:s("distill.form.source"),help:s("distill.form.sourceHelp"),children:e.jsxs(I,{value:l.source,onValueChange:t=>c("source",t),children:[e.jsx(_,{children:e.jsx(L,{})}),e.jsxs(E,{children:[e.jsx(u,{value:"auto",children:s("distill.form.sourceAuto")}),e.jsx(u,{value:"agent",children:s("distill.form.sourceAgent")}),e.jsx(u,{value:"llm",children:s("distill.form.sourceLlm")})]})]})}),l.source==="auto"&&e.jsx("div",{className:"flex items-end",children:e.jsx("p",{className:"text-[11px] text-text-muted",children:s("distill.form.autoNote")})}),l.source==="agent"&&e.jsx(b,{label:s("distill.form.agent"),help:s("distill.form.agentHelp"),children:Q?e.jsx("p",{className:"text-[11px] text-warning",children:s("distill.form.noAgents")}):e.jsxs(I,{value:l.agent,onValueChange:t=>c("agent",t),children:[e.jsx(_,{children:e.jsx(L,{placeholder:s("distill.form.agentPlaceholder")})}),e.jsx(E,{children:d.map(t=>e.jsx(u,{value:t,children:W(t)},t))})]})}),l.source==="llm"&&e.jsx(b,{label:s("distill.form.llmBackend"),help:s("distill.form.llmBackendHelp"),children:z?e.jsx("p",{className:"text-[11px] text-warning",children:s("distill.form.noBackends")}):e.jsxs(I,{value:l.llmBackend,onValueChange:t=>c("llmBackend",t),children:[e.jsx(_,{children:e.jsx(L,{placeholder:s("distill.form.llmPlaceholder")})}),e.jsx(E,{children:x.map(t=>e.jsxs(u,{value:t.name,children:[t.name," ",e.jsxs("span",{className:"text-text-muted",children:["· ",t.model]})]},t.name))})]})})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs font-medium text-text-dim",children:s("distill.form.scheduleTitle")}),e.jsxs("div",{className:"mt-2 grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsx(b,{label:s("distill.form.enabled"),help:s("distill.form.enabledHelp"),children:e.jsxs(I,{value:l.enabled?"on":"off",onValueChange:t=>c("enabled",t==="on"),children:[e.jsx(_,{children:e.jsx(L,{})}),e.jsxs(E,{children:[e.jsx(u,{value:"on",children:s("distill.form.enabledOn")}),e.jsx(u,{value:"off",children:s("distill.form.enabledOff")})]})]})}),e.jsx(y,{label:s("distill.form.intervalMs"),help:s("distill.form.intervalMsHelp"),value:l.intervalMs,placeholder:S.intervalMs,min:1e4,step:1e4,onChange:t=>c("intervalMs",t)}),e.jsx(y,{label:s("distill.form.floorMin"),help:s("distill.form.floorMinHelp"),value:l.floorMin,placeholder:S.floorMin,min:0,step:5,onChange:t=>c("floorMin",t)}),e.jsx(y,{label:s("distill.form.batchMax"),help:s("distill.form.batchMaxHelp"),value:l.batchMax,placeholder:S.batchMax,min:1,step:1,onChange:t=>c("batchMax",t)}),e.jsx(y,{label:s("distill.form.maxPending"),help:s("distill.form.maxPendingHelp"),value:l.maxPending,placeholder:S.maxPending,min:1,step:10,onChange:t=>c("maxPending",t)})]})]})]})]})}function b({label:n,help:s,children:a}){return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(Z,{className:"text-xs text-text-dim",children:n}),a,s&&e.jsx("p",{className:"text-[11px] text-text-muted",children:s})]})}function y({label:n,help:s,value:a,placeholder:r,min:p,step:m,onChange:d}){return e.jsx(b,{label:n,help:s,children:e.jsx($,{type:"number",min:p,step:m,value:a,placeholder:r,onChange:x=>d(x.target.value),className:"font-mono text-xs"})})}function Ie(){const{t:n}=P(["memory","common"]),s=ae(),a=s.data,r=ie();async function p(){try{await r.mutateAsync(),g.success(n("distill.actions.runStarted"))}catch(x){const{message:v}=U(x,n);g.error(v)}}const m=!!a?.running,d=a?.pendingTotal??0;return e.jsxs("div",{className:"mx-auto flex max-w-5xl flex-col gap-4",children:[e.jsxs("header",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("h1",{className:"text-xl font-semibold",children:n("distill.title")}),e.jsxs(B,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>s.refetch(),disabled:s.isFetching,"aria-label":n("actions.refresh",{ns:"common"}),children:[s.isFetching?e.jsx(R,{className:"h-4 w-4 animate-spin"}):e.jsx(re,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:n("actions.refresh",{ns:"common"})})]})]}),e.jsx("p",{className:"text-sm text-text-dim",children:n("distill.subtitle")})]}),e.jsx(ue,{onSaved:()=>void s.refetch()}),e.jsxs("div",{className:"rounded-md border border-border bg-surface p-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-sm",children:[e.jsx("span",{className:"font-medium",children:n("distill.status.title")}),e.jsx(O,{variant:a?.enabled?"success":"secondary",children:a?.enabled?n("distill.status.enabledTrue"):n("distill.status.enabledFalse")}),m&&e.jsxs(O,{variant:"info",children:[e.jsx(R,{className:"mr-1 inline h-3 w-3 animate-spin"}),n("distill.status.running")]}),e.jsx("div",{className:"ml-auto",children:e.jsxs(B,{variant:"default",size:"sm",onClick:()=>void p(),disabled:r.isPending||m||!a?.enabled,children:[r.isPending?e.jsx(R,{className:"h-4 w-4 animate-spin"}):e.jsx(oe,{className:"h-4 w-4"}),n("distill.actions.runNow")]})})]}),s.isLoading?e.jsx("div",{className:"mt-3 h-20 w-full rounded-md bg-surface-2 animate-pulse"}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mt-3 grid grid-cols-2 gap-2 sm:grid-cols-3",children:[e.jsx(D,{label:n("distill.status.pending"),value:d,tone:d>0?"warning":"success"}),e.jsx(D,{label:n("distill.status.lastProcessed"),value:a?.lastProcessed??0,tone:"info"}),e.jsx(D,{label:n("distill.status.lastRun"),value:fe(a?.lastRunAt),tone:"info"})]}),d===0&&e.jsxs("p",{className:"mt-2 flex items-center gap-1 text-xs text-text-muted",children:[e.jsx(de,{className:"h-3 w-3"}),n("distill.status.bufferEmpty")]}),a?.lastError&&e.jsxs("p",{className:"mt-2 text-xs text-danger break-all",children:[n("distill.status.lastError"),": ",a.lastError]})]})]})]})}const xe={info:"border-info/30 text-info",success:"border-success/30 text-success",warning:"border-warning/30 text-warning",danger:"border-danger/30 text-danger"};function D({label:n,value:s,tone:a}){return e.jsxs("div",{className:ee("rounded-md border bg-bg px-2 py-2",xe[a]),children:[e.jsx("div",{className:"text-[10px] uppercase tracking-wide text-text-dim",children:n}),e.jsx("div",{className:"text-xl font-semibold tabular-nums",children:s})]})}function fe(n){if(!n)return"—";try{const s=new Date(n);return Number.isNaN(s.getTime())?String(n):s.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return String(n)}}export{Ie as default};
|
|
7
|
+
//# sourceMappingURL=distill-DxSq7g_8.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"distill-DxSq7g_8.js","sources":["../../node_modules/lucide-react/dist/esm/icons/alarm-clock-check.js","../../src/routes/memory/distill-config-form.tsx","../../src/routes/memory/distill.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.469.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 AlarmClockCheck = createLucideIcon(\"AlarmClockCheck\", [\n [\"circle\", { cx: \"12\", cy: \"13\", r: \"8\", key: \"3y4lt7\" }],\n [\"path\", { d: \"M5 3 2 6\", key: \"18tl5t\" }],\n [\"path\", { d: \"m22 6-3-3\", key: \"1opdir\" }],\n [\"path\", { d: \"M6.38 18.7 4 21\", key: \"17xu3x\" }],\n [\"path\", { d: \"M17.64 18.67 20 21\", key: \"kv2oe2\" }],\n [\"path\", { d: \"m9 13 2 2 4-4\", key: \"6343dt\" }]\n]);\n\nexport { AlarmClockCheck as default };\n//# sourceMappingURL=alarm-clock-check.js.map\n","/**\n * DistillConfigForm — inline editor for the \"dream distillation\"\n * scheduler (memory-distiller.ts + memory-distill.ts).\n *\n * Two things the operator configures here:\n *\n * 1. SOURCE — which LLM extracts facts from buffered turns:\n * auto → the turn's own agent (zero-config default; nothing else\n * to set). Recommended for most installs.\n * agent → a specific, already-enabled agent CLI\n * (IMHUB_MEMORY_DISTILL_AGENT).\n * llm → a standalone LLM backend bound to the `distill` role,\n * configured exactly like the native agent's LLM\n * (PUT /api/llm/roles { distill }). No CLI spawn.\n *\n * 2. SCHEDULE — the cadence knobs (enabled / interval / staleness\n * floor / batch size / per-user buffer cap), all IMHUB_MEMORY_DISTILL_*\n * env keys behind the server allowlist.\n *\n * Save flow mirrors vector-backend-form: diff against the last-loaded\n * values, PUT /api/env for the env keys, and — only when source=llm and\n * the chosen backend changed — PUT /api/llm/roles to (re)bind the\n * distill role. Empty agent / backend selections are validated before\n * save so we never persist a half-configured source.\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Loader2, Save } from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { useEnv, useUpdateEnv, useConfig } from '@/hooks/use-settings'\nimport { useLlmList, useLlmPutRoles } from '@/hooks/use-llm-admin'\nimport { describeError } from '@/lib/api/errors'\nimport { agentDisplayName } from '@/lib/agent-label'\n\ntype DistillSource = 'auto' | 'agent' | 'llm'\n\ninterface FormState {\n source: DistillSource\n agent: string // IMHUB_MEMORY_DISTILL_AGENT (source=agent)\n llmBackend: string // llmRoles.distill backend name (source=llm)\n enabled: boolean // IMHUB_MEMORY_DISTILL_ENABLED\n intervalMs: string // IMHUB_MEMORY_DISTILL_INTERVAL_MS\n floorMin: string // IMHUB_MEMORY_DISTILL_FLOOR_MIN\n batchMax: string // IMHUB_MEMORY_DISTILL_BATCH_MAX\n maxPending: string // IMHUB_MEMORY_DISTILL_MAX_PENDING\n}\n\n// Mirror of the memory-distiller.ts defaults so placeholders match the\n// runtime fallbacks when a key is unset.\nconst DEFAULTS = {\n intervalMs: '300000',\n floorMin: '30',\n batchMax: '20',\n maxPending: '200',\n} as const\n\nfunction readEnabled(raw: string | undefined): boolean {\n const v = (raw ?? '1').trim().toLowerCase()\n return v !== '0' && v !== 'false' && v !== 'no' && v !== 'off'\n}\n\nfunction readSource(raw: string | undefined): DistillSource {\n const v = (raw || 'auto').toLowerCase()\n return v === 'agent' || v === 'llm' ? v : 'auto'\n}\n\nexport interface DistillConfigFormProps {\n /** Called after a successful save so the parent can refresh status. */\n onSaved?: () => void\n}\n\nexport function DistillConfigForm({ onSaved }: DistillConfigFormProps): JSX.Element {\n const { t } = useTranslation(['memory', 'common'])\n\n const envQuery = useEnv({ reveal: false })\n const env = useMemo(() => envQuery.data?.env ?? {}, [envQuery.data?.env])\n const cfgQuery = useConfig()\n const llmQuery = useLlmList()\n\n const enabledAgents = cfgQuery.data?.agents ?? []\n const llmBackends = llmQuery.data?.backends ?? []\n const currentDistillRole = llmQuery.data?.roles?.distill ?? ''\n\n const readForm = useMemo<() => FormState>(() => () => ({\n source: readSource(env.IMHUB_MEMORY_DISTILL_SOURCE),\n agent: env.IMHUB_MEMORY_DISTILL_AGENT || '',\n llmBackend: currentDistillRole,\n enabled: readEnabled(env.IMHUB_MEMORY_DISTILL_ENABLED),\n intervalMs: env.IMHUB_MEMORY_DISTILL_INTERVAL_MS || '',\n floorMin: env.IMHUB_MEMORY_DISTILL_FLOOR_MIN || '',\n batchMax: env.IMHUB_MEMORY_DISTILL_BATCH_MAX || '',\n maxPending: env.IMHUB_MEMORY_DISTILL_MAX_PENDING || '',\n }), [env, currentDistillRole])\n\n const [form, setForm] = useState<FormState>(readForm)\n const initialRef = useRef<FormState>(form)\n\n // Re-seed from server once the env + llm roles have both loaded (and on\n // any later refetch). useEffect so we don't stomp mid-edit on every render.\n useEffect(() => {\n if (!envQuery.data) return\n const next = readForm()\n setForm(next)\n initialRef.current = next\n }, [envQuery.data, readForm])\n\n const updateEnv = useUpdateEnv()\n const putRoles = useLlmPutRoles()\n\n const dirty = useMemo(() => {\n const initial = initialRef.current\n return (Object.keys(form) as Array<keyof FormState>).some((k) => form[k] !== initial[k])\n }, [form])\n\n function set<K extends keyof FormState>(k: K, v: FormState[K]): void {\n setForm((prev) => ({ ...prev, [k]: v }))\n }\n\n function numField(value: string, min: number, label: string): string | null {\n if (!value.trim()) return null\n const n = Number(value)\n if (!Number.isFinite(n) || n < min) return t('distill.form.errors.numRange', { field: label, min })\n return null\n }\n\n function validate(): string | null {\n if (form.source === 'agent' && !form.agent.trim()) {\n return t('distill.form.errors.agentRequired')\n }\n if (form.source === 'llm' && !form.llmBackend.trim()) {\n return t('distill.form.errors.llmRequired')\n }\n return (\n numField(form.intervalMs, 10000, t('distill.form.intervalMs'))\n ?? numField(form.floorMin, 0, t('distill.form.floorMin'))\n ?? numField(form.batchMax, 1, t('distill.form.batchMax'))\n ?? numField(form.maxPending, 1, t('distill.form.maxPending'))\n )\n }\n\n function buildEnvUpdates(): Record<string, string | null> {\n const initial = initialRef.current\n const out: Record<string, string | null> = {}\n const diffStr = (key: string, cur: string, prev: string): void => {\n if (cur === prev) return\n out[key] = cur.trim() === '' ? null : cur.trim()\n }\n if (form.source !== initial.source) {\n // 'auto' is the runtime default → store null to keep env tidy.\n out.IMHUB_MEMORY_DISTILL_SOURCE = form.source === 'auto' ? null : form.source\n }\n if (form.enabled !== initial.enabled) {\n out.IMHUB_MEMORY_DISTILL_ENABLED = form.enabled ? '1' : '0'\n }\n // Only persist the agent name when the chosen source actually uses it,\n // so flipping away from 'agent' doesn't leave a stale key behind.\n if (form.source === 'agent') {\n diffStr('IMHUB_MEMORY_DISTILL_AGENT', form.agent, initial.agent)\n } else if (initial.agent) {\n out.IMHUB_MEMORY_DISTILL_AGENT = null\n }\n diffStr('IMHUB_MEMORY_DISTILL_INTERVAL_MS', form.intervalMs, initial.intervalMs)\n diffStr('IMHUB_MEMORY_DISTILL_FLOOR_MIN', form.floorMin, initial.floorMin)\n diffStr('IMHUB_MEMORY_DISTILL_BATCH_MAX', form.batchMax, initial.batchMax)\n diffStr('IMHUB_MEMORY_DISTILL_MAX_PENDING', form.maxPending, initial.maxPending)\n return out\n }\n\n async function onSave(): Promise<void> {\n const err = validate()\n if (err) { toast.error(err); return }\n\n const envUpdates = buildEnvUpdates()\n const roleChanged = form.source === 'llm'\n && form.llmBackend.trim() !== ''\n && form.llmBackend !== initialRef.current.llmBackend\n\n if (Object.keys(envUpdates).length === 0 && !roleChanged) {\n toast.info(t('distill.form.nothingChanged'))\n return\n }\n\n try {\n if (Object.keys(envUpdates).length > 0) {\n await updateEnv.mutateAsync({ updates: envUpdates })\n }\n if (roleChanged) {\n await putRoles.mutateAsync({ distill: form.llmBackend.trim() })\n }\n toast.success(t('distill.form.savedToast'))\n onSaved?.()\n } catch (serr) {\n const { message } = describeError(serr, t)\n toast.error(message)\n }\n }\n\n function onDiscard(): void {\n setForm(initialRef.current)\n }\n\n const busy = updateEnv.isPending || putRoles.isPending\n const noBackends = llmBackends.length === 0\n const noAgents = enabledAgents.length === 0\n\n return (\n <div className=\"rounded-md border border-border bg-surface p-3\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"text-sm font-medium\">{t('distill.form.title')}</h2>\n {dirty && <Badge variant=\"info\">{t('distill.form.dirty')}</Badge>}\n <div className=\"ml-auto flex items-center gap-2\">\n {dirty && (\n <Button type=\"button\" variant=\"secondary\" size=\"sm\" onClick={onDiscard} disabled={busy}>\n {t('distill.form.discard')}\n </Button>\n )}\n <Button type=\"button\" size=\"sm\" onClick={() => void onSave()} disabled={!dirty || busy}>\n {busy ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Save className=\"h-4 w-4\" />}\n {t('distill.form.save')}\n </Button>\n </div>\n </div>\n <p className=\"mt-1 text-xs text-text-dim\">{t('distill.form.hint')}</p>\n\n {envQuery.isLoading ? (\n <div className=\"mt-3 h-32 w-full rounded-md bg-surface-2 animate-pulse\" />\n ) : (\n <div className=\"mt-3 flex flex-col gap-4\">\n {/* ── Source ── */}\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <Field label={t('distill.form.source')} help={t('distill.form.sourceHelp')}>\n <Select value={form.source} onValueChange={(v) => set('source', v as DistillSource)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"auto\">{t('distill.form.sourceAuto')}</SelectItem>\n <SelectItem value=\"agent\">{t('distill.form.sourceAgent')}</SelectItem>\n <SelectItem value=\"llm\">{t('distill.form.sourceLlm')}</SelectItem>\n </SelectContent>\n </Select>\n </Field>\n\n {form.source === 'auto' && (\n <div className=\"flex items-end\">\n <p className=\"text-[11px] text-text-muted\">{t('distill.form.autoNote')}</p>\n </div>\n )}\n\n {form.source === 'agent' && (\n <Field label={t('distill.form.agent')} help={t('distill.form.agentHelp')}>\n {noAgents ? (\n <p className=\"text-[11px] text-warning\">{t('distill.form.noAgents')}</p>\n ) : (\n <Select value={form.agent} onValueChange={(v) => set('agent', v)}>\n <SelectTrigger>\n <SelectValue placeholder={t('distill.form.agentPlaceholder')} />\n </SelectTrigger>\n <SelectContent>\n {enabledAgents.map((name) => (\n <SelectItem key={name} value={name}>{agentDisplayName(name)}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n </Field>\n )}\n\n {form.source === 'llm' && (\n <Field label={t('distill.form.llmBackend')} help={t('distill.form.llmBackendHelp')}>\n {noBackends ? (\n <p className=\"text-[11px] text-warning\">{t('distill.form.noBackends')}</p>\n ) : (\n <Select value={form.llmBackend} onValueChange={(v) => set('llmBackend', v)}>\n <SelectTrigger>\n <SelectValue placeholder={t('distill.form.llmPlaceholder')} />\n </SelectTrigger>\n <SelectContent>\n {llmBackends.map((b) => (\n <SelectItem key={b.name} value={b.name}>\n {b.name} <span className=\"text-text-muted\">· {b.model}</span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n </Field>\n )}\n </div>\n\n {/* ── Schedule ── */}\n <div>\n <div className=\"text-xs font-medium text-text-dim\">{t('distill.form.scheduleTitle')}</div>\n <div className=\"mt-2 grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <Field label={t('distill.form.enabled')} help={t('distill.form.enabledHelp')}>\n <Select\n value={form.enabled ? 'on' : 'off'}\n onValueChange={(v) => set('enabled', v === 'on')}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"on\">{t('distill.form.enabledOn')}</SelectItem>\n <SelectItem value=\"off\">{t('distill.form.enabledOff')}</SelectItem>\n </SelectContent>\n </Select>\n </Field>\n <NumberField\n label={t('distill.form.intervalMs')}\n help={t('distill.form.intervalMsHelp')}\n value={form.intervalMs}\n placeholder={DEFAULTS.intervalMs}\n min={10000}\n step={10000}\n onChange={(v) => set('intervalMs', v)}\n />\n <NumberField\n label={t('distill.form.floorMin')}\n help={t('distill.form.floorMinHelp')}\n value={form.floorMin}\n placeholder={DEFAULTS.floorMin}\n min={0}\n step={5}\n onChange={(v) => set('floorMin', v)}\n />\n <NumberField\n label={t('distill.form.batchMax')}\n help={t('distill.form.batchMaxHelp')}\n value={form.batchMax}\n placeholder={DEFAULTS.batchMax}\n min={1}\n step={1}\n onChange={(v) => set('batchMax', v)}\n />\n <NumberField\n label={t('distill.form.maxPending')}\n help={t('distill.form.maxPendingHelp')}\n value={form.maxPending}\n placeholder={DEFAULTS.maxPending}\n min={1}\n step={10}\n onChange={(v) => set('maxPending', v)}\n />\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nfunction Field({\n label,\n help,\n children,\n}: {\n label: string\n help?: string\n children: React.ReactNode\n}): JSX.Element {\n return (\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs text-text-dim\">{label}</Label>\n {children}\n {help && <p className=\"text-[11px] text-text-muted\">{help}</p>}\n </div>\n )\n}\n\nfunction NumberField({\n label,\n help,\n value,\n placeholder,\n min,\n step,\n onChange,\n}: {\n label: string\n help?: string\n value: string\n placeholder: string\n min: number\n step: number\n onChange: (v: string) => void\n}): JSX.Element {\n return (\n <Field label={label} help={help}>\n <Input\n type=\"number\"\n min={min}\n step={step}\n value={value}\n placeholder={placeholder}\n onChange={(e) => onChange(e.target.value)}\n className=\"font-mono text-xs\"\n />\n </Field>\n )\n}\n","/**\n * /memory/distill — \"dream distillation\" control surface.\n *\n * Dream distillation buffers every chat turn into pending_distill and\n * batch-extracts facts in the background when the system is idle (or\n * once a user's oldest buffered turn passes the staleness floor). This\n * tab lets the operator:\n *\n * - configure the extraction SOURCE + SCHEDULE (DistillConfigForm)\n * - watch the live buffer depth + last-run telemetry (status tiles)\n * - force a pass now (\"Run now\" → POST /api/memory/distill)\n *\n * Status polls every 3s (useDistillStatus) so a manual run visibly\n * drains `pendingTotal` to zero without a refresh. This view is global\n * (not per-user) — the buffer spans every user — so it ignores the\n * layout's ?user= filter.\n */\n\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { AlarmClockCheck, Loader2, Play, RefreshCcw } from 'lucide-react'\n\nimport { DistillConfigForm } from './distill-config-form'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { useDistillStatus, useTriggerDistill } from '@/hooks/use-memory'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\nexport default function MemoryDistillRoute(): JSX.Element {\n const { t } = useTranslation(['memory', 'common'])\n const statusQuery = useDistillStatus()\n const status = statusQuery.data\n const trigger = useTriggerDistill()\n\n async function onRunNow(): Promise<void> {\n try {\n await trigger.mutateAsync()\n toast.success(t('distill.actions.runStarted'))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n }\n }\n\n const running = !!status?.running\n const pending = status?.pendingTotal ?? 0\n\n return (\n <div className=\"mx-auto flex max-w-5xl flex-col gap-4\">\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('distill.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => statusQuery.refetch()}\n disabled={statusQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {statusQuery.isFetching ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('distill.subtitle')}</p>\n </header>\n\n {/* Configuration */}\n <DistillConfigForm onSaved={() => void statusQuery.refetch()} />\n\n {/* Status + actions */}\n <div className=\"rounded-md border border-border bg-surface p-3\">\n <div className=\"flex flex-wrap items-center gap-2 text-sm\">\n <span className=\"font-medium\">{t('distill.status.title')}</span>\n <Badge variant={status?.enabled ? 'success' : 'secondary'}>\n {status?.enabled ? t('distill.status.enabledTrue') : t('distill.status.enabledFalse')}\n </Badge>\n {running && (\n <Badge variant=\"info\">\n <Loader2 className=\"mr-1 inline h-3 w-3 animate-spin\" />\n {t('distill.status.running')}\n </Badge>\n )}\n <div className=\"ml-auto\">\n <Button\n variant=\"default\"\n size=\"sm\"\n onClick={() => void onRunNow()}\n disabled={trigger.isPending || running || !status?.enabled}\n >\n {trigger.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Play className=\"h-4 w-4\" />}\n {t('distill.actions.runNow')}\n </Button>\n </div>\n </div>\n\n {statusQuery.isLoading ? (\n <div className=\"mt-3 h-20 w-full rounded-md bg-surface-2 animate-pulse\" />\n ) : (\n <>\n <div className=\"mt-3 grid grid-cols-2 gap-2 sm:grid-cols-3\">\n <StatTile label={t('distill.status.pending')} value={pending} tone={pending > 0 ? 'warning' : 'success'} />\n <StatTile label={t('distill.status.lastProcessed')} value={status?.lastProcessed ?? 0} tone=\"info\" />\n <StatTile label={t('distill.status.lastRun')} value={formatEpoch(status?.lastRunAt)} tone=\"info\" />\n </div>\n {pending === 0 && (\n <p className=\"mt-2 flex items-center gap-1 text-xs text-text-muted\">\n <AlarmClockCheck className=\"h-3 w-3\" />\n {t('distill.status.bufferEmpty')}\n </p>\n )}\n {status?.lastError && (\n <p className=\"mt-2 text-xs text-danger break-all\">\n {t('distill.status.lastError')}: {status.lastError}\n </p>\n )}\n </>\n )}\n </div>\n </div>\n )\n}\n\ninterface StatTileProps {\n label: string\n value: number | string\n tone: 'info' | 'success' | 'warning' | 'danger'\n}\n\nconst TONE_STYLES: Record<StatTileProps['tone'], string> = {\n info: 'border-info/30 text-info',\n success: 'border-success/30 text-success',\n warning: 'border-warning/30 text-warning',\n danger: 'border-danger/30 text-danger',\n}\n\nfunction StatTile({ label, value, tone }: StatTileProps): JSX.Element {\n return (\n <div className={cn('rounded-md border bg-bg px-2 py-2', TONE_STYLES[tone])}>\n <div className=\"text-[10px] uppercase tracking-wide text-text-dim\">{label}</div>\n <div className=\"text-xl font-semibold tabular-nums\">{value}</div>\n </div>\n )\n}\n\nfunction formatEpoch(ms: number | null | undefined): string {\n if (!ms) return '—'\n try {\n const d = new Date(ms)\n if (Number.isNaN(d.getTime())) return String(ms)\n return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch {\n return String(ms)\n }\n}\n"],"names":["AlarmClockCheck","createLucideIcon","DEFAULTS","readEnabled","raw","v","readSource","DistillConfigForm","onSaved","t","useTranslation","envQuery","useEnv","env","useMemo","cfgQuery","useConfig","llmQuery","useLlmList","enabledAgents","llmBackends","currentDistillRole","readForm","form","setForm","useState","initialRef","useRef","useEffect","next","updateEnv","useUpdateEnv","putRoles","useLlmPutRoles","dirty","initial","k","set","prev","numField","value","min","label","n","validate","buildEnvUpdates","out","diffStr","key","cur","onSave","err","toast","envUpdates","roleChanged","serr","message","describeError","onDiscard","busy","noBackends","noAgents","jsxs","jsx","Badge","Button","Loader2","Save","Field","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","name","agentDisplayName","b","NumberField","help","children","Label","placeholder","step","onChange","Input","e","MemoryDistillRoute","statusQuery","useDistillStatus","status","trigger","useTriggerDistill","onRunNow","running","pending","RefreshCcw","Play","Fragment","StatTile","formatEpoch","TONE_STYLES","tone","cn","ms","d"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{o}from"./index-
|
|
1
|
+
import{o}from"./index-CzlhMSb2.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
5
5
|
* See the LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/const a=o("Download",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"7 10 12 15 17 10",key:"2ggqvy"}],["line",{x1:"12",x2:"12",y1:"15",y2:"3",key:"1vk2je"}]]);export{a as D};
|
|
7
|
-
//# sourceMappingURL=download-
|
|
7
|
+
//# sourceMappingURL=download-DO4Kw3Fi.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download-
|
|
1
|
+
{"version":3,"file":"download-DO4Kw3Fi.js","sources":["../../node_modules/lucide-react/dist/esm/icons/download.js"],"sourcesContent":["/**\n * @license lucide-react v0.469.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 Download = createLucideIcon(\"Download\", [\n [\"path\", { d: \"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\", key: \"ih7n3h\" }],\n [\"polyline\", { points: \"7 10 12 15 17 10\", key: \"2ggqvy\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"15\", y2: \"3\", key: \"1vk2je\" }]\n]);\n\nexport { Download as default };\n//# sourceMappingURL=download.js.map\n"],"names":["Download","createLucideIcon"],"mappings":"mCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAWC,EAAiB,WAAY,CAC5C,CAAC,OAAQ,CAAE,EAAG,4CAA6C,IAAK,QAAQ,CAAE,EAC1E,CAAC,WAAY,CAAE,OAAQ,mBAAoB,IAAK,QAAQ,CAAE,EAC1D,CAAC,OAAQ,CAAE,GAAI,KAAM,GAAI,KAAM,GAAI,KAAM,GAAI,IAAK,IAAK,QAAQ,CAAE,CACnE,CAAC","x_google_ignoreList":[0]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{o as A,u as F,j as e,
|
|
1
|
+
import{o as A,u as F,j as e,ab as L,l as I,B as u,I as S,c as z,S as D,g as V,h as X,i as J,k as g,X as K,m,n as j,L as Q}from"./index-CzlhMSb2.js";import{r as M}from"./react-DlP5eolq.js";import{u as Y,b as q,f as G}from"./use-settings-DZhfMpNR.js";import{L as H}from"./loader-circle-AgQ2XO06.js";import{C as W}from"./circle-x-BZ3UUhcm.js";import{C as Z}from"./circle-check-BWBI4Qhk.js";import{R as $}from"./refresh-ccw-CM-Cjwud.js";import{E as ee,a as se}from"./eye-BMxHZFil.js";import{S as ae}from"./save-xBMgs6Bd.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
5
5
|
* See the LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/const te=A("Mail",[["rect",{width:"20",height:"16",x:"2",y:"4",rx:"2",key:"18n3k1"}],["path",{d:"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7",key:"1ocrg3"}]]),U=["IMHUB_SMTP_HOST","IMHUB_SMTP_PORT","IMHUB_SMTP_USER","IMHUB_SMTP_PASS","IMHUB_SMTP_FROM","IMHUB_SMTP_SECURE"];function v(){return{IMHUB_SMTP_HOST:"",IMHUB_SMTP_PORT:"",IMHUB_SMTP_USER:"",IMHUB_SMTP_PASS:"",IMHUB_SMTP_FROM:"",IMHUB_SMTP_SECURE:"auto"}}function ie(s){const i=(s??"").trim().toLowerCase();return i==="1"||i==="true"||i==="yes"?"true":i==="0"||i==="false"||i==="no"?"false":"auto"}function P(s){return{IMHUB_SMTP_HOST:s.IMHUB_SMTP_HOST??"",IMHUB_SMTP_PORT:s.IMHUB_SMTP_PORT??"",IMHUB_SMTP_USER:s.IMHUB_SMTP_USER??"",IMHUB_SMTP_PASS:s.IMHUB_SMTP_PASS??"",IMHUB_SMTP_FROM:s.IMHUB_SMTP_FROM??"",IMHUB_SMTP_SECURE:ie(s.IMHUB_SMTP_SECURE)}}function B(s){return/\*{3,}/.test(s)}function he(){const{t:s}=F(["settings","common"]),[i,T]=M.useState(!1),n=Y({reveal:i}),o=q(),h=G(),l=n.data?.env??{},[r,f]=M.useState(v),[b,C]=M.useState("");M.useEffect(()=>{if(!n.data)return;const a=P(l),t=JSON.stringify(a);t!==b&&(f(a),C(t))},[n.dataUpdatedAt]);const _=!!(l.IMHUB_SMTP_HOST&&l.IMHUB_SMTP_USER&&l.IMHUB_SMTP_PASS),N=M.useMemo(()=>{if(!n.data)return!1;const a=P(l);for(const t of U)if(!(t==="IMHUB_SMTP_PASS"&&r[t]&&B(r[t])&&r[t]===a[t])&&r[t]!==a[t])return!0;return!1},[r,l,n.data]);function d(a,t){f(c=>({...c,[a]:t}))}function E(){n.data&&f(P(l))}async function R(){if(!n.data)return;const a=P(l),t={};for(const c of U){const p=r[c],k=a[c];p!==k&&(c==="IMHUB_SMTP_PASS"&&B(p)||(t[c]=p===""?null:p))}if(Object.keys(t).length===0){m.info(s("email.toast.noChanges"));return}try{await o.mutateAsync({updates:t}),m.success(s("email.toast.saved"))}catch(c){m.error(j(c,s).message)}}async function y(){if(!n.data)return;const a={};for(const t of U)a[t]=null;try{await o.mutateAsync({updates:a}),f(v()),m.success(s("email.toast.disabled"))}catch(t){m.error(j(t,s).message)}}async function w(){try{const a=await h.mutateAsync();m.success(a.message)}catch(a){m.error(j(a,s).message)}}const O=h.isPending?e.jsx(H,{className:"h-4 w-4 animate-spin"}):h.isError?e.jsx(W,{className:"h-4 w-4 text-danger"}):h.isSuccess?e.jsx(Z,{className:"h-4 w-4 text-success"}):e.jsx(L,{className:"h-4 w-4"});return e.jsxs("div",{className:"mx-auto flex max-w-4xl flex-col gap-4",children:[e.jsxs("header",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("h1",{className:"text-xl font-semibold",children:s("email.title")}),_?e.jsx(I,{variant:"success",children:s("email.statusOn")}):e.jsx(I,{variant:"outline",children:s("email.statusOff")}),e.jsxs(u,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>void n.refetch(),disabled:n.isFetching,"aria-label":s("actions.refresh",{ns:"common"}),children:[n.isFetching?e.jsx(H,{className:"h-4 w-4 animate-spin"}):e.jsx($,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:s("actions.refresh",{ns:"common"})})]})]}),e.jsx("p",{className:"text-sm text-text-dim",children:s("email.subtitle")})]}),n.isLoading?e.jsx("div",{className:"h-64 rounded-md bg-surface-2 animate-pulse"}):e.jsxs("section",{className:"rounded-md border border-border bg-surface",children:[e.jsxs("header",{className:"flex items-center gap-2 border-b border-border px-4 py-3",children:[e.jsx(te,{className:"h-4 w-4 text-text-dim"}),e.jsx("h2",{className:"text-sm font-semibold",children:s("email.cardTitle")}),e.jsxs(u,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>T(a=>!a),disabled:n.isFetching,"aria-label":s(i?"email.hide":"email.reveal"),children:[i?e.jsx(ee,{className:"h-4 w-4"}):e.jsx(se,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:s(i?"email.hide":"email.reveal")})]})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-3 px-4 py-4 sm:grid-cols-2",children:[e.jsx(x,{label:s("email.host"),hint:s("email.hostHint"),children:e.jsx(S,{value:r.IMHUB_SMTP_HOST,onChange:a=>d("IMHUB_SMTP_HOST",a.target.value),placeholder:"smtp.gmail.com",autoComplete:"off"})}),e.jsx(x,{label:s("email.port"),hint:s("email.portHint"),children:e.jsx(S,{type:"number",inputMode:"numeric",min:1,max:65535,value:r.IMHUB_SMTP_PORT,onChange:a=>d("IMHUB_SMTP_PORT",a.target.value),placeholder:"465",autoComplete:"off"})}),e.jsx(x,{label:s("email.user"),hint:s("email.userHint"),children:e.jsx(S,{value:r.IMHUB_SMTP_USER,onChange:a=>d("IMHUB_SMTP_USER",a.target.value),placeholder:"you@example.com",autoComplete:"off"})}),e.jsx(x,{label:s("email.pass"),hint:s("email.passHint"),children:e.jsx(S,{type:i?"text":"password",value:r.IMHUB_SMTP_PASS,onChange:a=>d("IMHUB_SMTP_PASS",a.target.value),placeholder:"••••••••",autoComplete:"new-password",className:z(B(r.IMHUB_SMTP_PASS)&&"font-mono text-text-muted")})}),e.jsx(x,{label:s("email.from"),hint:s("email.fromHint"),children:e.jsx(S,{value:r.IMHUB_SMTP_FROM,onChange:a=>d("IMHUB_SMTP_FROM",a.target.value),placeholder:"",autoComplete:"off"})}),e.jsx(x,{label:s("email.secure"),hint:s("email.secureHint"),children:e.jsxs(D,{value:r.IMHUB_SMTP_SECURE,onValueChange:a=>d("IMHUB_SMTP_SECURE",a),children:[e.jsx(V,{children:e.jsx(X,{})}),e.jsxs(J,{children:[e.jsx(g,{value:"auto",children:s("email.secureAuto")}),e.jsx(g,{value:"true",children:s("email.secureTrue")}),e.jsx(g,{value:"false",children:s("email.secureFalse")})]})]})})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 border-t border-border px-4 py-3",children:[e.jsxs(u,{variant:"secondary",size:"sm",onClick:()=>void w(),disabled:!_||h.isPending,title:_?void 0:s("email.testNeedsConfigured"),children:[O,s("email.testBtn")]}),e.jsxs(u,{variant:"ghost",size:"sm",onClick:()=>void y(),disabled:!_||o.isPending,className:"text-danger hover:text-danger",children:[e.jsx(K,{className:"h-4 w-4"}),s("email.disableBtn")]}),e.jsx("span",{className:"ml-auto"}),N&&e.jsxs(e.Fragment,{children:[e.jsx(u,{variant:"ghost",size:"sm",onClick:E,disabled:o.isPending,children:s("email.discard")}),e.jsxs(u,{size:"sm",onClick:()=>void R(),disabled:o.isPending,children:[o.isPending?e.jsx(H,{className:"h-4 w-4 animate-spin"}):e.jsx(ae,{className:"h-4 w-4"}),o.isPending?s("email.saving"):s("email.saveBtn")]})]})]})]})]})}function x({label:s,hint:i,children:T}){return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(Q,{className:"text-xs font-medium",children:s}),T,i&&e.jsx("p",{className:"text-[11px] text-text-dim",children:i})]})}export{he as default,ie as normalizeSecure};
|
|
7
|
-
//# sourceMappingURL=email-
|
|
7
|
+
//# sourceMappingURL=email-Dkqwudqq.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email-C8Fx7GcZ.js","sources":["../../node_modules/lucide-react/dist/esm/icons/mail.js","../../src/routes/settings/email.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.469.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 Mail = createLucideIcon(\"Mail\", [\n [\"rect\", { width: \"20\", height: \"16\", x: \"2\", y: \"4\", rx: \"2\", key: \"18n3k1\" }],\n [\"path\", { d: \"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\", key: \"1ocrg3\" }]\n]);\n\nexport { Mail as default };\n//# sourceMappingURL=mail.js.map\n","/**\n * /settings/email — SMTP credentials editor (matches v1 settings.html's\n * \"📨 SMTP\" card). Drives email delivery for `/remind email me@x.com …`.\n *\n * Six env keys, persisted to `~/.agim/.env`:\n * * IMHUB_SMTP_HOST / PORT / USER / PASS / FROM / SECURE\n *\n * IMHUB_SMTP_PASS is in the backend's SECRET_KEYS set — masked unless\n * the Reveal toggle issues a `?reveal=1` fetch. Submitting a masked\n * string back is a no-op on the backend (it preserves the real value).\n *\n * Test button calls POST /api/messengers/email/test which runs\n * `nodemailer.verify()` against the live env (i.e. the operator must\n * Save first, then Test — same UX as v1).\n *\n * Disable button clears all six keys via a single PUT /api/env with\n * null values; the email adapter then logs `email.disabled` on the\n * next service restart.\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport {\n CheckCircle2, Eye, EyeOff, Loader2, Mail, RefreshCcw,\n Save, Send, X, XCircle,\n} from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { useEnv, useUpdateEnv, useTestEmail } from '@/hooks/use-settings'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\nconst SMTP_KEYS = [\n 'IMHUB_SMTP_HOST',\n 'IMHUB_SMTP_PORT',\n 'IMHUB_SMTP_USER',\n 'IMHUB_SMTP_PASS',\n 'IMHUB_SMTP_FROM',\n 'IMHUB_SMTP_SECURE',\n] as const\n\ntype SmtpKey = typeof SMTP_KEYS[number]\ntype SecureMode = 'auto' | 'true' | 'false'\n\ninterface Draft {\n IMHUB_SMTP_HOST: string\n IMHUB_SMTP_PORT: string\n IMHUB_SMTP_USER: string\n IMHUB_SMTP_PASS: string\n IMHUB_SMTP_FROM: string\n IMHUB_SMTP_SECURE: SecureMode\n}\n\nfunction emptyDraft(): Draft {\n return {\n IMHUB_SMTP_HOST: '',\n IMHUB_SMTP_PORT: '',\n IMHUB_SMTP_USER: '',\n IMHUB_SMTP_PASS: '',\n IMHUB_SMTP_FROM: '',\n IMHUB_SMTP_SECURE: 'auto',\n }\n}\n\n// R13: exported so the unit suite can lock the env-string → SecureMode\n// mapping without spinning up Radix Select (whose trigger label isn't\n// readable in jsdom). Mirrors the operator's mental model: anything\n// that reads as \"yes/true/on\" maps to true; \"no/false/off\" to false;\n// blank / unknown to auto (defer to port-based heuristic at send time).\nexport function normalizeSecure(raw: string | undefined): SecureMode {\n const v = (raw ?? '').trim().toLowerCase()\n if (v === '1' || v === 'true' || v === 'yes') return 'true'\n if (v === '0' || v === 'false' || v === 'no') return 'false'\n return 'auto'\n}\n\nfunction draftFromEnv(env: Record<string, string>): Draft {\n return {\n IMHUB_SMTP_HOST: env.IMHUB_SMTP_HOST ?? '',\n IMHUB_SMTP_PORT: env.IMHUB_SMTP_PORT ?? '',\n IMHUB_SMTP_USER: env.IMHUB_SMTP_USER ?? '',\n IMHUB_SMTP_PASS: env.IMHUB_SMTP_PASS ?? '',\n IMHUB_SMTP_FROM: env.IMHUB_SMTP_FROM ?? '',\n IMHUB_SMTP_SECURE: normalizeSecure(env.IMHUB_SMTP_SECURE),\n }\n}\n\n/** Detect the backend's secret-mask format: `ab****yz` (3+ `*` between\n * surrounding chars). PUT /api/env preserves the real value when it\n * sees this pattern, so client edits that just echo the mask are a\n * no-op — we skip them in the dirty check + the submit body. */\nfunction isMasked(s: string): boolean {\n return /\\*{3,}/.test(s)\n}\n\nexport default function SettingsEmailRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n\n const [reveal, setReveal] = useState(false)\n const envQuery = useEnv({ reveal })\n const updateEnv = useUpdateEnv()\n const testMut = useTestEmail()\n\n const env = envQuery.data?.env ?? {}\n\n const [draft, setDraft] = useState<Draft>(emptyDraft)\n // Sync draft from server whenever a fresh env arrives (initial load\n // + reveal toggle + post-save refetch). Local edits that diverge stay\n // until the user Saves or Discards.\n const [syncedHash, setSyncedHash] = useState<string>('')\n useEffect(() => {\n if (!envQuery.data) return\n const next = draftFromEnv(env)\n const hash = JSON.stringify(next)\n if (hash !== syncedHash) {\n setDraft(next)\n setSyncedHash(hash)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [envQuery.dataUpdatedAt])\n\n const isConfigured = !!(env.IMHUB_SMTP_HOST && env.IMHUB_SMTP_USER && env.IMHUB_SMTP_PASS)\n\n const isDirty = useMemo(() => {\n if (!envQuery.data) return false\n const current = draftFromEnv(env)\n for (const k of SMTP_KEYS) {\n // PASS: ignore \"user just echoed the mask back\" as no-change.\n if (k === 'IMHUB_SMTP_PASS' && draft[k] && isMasked(draft[k]) && draft[k] === current[k]) continue\n if (draft[k] !== current[k]) return true\n }\n return false\n }, [draft, env, envQuery.data])\n\n function setField<K extends SmtpKey>(key: K, value: Draft[K]): void {\n setDraft((d) => ({ ...d, [key]: value }))\n }\n\n function onDiscard(): void {\n if (!envQuery.data) return\n setDraft(draftFromEnv(env))\n }\n\n async function onSave(): Promise<void> {\n if (!envQuery.data) return\n const current = draftFromEnv(env)\n const updates: Record<string, string | null> = {}\n for (const k of SMTP_KEYS) {\n const next = draft[k]\n const cur = current[k]\n if (next === cur) continue\n // Don't ship a masked PASS as the new value — backend's\n // isMasked-detect already skips it server-side, but keep the\n // wire honest.\n if (k === 'IMHUB_SMTP_PASS' && isMasked(next)) continue\n // Empty string → null (explicit unset) for non-PASS fields.\n // For PASS, an empty string also means \"clear\" (Disable button uses\n // the same path).\n updates[k] = next === '' ? null : next\n }\n if (Object.keys(updates).length === 0) {\n toast.info(t('email.toast.noChanges'))\n return\n }\n try {\n await updateEnv.mutateAsync({ updates })\n toast.success(t('email.toast.saved'))\n // refetch handled by hook's onSuccess; draft will re-sync via\n // the dataUpdatedAt effect on the next paint.\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n async function onDisable(): Promise<void> {\n if (!envQuery.data) return\n const updates: Record<string, string | null> = {}\n for (const k of SMTP_KEYS) updates[k] = null\n try {\n await updateEnv.mutateAsync({ updates })\n setDraft(emptyDraft())\n toast.success(t('email.toast.disabled'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n async function onTest(): Promise<void> {\n try {\n const res = await testMut.mutateAsync()\n toast.success(res.message)\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n const testIcon =\n testMut.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : testMut.isError ? <XCircle className=\"h-4 w-4 text-danger\" />\n : testMut.isSuccess ? <CheckCircle2 className=\"h-4 w-4 text-success\" />\n : <Send className=\"h-4 w-4\" />\n\n return (\n <div className=\"mx-auto flex max-w-4xl flex-col gap-4\">\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('email.title')}</h1>\n {isConfigured\n ? <Badge variant=\"success\">{t('email.statusOn')}</Badge>\n : <Badge variant=\"outline\">{t('email.statusOff')}</Badge>}\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => void envQuery.refetch()}\n disabled={envQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {envQuery.isFetching\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('email.subtitle')}</p>\n </header>\n\n {envQuery.isLoading ? (\n <div className=\"h-64 rounded-md bg-surface-2 animate-pulse\" />\n ) : (\n <section className=\"rounded-md border border-border bg-surface\">\n <header className=\"flex items-center gap-2 border-b border-border px-4 py-3\">\n <Mail className=\"h-4 w-4 text-text-dim\" />\n <h2 className=\"text-sm font-semibold\">{t('email.cardTitle')}</h2>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => setReveal((v) => !v)}\n disabled={envQuery.isFetching}\n aria-label={reveal ? t('email.hide') : t('email.reveal')}\n >\n {reveal ? <EyeOff className=\"h-4 w-4\" /> : <Eye className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{reveal ? t('email.hide') : t('email.reveal')}</span>\n </Button>\n </header>\n\n <div className=\"grid grid-cols-1 gap-3 px-4 py-4 sm:grid-cols-2\">\n <Field label={t('email.host')} hint={t('email.hostHint')}>\n <Input\n value={draft.IMHUB_SMTP_HOST}\n onChange={(e) => setField('IMHUB_SMTP_HOST', e.target.value)}\n placeholder=\"smtp.gmail.com\"\n autoComplete=\"off\"\n />\n </Field>\n <Field label={t('email.port')} hint={t('email.portHint')}>\n <Input\n type=\"number\"\n inputMode=\"numeric\"\n min={1}\n max={65535}\n value={draft.IMHUB_SMTP_PORT}\n onChange={(e) => setField('IMHUB_SMTP_PORT', e.target.value)}\n placeholder=\"465\"\n autoComplete=\"off\"\n />\n </Field>\n <Field label={t('email.user')} hint={t('email.userHint')}>\n <Input\n value={draft.IMHUB_SMTP_USER}\n onChange={(e) => setField('IMHUB_SMTP_USER', e.target.value)}\n placeholder=\"you@example.com\"\n autoComplete=\"off\"\n />\n </Field>\n <Field label={t('email.pass')} hint={t('email.passHint')}>\n <Input\n type={reveal ? 'text' : 'password'}\n value={draft.IMHUB_SMTP_PASS}\n onChange={(e) => setField('IMHUB_SMTP_PASS', e.target.value)}\n placeholder=\"••••••••\"\n autoComplete=\"new-password\"\n className={cn(isMasked(draft.IMHUB_SMTP_PASS) && 'font-mono text-text-muted')}\n />\n </Field>\n <Field label={t('email.from')} hint={t('email.fromHint')}>\n <Input\n value={draft.IMHUB_SMTP_FROM}\n onChange={(e) => setField('IMHUB_SMTP_FROM', e.target.value)}\n placeholder=\"\"\n autoComplete=\"off\"\n />\n </Field>\n <Field label={t('email.secure')} hint={t('email.secureHint')}>\n <Select\n value={draft.IMHUB_SMTP_SECURE}\n onValueChange={(v) => setField('IMHUB_SMTP_SECURE', v as SecureMode)}\n >\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"auto\">{t('email.secureAuto')}</SelectItem>\n <SelectItem value=\"true\">{t('email.secureTrue')}</SelectItem>\n <SelectItem value=\"false\">{t('email.secureFalse')}</SelectItem>\n </SelectContent>\n </Select>\n </Field>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2 border-t border-border px-4 py-3\">\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => void onTest()}\n disabled={!isConfigured || testMut.isPending}\n title={!isConfigured ? t('email.testNeedsConfigured') : undefined}\n >\n {testIcon}\n {t('email.testBtn')}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => void onDisable()}\n disabled={!isConfigured || updateEnv.isPending}\n className=\"text-danger hover:text-danger\"\n >\n <X className=\"h-4 w-4\" />\n {t('email.disableBtn')}\n </Button>\n <span className=\"ml-auto\" />\n {isDirty && (\n <>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={onDiscard}\n disabled={updateEnv.isPending}\n >\n {t('email.discard')}\n </Button>\n <Button\n size=\"sm\"\n onClick={() => void onSave()}\n disabled={updateEnv.isPending}\n >\n {updateEnv.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <Save className=\"h-4 w-4\" />}\n {updateEnv.isPending ? t('email.saving') : t('email.saveBtn')}\n </Button>\n </>\n )}\n </div>\n </section>\n )}\n </div>\n )\n}\n\ninterface FieldProps {\n label: string\n hint?: string\n children: React.ReactNode\n}\n\nfunction Field({ label, hint, children }: FieldProps): JSX.Element {\n return (\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs font-medium\">{label}</Label>\n {children}\n {hint && <p className=\"text-[11px] text-text-dim\">{hint}</p>}\n </div>\n )\n}\n"],"names":["Mail","createLucideIcon","SMTP_KEYS","emptyDraft","normalizeSecure","raw","v","draftFromEnv","env","isMasked","SettingsEmailRoute","t","useTranslation","reveal","setReveal","useState","envQuery","useEnv","updateEnv","useUpdateEnv","testMut","useTestEmail","draft","setDraft","syncedHash","setSyncedHash","useEffect","next","hash","isConfigured","isDirty","useMemo","current","k","setField","key","value","d","onDiscard","onSave","updates","cur","toast","err","describeError","onDisable","onTest","res","testIcon","jsx","Loader2","XCircle","CheckCircle2","Send","jsxs","Badge","Button","RefreshCcw","EyeOff","Eye","Field","Input","e","cn","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","X","Fragment","Save","label","hint","children","Label"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"email-Dkqwudqq.js","sources":["../../node_modules/lucide-react/dist/esm/icons/mail.js","../../src/routes/settings/email.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.469.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 Mail = createLucideIcon(\"Mail\", [\n [\"rect\", { width: \"20\", height: \"16\", x: \"2\", y: \"4\", rx: \"2\", key: \"18n3k1\" }],\n [\"path\", { d: \"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\", key: \"1ocrg3\" }]\n]);\n\nexport { Mail as default };\n//# sourceMappingURL=mail.js.map\n","/**\n * /settings/email — SMTP credentials editor (matches v1 settings.html's\n * \"📨 SMTP\" card). Drives email delivery for `/remind email me@x.com …`.\n *\n * Six env keys, persisted to `~/.agim/.env`:\n * * IMHUB_SMTP_HOST / PORT / USER / PASS / FROM / SECURE\n *\n * IMHUB_SMTP_PASS is in the backend's SECRET_KEYS set — masked unless\n * the Reveal toggle issues a `?reveal=1` fetch. Submitting a masked\n * string back is a no-op on the backend (it preserves the real value).\n *\n * Test button calls POST /api/messengers/email/test which runs\n * `nodemailer.verify()` against the live env (i.e. the operator must\n * Save first, then Test — same UX as v1).\n *\n * Disable button clears all six keys via a single PUT /api/env with\n * null values; the email adapter then logs `email.disabled` on the\n * next service restart.\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport {\n CheckCircle2, Eye, EyeOff, Loader2, Mail, RefreshCcw,\n Save, Send, X, XCircle,\n} from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { useEnv, useUpdateEnv, useTestEmail } from '@/hooks/use-settings'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\nconst SMTP_KEYS = [\n 'IMHUB_SMTP_HOST',\n 'IMHUB_SMTP_PORT',\n 'IMHUB_SMTP_USER',\n 'IMHUB_SMTP_PASS',\n 'IMHUB_SMTP_FROM',\n 'IMHUB_SMTP_SECURE',\n] as const\n\ntype SmtpKey = typeof SMTP_KEYS[number]\ntype SecureMode = 'auto' | 'true' | 'false'\n\ninterface Draft {\n IMHUB_SMTP_HOST: string\n IMHUB_SMTP_PORT: string\n IMHUB_SMTP_USER: string\n IMHUB_SMTP_PASS: string\n IMHUB_SMTP_FROM: string\n IMHUB_SMTP_SECURE: SecureMode\n}\n\nfunction emptyDraft(): Draft {\n return {\n IMHUB_SMTP_HOST: '',\n IMHUB_SMTP_PORT: '',\n IMHUB_SMTP_USER: '',\n IMHUB_SMTP_PASS: '',\n IMHUB_SMTP_FROM: '',\n IMHUB_SMTP_SECURE: 'auto',\n }\n}\n\n// R13: exported so the unit suite can lock the env-string → SecureMode\n// mapping without spinning up Radix Select (whose trigger label isn't\n// readable in jsdom). Mirrors the operator's mental model: anything\n// that reads as \"yes/true/on\" maps to true; \"no/false/off\" to false;\n// blank / unknown to auto (defer to port-based heuristic at send time).\nexport function normalizeSecure(raw: string | undefined): SecureMode {\n const v = (raw ?? '').trim().toLowerCase()\n if (v === '1' || v === 'true' || v === 'yes') return 'true'\n if (v === '0' || v === 'false' || v === 'no') return 'false'\n return 'auto'\n}\n\nfunction draftFromEnv(env: Record<string, string>): Draft {\n return {\n IMHUB_SMTP_HOST: env.IMHUB_SMTP_HOST ?? '',\n IMHUB_SMTP_PORT: env.IMHUB_SMTP_PORT ?? '',\n IMHUB_SMTP_USER: env.IMHUB_SMTP_USER ?? '',\n IMHUB_SMTP_PASS: env.IMHUB_SMTP_PASS ?? '',\n IMHUB_SMTP_FROM: env.IMHUB_SMTP_FROM ?? '',\n IMHUB_SMTP_SECURE: normalizeSecure(env.IMHUB_SMTP_SECURE),\n }\n}\n\n/** Detect the backend's secret-mask format: `ab****yz` (3+ `*` between\n * surrounding chars). PUT /api/env preserves the real value when it\n * sees this pattern, so client edits that just echo the mask are a\n * no-op — we skip them in the dirty check + the submit body. */\nfunction isMasked(s: string): boolean {\n return /\\*{3,}/.test(s)\n}\n\nexport default function SettingsEmailRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n\n const [reveal, setReveal] = useState(false)\n const envQuery = useEnv({ reveal })\n const updateEnv = useUpdateEnv()\n const testMut = useTestEmail()\n\n const env = envQuery.data?.env ?? {}\n\n const [draft, setDraft] = useState<Draft>(emptyDraft)\n // Sync draft from server whenever a fresh env arrives (initial load\n // + reveal toggle + post-save refetch). Local edits that diverge stay\n // until the user Saves or Discards.\n const [syncedHash, setSyncedHash] = useState<string>('')\n useEffect(() => {\n if (!envQuery.data) return\n const next = draftFromEnv(env)\n const hash = JSON.stringify(next)\n if (hash !== syncedHash) {\n setDraft(next)\n setSyncedHash(hash)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [envQuery.dataUpdatedAt])\n\n const isConfigured = !!(env.IMHUB_SMTP_HOST && env.IMHUB_SMTP_USER && env.IMHUB_SMTP_PASS)\n\n const isDirty = useMemo(() => {\n if (!envQuery.data) return false\n const current = draftFromEnv(env)\n for (const k of SMTP_KEYS) {\n // PASS: ignore \"user just echoed the mask back\" as no-change.\n if (k === 'IMHUB_SMTP_PASS' && draft[k] && isMasked(draft[k]) && draft[k] === current[k]) continue\n if (draft[k] !== current[k]) return true\n }\n return false\n }, [draft, env, envQuery.data])\n\n function setField<K extends SmtpKey>(key: K, value: Draft[K]): void {\n setDraft((d) => ({ ...d, [key]: value }))\n }\n\n function onDiscard(): void {\n if (!envQuery.data) return\n setDraft(draftFromEnv(env))\n }\n\n async function onSave(): Promise<void> {\n if (!envQuery.data) return\n const current = draftFromEnv(env)\n const updates: Record<string, string | null> = {}\n for (const k of SMTP_KEYS) {\n const next = draft[k]\n const cur = current[k]\n if (next === cur) continue\n // Don't ship a masked PASS as the new value — backend's\n // isMasked-detect already skips it server-side, but keep the\n // wire honest.\n if (k === 'IMHUB_SMTP_PASS' && isMasked(next)) continue\n // Empty string → null (explicit unset) for non-PASS fields.\n // For PASS, an empty string also means \"clear\" (Disable button uses\n // the same path).\n updates[k] = next === '' ? null : next\n }\n if (Object.keys(updates).length === 0) {\n toast.info(t('email.toast.noChanges'))\n return\n }\n try {\n await updateEnv.mutateAsync({ updates })\n toast.success(t('email.toast.saved'))\n // refetch handled by hook's onSuccess; draft will re-sync via\n // the dataUpdatedAt effect on the next paint.\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n async function onDisable(): Promise<void> {\n if (!envQuery.data) return\n const updates: Record<string, string | null> = {}\n for (const k of SMTP_KEYS) updates[k] = null\n try {\n await updateEnv.mutateAsync({ updates })\n setDraft(emptyDraft())\n toast.success(t('email.toast.disabled'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n async function onTest(): Promise<void> {\n try {\n const res = await testMut.mutateAsync()\n toast.success(res.message)\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n const testIcon =\n testMut.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : testMut.isError ? <XCircle className=\"h-4 w-4 text-danger\" />\n : testMut.isSuccess ? <CheckCircle2 className=\"h-4 w-4 text-success\" />\n : <Send className=\"h-4 w-4\" />\n\n return (\n <div className=\"mx-auto flex max-w-4xl flex-col gap-4\">\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('email.title')}</h1>\n {isConfigured\n ? <Badge variant=\"success\">{t('email.statusOn')}</Badge>\n : <Badge variant=\"outline\">{t('email.statusOff')}</Badge>}\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => void envQuery.refetch()}\n disabled={envQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {envQuery.isFetching\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('email.subtitle')}</p>\n </header>\n\n {envQuery.isLoading ? (\n <div className=\"h-64 rounded-md bg-surface-2 animate-pulse\" />\n ) : (\n <section className=\"rounded-md border border-border bg-surface\">\n <header className=\"flex items-center gap-2 border-b border-border px-4 py-3\">\n <Mail className=\"h-4 w-4 text-text-dim\" />\n <h2 className=\"text-sm font-semibold\">{t('email.cardTitle')}</h2>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => setReveal((v) => !v)}\n disabled={envQuery.isFetching}\n aria-label={reveal ? t('email.hide') : t('email.reveal')}\n >\n {reveal ? <EyeOff className=\"h-4 w-4\" /> : <Eye className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{reveal ? t('email.hide') : t('email.reveal')}</span>\n </Button>\n </header>\n\n <div className=\"grid grid-cols-1 gap-3 px-4 py-4 sm:grid-cols-2\">\n <Field label={t('email.host')} hint={t('email.hostHint')}>\n <Input\n value={draft.IMHUB_SMTP_HOST}\n onChange={(e) => setField('IMHUB_SMTP_HOST', e.target.value)}\n placeholder=\"smtp.gmail.com\"\n autoComplete=\"off\"\n />\n </Field>\n <Field label={t('email.port')} hint={t('email.portHint')}>\n <Input\n type=\"number\"\n inputMode=\"numeric\"\n min={1}\n max={65535}\n value={draft.IMHUB_SMTP_PORT}\n onChange={(e) => setField('IMHUB_SMTP_PORT', e.target.value)}\n placeholder=\"465\"\n autoComplete=\"off\"\n />\n </Field>\n <Field label={t('email.user')} hint={t('email.userHint')}>\n <Input\n value={draft.IMHUB_SMTP_USER}\n onChange={(e) => setField('IMHUB_SMTP_USER', e.target.value)}\n placeholder=\"you@example.com\"\n autoComplete=\"off\"\n />\n </Field>\n <Field label={t('email.pass')} hint={t('email.passHint')}>\n <Input\n type={reveal ? 'text' : 'password'}\n value={draft.IMHUB_SMTP_PASS}\n onChange={(e) => setField('IMHUB_SMTP_PASS', e.target.value)}\n placeholder=\"••••••••\"\n autoComplete=\"new-password\"\n className={cn(isMasked(draft.IMHUB_SMTP_PASS) && 'font-mono text-text-muted')}\n />\n </Field>\n <Field label={t('email.from')} hint={t('email.fromHint')}>\n <Input\n value={draft.IMHUB_SMTP_FROM}\n onChange={(e) => setField('IMHUB_SMTP_FROM', e.target.value)}\n placeholder=\"\"\n autoComplete=\"off\"\n />\n </Field>\n <Field label={t('email.secure')} hint={t('email.secureHint')}>\n <Select\n value={draft.IMHUB_SMTP_SECURE}\n onValueChange={(v) => setField('IMHUB_SMTP_SECURE', v as SecureMode)}\n >\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"auto\">{t('email.secureAuto')}</SelectItem>\n <SelectItem value=\"true\">{t('email.secureTrue')}</SelectItem>\n <SelectItem value=\"false\">{t('email.secureFalse')}</SelectItem>\n </SelectContent>\n </Select>\n </Field>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2 border-t border-border px-4 py-3\">\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => void onTest()}\n disabled={!isConfigured || testMut.isPending}\n title={!isConfigured ? t('email.testNeedsConfigured') : undefined}\n >\n {testIcon}\n {t('email.testBtn')}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => void onDisable()}\n disabled={!isConfigured || updateEnv.isPending}\n className=\"text-danger hover:text-danger\"\n >\n <X className=\"h-4 w-4\" />\n {t('email.disableBtn')}\n </Button>\n <span className=\"ml-auto\" />\n {isDirty && (\n <>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={onDiscard}\n disabled={updateEnv.isPending}\n >\n {t('email.discard')}\n </Button>\n <Button\n size=\"sm\"\n onClick={() => void onSave()}\n disabled={updateEnv.isPending}\n >\n {updateEnv.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <Save className=\"h-4 w-4\" />}\n {updateEnv.isPending ? t('email.saving') : t('email.saveBtn')}\n </Button>\n </>\n )}\n </div>\n </section>\n )}\n </div>\n )\n}\n\ninterface FieldProps {\n label: string\n hint?: string\n children: React.ReactNode\n}\n\nfunction Field({ label, hint, children }: FieldProps): JSX.Element {\n return (\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs font-medium\">{label}</Label>\n {children}\n {hint && <p className=\"text-[11px] text-text-dim\">{hint}</p>}\n </div>\n )\n}\n"],"names":["Mail","createLucideIcon","SMTP_KEYS","emptyDraft","normalizeSecure","raw","v","draftFromEnv","env","isMasked","SettingsEmailRoute","t","useTranslation","reveal","setReveal","useState","envQuery","useEnv","updateEnv","useUpdateEnv","testMut","useTestEmail","draft","setDraft","syncedHash","setSyncedHash","useEffect","next","hash","isConfigured","isDirty","useMemo","current","k","setField","key","value","d","onDiscard","onSave","updates","cur","toast","err","describeError","onDisable","onTest","res","testIcon","jsx","Loader2","XCircle","CheckCircle2","Send","jsxs","Badge","Button","RefreshCcw","EyeOff","Eye","Field","Input","e","cn","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","X","Fragment","Save","label","hint","children","Label"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as e,c as x}from"./index-
|
|
2
|
-
//# sourceMappingURL=empty-state-
|
|
1
|
+
import{j as e,c as x}from"./index-CzlhMSb2.js";function i({icon:t,title:m,description:s,children:a,className:r,...c}){return e.jsxs("div",{className:x("flex flex-col items-center justify-center text-center","py-12 px-4 gap-3",r),...c,children:[t&&e.jsx("div",{className:x("flex items-center justify-center","h-12 w-12 rounded-full bg-surface-2 text-text-dim","[&_svg]:h-6 [&_svg]:w-6"),"aria-hidden":"true",children:t}),e.jsx("h3",{className:"text-base font-semibold text-text",children:m}),s&&e.jsx("p",{className:"text-sm text-text-dim max-w-sm",children:s}),a&&e.jsx("div",{className:"mt-2 flex flex-wrap items-center justify-center gap-2",children:a})]})}i.displayName="EmptyState";export{i as E};
|
|
2
|
+
//# sourceMappingURL=empty-state-DGH3i5i2.js.map
|