agim-cli 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +39 -3
- package/README.zh-CN.md +42 -7
- package/dist/cli-ui/cmd-handlers.d.ts +22 -1
- package/dist/cli-ui/cmd-handlers.d.ts.map +1 -1
- package/dist/cli-ui/cmd-handlers.js +304 -40
- package/dist/cli-ui/cmd-handlers.js.map +1 -1
- package/dist/cli-ui/config-wizard.d.ts +13 -1
- package/dist/cli-ui/config-wizard.d.ts.map +1 -1
- package/dist/cli-ui/config-wizard.js +93 -21
- package/dist/cli-ui/config-wizard.js.map +1 -1
- package/dist/cli-ui/doctor.d.ts +15 -0
- package/dist/cli-ui/doctor.d.ts.map +1 -0
- package/dist/cli-ui/doctor.js +151 -0
- package/dist/cli-ui/doctor.js.map +1 -0
- package/dist/cli-ui/entry-menu.d.ts +6 -0
- package/dist/cli-ui/entry-menu.d.ts.map +1 -1
- package/dist/cli-ui/entry-menu.js +67 -30
- package/dist/cli-ui/entry-menu.js.map +1 -1
- package/dist/cli-ui/i18n.d.ts +15 -6
- package/dist/cli-ui/i18n.d.ts.map +1 -1
- package/dist/cli-ui/i18n.js +30 -12
- package/dist/cli-ui/i18n.js.map +1 -1
- package/dist/cli-ui/quickstart.d.ts +3 -0
- package/dist/cli-ui/quickstart.d.ts.map +1 -0
- package/dist/cli-ui/quickstart.js +108 -0
- package/dist/cli-ui/quickstart.js.map +1 -0
- package/dist/cli-ui/readiness.d.ts +10 -0
- package/dist/cli-ui/readiness.d.ts.map +1 -0
- package/dist/cli-ui/readiness.js +75 -0
- package/dist/cli-ui/readiness.js.map +1 -0
- package/dist/cli-ui/service.d.ts +23 -0
- package/dist/cli-ui/service.d.ts.map +1 -1
- package/dist/cli-ui/service.js +114 -5
- package/dist/cli-ui/service.js.map +1 -1
- package/dist/cli.js +99 -396
- package/dist/cli.js.map +1 -1
- package/dist/core/acp-server.d.ts.map +1 -1
- package/dist/core/acp-server.js +16 -2
- package/dist/core/acp-server.js.map +1 -1
- package/dist/core/agent-cwd.d.ts +8 -0
- package/dist/core/agent-cwd.d.ts.map +1 -1
- package/dist/core/agent-cwd.js +57 -7
- package/dist/core/agent-cwd.js.map +1 -1
- package/dist/core/commands/builtin.d.ts.map +1 -1
- package/dist/core/commands/builtin.js +12 -2
- package/dist/core/commands/builtin.js.map +1 -1
- package/dist/core/commands/model.d.ts.map +1 -1
- package/dist/core/commands/model.js +31 -2
- package/dist/core/commands/model.js.map +1 -1
- package/dist/core/llm/anthropic-provider.js +2 -1
- package/dist/core/llm/anthropic-provider.js.map +1 -1
- package/dist/core/llm/openai-compat-provider.js +3 -2
- package/dist/core/llm/openai-compat-provider.js.map +1 -1
- package/dist/core/llm/provider-base.d.ts +4 -4
- package/dist/core/llm/provider-base.d.ts.map +1 -1
- package/dist/core/llm/provider-base.js +1 -1
- package/dist/core/llm/provider-base.js.map +1 -1
- package/dist/plugins/agents/native/index.d.ts +1 -0
- package/dist/plugins/agents/native/index.d.ts.map +1 -1
- package/dist/plugins/agents/native/index.js +14 -0
- package/dist/plugins/agents/native/index.js.map +1 -1
- package/dist/plugins/agents/pi-native/factory.d.ts.map +1 -1
- package/dist/plugins/agents/pi-native/factory.js +19 -3
- package/dist/plugins/agents/pi-native/factory.js.map +1 -1
- package/dist/plugins/agents/pi-native/index.d.ts +11 -0
- package/dist/plugins/agents/pi-native/index.d.ts.map +1 -1
- package/dist/plugins/agents/pi-native/index.js +56 -2
- package/dist/plugins/agents/pi-native/index.js.map +1 -1
- package/dist/plugins/agents/pi-native/provider-resolver.d.ts +2 -0
- package/dist/plugins/agents/pi-native/provider-resolver.d.ts.map +1 -1
- package/dist/plugins/agents/pi-native/provider-resolver.js +9 -1
- package/dist/plugins/agents/pi-native/provider-resolver.js.map +1 -1
- package/dist/web/public/assets/a2a-CTsDMefo.js +7 -0
- package/dist/web/public/assets/a2a-CTsDMefo.js.map +1 -0
- package/dist/web/public/assets/{activity-BAgb2WZC.js → activity-ul8Os7Pz.js} +2 -2
- package/dist/web/public/assets/{activity-BAgb2WZC.js.map → activity-ul8Os7Pz.js.map} +1 -1
- package/dist/web/public/assets/{admins-CZYANmhn.js → admins-ByMAuquy.js} +3 -3
- package/dist/web/public/assets/{admins-CZYANmhn.js.map → admins-ByMAuquy.js.map} +1 -1
- package/dist/web/public/assets/agents-Ds1zyxBj.js +2 -0
- package/dist/web/public/assets/{agents-BXThDW6f.js.map → agents-Ds1zyxBj.js.map} +1 -1
- package/dist/web/public/assets/{approvals-ByPXIYVl.js → approvals-DOWlWI7Z.js} +3 -3
- package/dist/web/public/assets/{approvals-ByPXIYVl.js.map → approvals-DOWlWI7Z.js.map} +1 -1
- package/dist/web/public/assets/{arrow-down-B8DkdbEY.js → arrow-down-7i0xwCI2.js} +2 -2
- package/dist/web/public/assets/{arrow-down-B8DkdbEY.js.map → arrow-down-7i0xwCI2.js.map} +1 -1
- package/dist/web/public/assets/arrow-right-A889Wof8.js +7 -0
- package/dist/web/public/assets/arrow-right-A889Wof8.js.map +1 -0
- package/dist/web/public/assets/{arrow-up-i_dEdXkz.js → arrow-up-Dm0U4-6U.js} +2 -2
- package/dist/web/public/assets/{arrow-up-i_dEdXkz.js.map → arrow-up-Dm0U4-6U.js.map} +1 -1
- package/dist/web/public/assets/{asks-yD_inOnM.js → asks-DGuBsrJ7.js} +3 -3
- package/dist/web/public/assets/{asks-yD_inOnM.js.map → asks-DGuBsrJ7.js.map} +1 -1
- package/dist/web/public/assets/{audit-teCIRtgN.js → audit-BRXsplJ2.js} +2 -2
- package/dist/web/public/assets/{audit-teCIRtgN.js.map → audit-BRXsplJ2.js.map} +1 -1
- package/dist/web/public/assets/{bell-CeWDMs8_.js → bell-B-UdeJsp.js} +2 -2
- package/dist/web/public/assets/{bell-CeWDMs8_.js.map → bell-B-UdeJsp.js.map} +1 -1
- package/dist/web/public/assets/bgjobs-CcRiffyJ.js +2 -0
- package/dist/web/public/assets/bgjobs-CcRiffyJ.js.map +1 -0
- package/dist/web/public/assets/book-open-CSCq5cjL.js +7 -0
- package/dist/web/public/assets/book-open-CSCq5cjL.js.map +1 -0
- package/dist/web/public/assets/{brain-BQqv0Zhc.js → brain-Dl4DF5kX.js} +2 -2
- package/dist/web/public/assets/{brain-BQqv0Zhc.js.map → brain-Dl4DF5kX.js.map} +1 -1
- package/dist/web/public/assets/{briefcase-DUXbR4xs.js → briefcase-CeKUkFSq.js} +2 -2
- package/dist/web/public/assets/{briefcase-DUXbR4xs.js.map → briefcase-CeKUkFSq.js.map} +1 -1
- package/dist/web/public/assets/chat-rLJMdJBk.js +12 -0
- package/dist/web/public/assets/chat-rLJMdJBk.js.map +1 -0
- package/dist/web/public/assets/{chevron-left-RC6mMSiX.js → chevron-left-01fAFVpo.js} +2 -2
- package/dist/web/public/assets/{chevron-left-RC6mMSiX.js.map → chevron-left-01fAFVpo.js.map} +1 -1
- package/dist/web/public/assets/{chevron-right-DrkYVi19.js → chevron-right-CFRb-SM_.js} +3 -3
- package/dist/web/public/assets/{chevron-right-DrkYVi19.js.map → chevron-right-CFRb-SM_.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-big-BC8ntMsz.js → circle-check-big-DBg2BD6o.js} +2 -2
- package/dist/web/public/assets/{circle-check-big-BC8ntMsz.js.map → circle-check-big-DBg2BD6o.js.map} +1 -1
- package/dist/web/public/assets/{circle-x-DHK7ypFY.js → circle-x-CqFMzO-x.js} +2 -2
- package/dist/web/public/assets/{circle-x-DHK7ypFY.js.map → circle-x-CqFMzO-x.js.map} +1 -1
- package/dist/web/public/assets/clipboard-list-lnqdk2_J.js +7 -0
- package/dist/web/public/assets/clipboard-list-lnqdk2_J.js.map +1 -0
- package/dist/web/public/assets/{clock-DXHhWqJH.js → clock-4hd1joQe.js} +3 -3
- package/dist/web/public/assets/{clock-DXHhWqJH.js.map → clock-4hd1joQe.js.map} +1 -1
- package/dist/web/public/assets/confirm-dialog-BDb0NLny.js +2 -0
- package/dist/web/public/assets/{confirm-dialog-gPKJnvEW.js.map → confirm-dialog-BDb0NLny.js.map} +1 -1
- package/dist/web/public/assets/{copy-DtQxgcR0.js → copy-CD4A7VD8.js} +3 -3
- package/dist/web/public/assets/{copy-DtQxgcR0.js.map → copy-CD4A7VD8.js.map} +1 -1
- package/dist/web/public/assets/dashboard-CG3WiG7h.js +2 -0
- package/dist/web/public/assets/dashboard-CG3WiG7h.js.map +1 -0
- package/dist/web/public/assets/{data-table-DOKUic1J.js → data-table-BkUshOZz.js} +2 -2
- package/dist/web/public/assets/{data-table-DOKUic1J.js.map → data-table-BkUshOZz.js.map} +1 -1
- package/dist/web/public/assets/database-lQzk64rV.js +7 -0
- package/dist/web/public/assets/database-lQzk64rV.js.map +1 -0
- package/dist/web/public/assets/{distill-p6P7-1UR.js → distill-CPurVW3v.js} +3 -3
- package/dist/web/public/assets/{distill-p6P7-1UR.js.map → distill-CPurVW3v.js.map} +1 -1
- package/dist/web/public/assets/{download-CqNiIHa8.js → download-CVZnHcwj.js} +2 -2
- package/dist/web/public/assets/{download-CqNiIHa8.js.map → download-CVZnHcwj.js.map} +1 -1
- package/dist/web/public/assets/dropdown-menu-BNH5SrVb.js +7 -0
- package/dist/web/public/assets/dropdown-menu-BNH5SrVb.js.map +1 -0
- package/dist/web/public/assets/{email-DwbfTUlV.js → email-YlI4MWLp.js} +3 -3
- package/dist/web/public/assets/{email-DwbfTUlV.js.map → email-YlI4MWLp.js.map} +1 -1
- package/dist/web/public/assets/{empty-state-CTwOQemt.js → empty-state-CuiqdZiB.js} +2 -2
- package/dist/web/public/assets/{empty-state-CTwOQemt.js.map → empty-state-CuiqdZiB.js.map} +1 -1
- package/dist/web/public/assets/{external-link-BY7Ye8yi.js → external-link-1WPpVvdu.js} +2 -2
- package/dist/web/public/assets/{external-link-BY7Ye8yi.js.map → external-link-1WPpVvdu.js.map} +1 -1
- package/dist/web/public/assets/{eye-6RUADoDS.js → eye-BfPyNFzk.js} +2 -2
- package/dist/web/public/assets/{eye-6RUADoDS.js.map → eye-BfPyNFzk.js.map} +1 -1
- package/dist/web/public/assets/{facts-DXE0aJmb.js → facts-xT_24pH8.js} +2 -2
- package/dist/web/public/assets/{facts-DXE0aJmb.js.map → facts-xT_24pH8.js.map} +1 -1
- package/dist/web/public/assets/file-text-BxfdLM0-.js +7 -0
- package/dist/web/public/assets/file-text-BxfdLM0-.js.map +1 -0
- package/dist/web/public/assets/{goals-C1LCm3qL.js → goals-C8ZQfbhj.js} +3 -3
- package/dist/web/public/assets/{goals-C1LCm3qL.js.map → goals-C8ZQfbhj.js.map} +1 -1
- package/dist/web/public/assets/health-A2StNEfn.js +2 -0
- package/dist/web/public/assets/{health-wqCp-K_o.js.map → health-A2StNEfn.js.map} +1 -1
- package/dist/web/public/assets/{heart-pulse-DfqI4GF7.js → heart-pulse-DXlE9oic.js} +2 -2
- package/dist/web/public/assets/{heart-pulse-DfqI4GF7.js.map → heart-pulse-DXlE9oic.js.map} +1 -1
- package/dist/web/public/assets/{heartbeat-Bumv4XtQ.js → heartbeat-ClO5gJrj.js} +3 -3
- package/dist/web/public/assets/{heartbeat-Bumv4XtQ.js.map → heartbeat-ClO5gJrj.js.map} +1 -1
- package/dist/web/public/assets/hot-bfTA-V_z.js +7 -0
- package/dist/web/public/assets/{hot-B-CMjQIr.js.map → hot-bfTA-V_z.js.map} +1 -1
- package/dist/web/public/assets/index-Bi2qWb-u.css +1 -0
- package/dist/web/public/assets/index-DCfdN5R7.js +244 -0
- package/dist/web/public/assets/index-DCfdN5R7.js.map +1 -0
- package/dist/web/public/assets/{injection-Dn_XqgLG.js → injection-omvCR6-p.js} +2 -2
- package/dist/web/public/assets/{injection-Dn_XqgLG.js.map → injection-omvCR6-p.js.map} +1 -1
- package/dist/web/public/assets/{installed-Cet-1M2Q.js → installed-DL6r3ktm.js} +4 -9
- package/dist/web/public/assets/installed-DL6r3ktm.js.map +1 -0
- package/dist/web/public/assets/jobs-Biy5lYd4.js +2 -0
- package/dist/web/public/assets/jobs-Biy5lYd4.js.map +1 -0
- package/dist/web/public/assets/layout-BLm6NJ3V.js +2 -0
- package/dist/web/public/assets/layout-BLm6NJ3V.js.map +1 -0
- package/dist/web/public/assets/layout-BTKafRVZ.js +2 -0
- package/dist/web/public/assets/layout-BTKafRVZ.js.map +1 -0
- package/dist/web/public/assets/layout-Bm-2s2fp.js +2 -0
- package/dist/web/public/assets/layout-Bm-2s2fp.js.map +1 -0
- package/dist/web/public/assets/layout-DsZ8eR4i.js +2 -0
- package/dist/web/public/assets/layout-DsZ8eR4i.js.map +1 -0
- package/dist/web/public/assets/{layout-D_3ZcVG7.js → layout-sxvovjEH.js} +2 -2
- package/dist/web/public/assets/{layout-D_3ZcVG7.js.map → layout-sxvovjEH.js.map} +1 -1
- package/dist/web/public/assets/llm-JjZDbBvJ.js +37 -0
- package/dist/web/public/assets/llm-JjZDbBvJ.js.map +1 -0
- package/dist/web/public/assets/loader-circle-DDdmcH0k.js +7 -0
- package/dist/web/public/assets/{loader-circle-DgdBWYl0.js.map → loader-circle-DDdmcH0k.js.map} +1 -1
- package/dist/web/public/assets/{map-pin-3QS1A0-I.js → map-pin-C_jAxukI.js} +2 -2
- package/dist/web/public/assets/{map-pin-3QS1A0-I.js.map → map-pin-C_jAxukI.js.map} +1 -1
- package/dist/web/public/assets/{mcp-DwKZULET.js → mcp-vKajK1F8.js} +3 -3
- package/dist/web/public/assets/{mcp-DwKZULET.js.map → mcp-vKajK1F8.js.map} +1 -1
- package/dist/web/public/assets/memos-DAt4k3DO.js +7 -0
- package/dist/web/public/assets/memos-DAt4k3DO.js.map +1 -0
- package/dist/web/public/assets/messengers-GYVTFlAj.js +2 -0
- package/dist/web/public/assets/messengers-GYVTFlAj.js.map +1 -0
- package/dist/web/public/assets/{mobile-Bq0FH9JV.js → mobile-VUyTo40E.js} +3 -3
- package/dist/web/public/assets/{mobile-Bq0FH9JV.js.map → mobile-VUyTo40E.js.map} +1 -1
- package/dist/web/public/assets/{network--s113Jkm.js → network-BUeWK3bs.js} +2 -2
- package/dist/web/public/assets/{network--s113Jkm.js.map → network-BUeWK3bs.js.map} +1 -1
- package/dist/web/public/assets/outbox-CEE0rwN3.js +2 -0
- package/dist/web/public/assets/outbox-CEE0rwN3.js.map +1 -0
- package/dist/web/public/assets/overview-BSOZ5gTD.js +12 -0
- package/dist/web/public/assets/overview-BSOZ5gTD.js.map +1 -0
- package/dist/web/public/assets/overview-COop5K2Y.js +12 -0
- package/dist/web/public/assets/overview-COop5K2Y.js.map +1 -0
- package/dist/web/public/assets/overview-DeH5ud6d.js +2 -0
- package/dist/web/public/assets/overview-DeH5ud6d.js.map +1 -0
- package/dist/web/public/assets/{pagination-DkdCTctJ.js → pagination-BBicLzXP.js} +3 -3
- package/dist/web/public/assets/{pagination-DkdCTctJ.js.map → pagination-BBicLzXP.js.map} +1 -1
- package/dist/web/public/assets/persona-CElXQZ4p.js +2 -0
- package/dist/web/public/assets/{persona-BvtcZh6G.js.map → persona-CElXQZ4p.js.map} +1 -1
- package/dist/web/public/assets/{plans-i3a6lrqF.js → plans-Bo5LlLeH.js} +3 -8
- package/dist/web/public/assets/plans-Bo5LlLeH.js.map +1 -0
- package/dist/web/public/assets/{play-CPoE_JnS.js → play-DX5wp4WH.js} +2 -2
- package/dist/web/public/assets/{play-CPoE_JnS.js.map → play-DX5wp4WH.js.map} +1 -1
- package/dist/web/public/assets/{plus-CfzKV_0u.js → plus-DH4J_YhN.js} +2 -2
- package/dist/web/public/assets/{plus-CfzKV_0u.js.map → plus-DH4J_YhN.js.map} +1 -1
- package/dist/web/public/assets/policy-BrgOuDt_.js +2 -0
- package/dist/web/public/assets/{policy-Cm88P8LO.js.map → policy-BrgOuDt_.js.map} +1 -1
- package/dist/web/public/assets/{qr-code-DMkV8nv2.js → qr-code-YrEuhMPC.js} +2 -2
- package/dist/web/public/assets/{qr-code-DMkV8nv2.js.map → qr-code-YrEuhMPC.js.map} +1 -1
- package/dist/web/public/assets/{refresh-ccw-nBMm5Xal.js → refresh-ccw-DlAd-eTQ.js} +2 -2
- package/dist/web/public/assets/{refresh-ccw-nBMm5Xal.js.map → refresh-ccw-DlAd-eTQ.js.map} +1 -1
- package/dist/web/public/assets/{reminders-DjEujanC.js → reminders-DBEE0zXG.js} +3 -3
- package/dist/web/public/assets/{reminders-DjEujanC.js.map → reminders-DBEE0zXG.js.map} +1 -1
- package/dist/web/public/assets/{save-DbrrCFDM.js → save-BDOtZrfp.js} +2 -2
- package/dist/web/public/assets/{save-DbrrCFDM.js.map → save-BDOtZrfp.js.map} +1 -1
- package/dist/web/public/assets/schedules-DAyhVI8-.js +2 -0
- package/dist/web/public/assets/schedules-DAyhVI8-.js.map +1 -0
- package/dist/web/public/assets/{search-5q3dkINm.js → search-55mtgHrB.js} +3 -3
- package/dist/web/public/assets/{search-5q3dkINm.js.map → search-55mtgHrB.js.map} +1 -1
- package/dist/web/public/assets/{search-DbE4VEm9.js → search-CAICU3aU.js} +2 -2
- package/dist/web/public/assets/{search-DbE4VEm9.js.map → search-CAICU3aU.js.map} +1 -1
- package/dist/web/public/assets/security-CbP4QgVp.js +2 -0
- package/dist/web/public/assets/security-CbP4QgVp.js.map +1 -0
- package/dist/web/public/assets/server-Dg4e8pvm.js +7 -0
- package/dist/web/public/assets/server-Dg4e8pvm.js.map +1 -0
- package/dist/web/public/assets/service-gWZa3sup.js +7 -0
- package/dist/web/public/assets/service-gWZa3sup.js.map +1 -0
- package/dist/web/public/assets/{shield-alert-WOa69jy3.js → shield-alert-DOKK9EnJ.js} +2 -2
- package/dist/web/public/assets/{shield-alert-WOa69jy3.js.map → shield-alert-DOKK9EnJ.js.map} +1 -1
- package/dist/web/public/assets/sparkles-G0QIs9nP.js +7 -0
- package/dist/web/public/assets/sparkles-G0QIs9nP.js.map +1 -0
- package/dist/web/public/assets/start-D-abhl3q.js +2 -0
- package/dist/web/public/assets/start-D-abhl3q.js.map +1 -0
- package/dist/web/public/assets/{status-badge-D5xhwquL.js → status-badge-CyLdpsXq.js} +2 -2
- package/dist/web/public/assets/{status-badge-D5xhwquL.js.map → status-badge-CyLdpsXq.js.map} +1 -1
- package/dist/web/public/assets/{subtasks-DMRyk6YS.js → subtasks-BnEjSGUR.js} +3 -3
- package/dist/web/public/assets/{subtasks-DMRyk6YS.js.map → subtasks-BnEjSGUR.js.map} +1 -1
- package/dist/web/public/assets/{table-Dx65w6V0.js → table-sCMZBe_Z.js} +2 -2
- package/dist/web/public/assets/{table-Dx65w6V0.js.map → table-sCMZBe_Z.js.map} +1 -1
- package/dist/web/public/assets/terminal-_pXeEjXG.js +7 -0
- package/dist/web/public/assets/terminal-_pXeEjXG.js.map +1 -0
- package/dist/web/public/assets/{topn-L7Juczp3.js → topn-D1B-gS1M.js} +3 -3
- package/dist/web/public/assets/{topn-L7Juczp3.js.map → topn-D1B-gS1M.js.map} +1 -1
- package/dist/web/public/assets/{trash-2-7xrfqd-v.js → trash-2-D2x2UPuZ.js} +2 -2
- package/dist/web/public/assets/{trash-2-7xrfqd-v.js.map → trash-2-D2x2UPuZ.js.map} +1 -1
- package/dist/web/public/assets/use-a2a-C98e2Via.js +2 -0
- package/dist/web/public/assets/use-a2a-C98e2Via.js.map +1 -0
- package/dist/web/public/assets/{use-agim-skills-pFjfgqMF.js → use-agim-skills-BbuJP3NT.js} +2 -2
- package/dist/web/public/assets/{use-agim-skills-pFjfgqMF.js.map → use-agim-skills-BbuJP3NT.js.map} +1 -1
- package/dist/web/public/assets/use-background-tasks-CwFmOokw.js +2 -0
- package/dist/web/public/assets/{use-background-tasks-D1--hHjp.js.map → use-background-tasks-CwFmOokw.js.map} +1 -1
- package/dist/web/public/assets/use-jobs-BJjeJ5lh.js +2 -0
- package/dist/web/public/assets/use-jobs-BJjeJ5lh.js.map +1 -0
- package/dist/web/public/assets/use-memory-CXDwKCco.js +2 -0
- package/dist/web/public/assets/{use-memory-Bz1Zao7g.js.map → use-memory-CXDwKCco.js.map} +1 -1
- package/dist/web/public/assets/use-observability-CY5ZUPrC.js +2 -0
- package/dist/web/public/assets/{use-observability-DtqSWVjM.js.map → use-observability-CY5ZUPrC.js.map} +1 -1
- package/dist/web/public/assets/use-outbox-DT_XWB_7.js +7 -0
- package/dist/web/public/assets/use-outbox-DT_XWB_7.js.map +1 -0
- package/dist/web/public/assets/use-schedules-D4W8fMwo.js +7 -0
- package/dist/web/public/assets/use-schedules-D4W8fMwo.js.map +1 -0
- package/dist/web/public/assets/use-settings-DGIjmUX0.js +2 -0
- package/dist/web/public/assets/use-settings-DGIjmUX0.js.map +1 -0
- package/dist/web/public/assets/use-skills-D2bMM580.js +7 -0
- package/dist/web/public/assets/use-skills-D2bMM580.js.map +1 -0
- package/dist/web/public/assets/use-vector-BYOFwjU0.js +2 -0
- package/dist/web/public/assets/use-vector-BYOFwjU0.js.map +1 -0
- package/dist/web/public/assets/use-workspace-CuytyHwb.js +2 -0
- package/dist/web/public/assets/{use-workspace-CConjEx0.js.map → use-workspace-CuytyHwb.js.map} +1 -1
- package/dist/web/public/assets/vector-CL8ezpSR.js +2 -0
- package/dist/web/public/assets/vector-CL8ezpSR.js.map +1 -0
- package/dist/web/public/assets/viewer-CD0iEfPU.js +7 -0
- package/dist/web/public/assets/viewer-CD0iEfPU.js.map +1 -0
- package/dist/web/public/assets/workspace-BA1_hso3.js +17 -0
- package/dist/web/public/assets/workspace-BA1_hso3.js.map +1 -0
- package/dist/web/public/assets/workspaces-DyGLJUgB.js +7 -0
- package/dist/web/public/assets/workspaces-DyGLJUgB.js.map +1 -0
- package/dist/web/public/index.html +2 -2
- package/dist/web/server.d.ts +0 -3
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +138 -3
- package/dist/web/server.js.map +1 -1
- package/package.json +1 -1
- package/dist/web/public/assets/a2a-D7MoJ1iT.js +0 -7
- package/dist/web/public/assets/a2a-D7MoJ1iT.js.map +0 -1
- package/dist/web/public/assets/agents-BXThDW6f.js +0 -7
- package/dist/web/public/assets/bgjobs-Rc05aEy9.js +0 -7
- package/dist/web/public/assets/bgjobs-Rc05aEy9.js.map +0 -1
- package/dist/web/public/assets/chat-DQpQLW9j.js +0 -17
- package/dist/web/public/assets/chat-DQpQLW9j.js.map +0 -1
- package/dist/web/public/assets/circle-check-DZnkaUdk.js +0 -7
- package/dist/web/public/assets/circle-check-DZnkaUdk.js.map +0 -1
- package/dist/web/public/assets/confirm-dialog-gPKJnvEW.js +0 -2
- package/dist/web/public/assets/health-wqCp-K_o.js +0 -2
- package/dist/web/public/assets/hot-B-CMjQIr.js +0 -12
- package/dist/web/public/assets/index-DHh1LYlA.js +0 -209
- package/dist/web/public/assets/index-DHh1LYlA.js.map +0 -1
- package/dist/web/public/assets/index-DknVjPYB.css +0 -1
- package/dist/web/public/assets/installed-Cet-1M2Q.js.map +0 -1
- package/dist/web/public/assets/jobs-CfEzOOAC.js +0 -2
- package/dist/web/public/assets/jobs-CfEzOOAC.js.map +0 -1
- package/dist/web/public/assets/layout-BX43KyXM.js +0 -2
- package/dist/web/public/assets/layout-BX43KyXM.js.map +0 -1
- package/dist/web/public/assets/layout-BcYZlaqf.js +0 -2
- package/dist/web/public/assets/layout-BcYZlaqf.js.map +0 -1
- package/dist/web/public/assets/layout-Cb7looUv.js +0 -2
- package/dist/web/public/assets/layout-Cb7looUv.js.map +0 -1
- package/dist/web/public/assets/layout-D7xH78OU.js +0 -2
- package/dist/web/public/assets/layout-D7xH78OU.js.map +0 -1
- package/dist/web/public/assets/llm-BZ9qqp-D.js +0 -27
- package/dist/web/public/assets/llm-BZ9qqp-D.js.map +0 -1
- package/dist/web/public/assets/loader-circle-DgdBWYl0.js +0 -7
- package/dist/web/public/assets/memos-BBtqFcoH.js +0 -12
- package/dist/web/public/assets/memos-BBtqFcoH.js.map +0 -1
- package/dist/web/public/assets/messengers-i7WvNT3o.js +0 -2
- package/dist/web/public/assets/messengers-i7WvNT3o.js.map +0 -1
- package/dist/web/public/assets/outbox-BbfC5kuG.js +0 -7
- package/dist/web/public/assets/outbox-BbfC5kuG.js.map +0 -1
- package/dist/web/public/assets/persona-BvtcZh6G.js +0 -2
- package/dist/web/public/assets/plans-i3a6lrqF.js.map +0 -1
- package/dist/web/public/assets/policy-Cm88P8LO.js +0 -2
- package/dist/web/public/assets/schedules-DzwDWykc.js +0 -7
- package/dist/web/public/assets/schedules-DzwDWykc.js.map +0 -1
- package/dist/web/public/assets/security-BIcnUrAs.js +0 -2
- package/dist/web/public/assets/security-BIcnUrAs.js.map +0 -1
- package/dist/web/public/assets/service-CnorFHzZ.js +0 -7
- package/dist/web/public/assets/service-CnorFHzZ.js.map +0 -1
- package/dist/web/public/assets/use-background-tasks-D1--hHjp.js +0 -2
- package/dist/web/public/assets/use-memory-Bz1Zao7g.js +0 -2
- package/dist/web/public/assets/use-observability-DtqSWVjM.js +0 -2
- package/dist/web/public/assets/use-settings-DKbDqCEJ.js +0 -2
- package/dist/web/public/assets/use-settings-DKbDqCEJ.js.map +0 -1
- package/dist/web/public/assets/use-workspace-CConjEx0.js +0 -2
- package/dist/web/public/assets/vector-D8sEa2W-.js +0 -2
- package/dist/web/public/assets/vector-D8sEa2W-.js.map +0 -1
- package/dist/web/public/assets/viewer-aSIjAKVA.js +0 -12
- package/dist/web/public/assets/viewer-aSIjAKVA.js.map +0 -1
- package/dist/web/public/assets/workspace-BqwWoinI.js +0 -17
- package/dist/web/public/assets/workspace-BqwWoinI.js.map +0 -1
- package/dist/web/public/assets/workspaces-ChsJcrav.js +0 -7
- package/dist/web/public/assets/workspaces-ChsJcrav.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-DwKZULET.js","sources":["../../node_modules/lucide-react/dist/esm/icons/server-cog.js","../../src/routes/settings/mcp.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 ServerCog = createLucideIcon(\"ServerCog\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"3\", key: \"1v7zrd\" }],\n [\n \"path\",\n {\n d: \"M4.5 10H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-.5\",\n key: \"tn8das\"\n }\n ],\n [\n \"path\",\n {\n d: \"M4.5 14H4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2h-.5\",\n key: \"1g2pve\"\n }\n ],\n [\"path\", { d: \"M6 6h.01\", key: \"1utrut\" }],\n [\"path\", { d: \"M6 18h.01\", key: \"uhywen\" }],\n [\"path\", { d: \"m15.7 13.4-.9-.3\", key: \"1jwmzr\" }],\n [\"path\", { d: \"m9.2 10.9-.9-.3\", key: \"qapnim\" }],\n [\"path\", { d: \"m10.6 15.7.3-.9\", key: \"quwk0k\" }],\n [\"path\", { d: \"m13.6 15.7-.4-1\", key: \"cb9xp7\" }],\n [\"path\", { d: \"m10.8 9.3-.4-1\", key: \"1uaiz5\" }],\n [\"path\", { d: \"m8.3 13.6 1-.4\", key: \"s6srou\" }],\n [\"path\", { d: \"m14.7 10.8 1-.4\", key: \"4d31cq\" }],\n [\"path\", { d: \"m13.4 8.3-.3.9\", key: \"1bm987\" }]\n]);\n\nexport { ServerCog as default };\n//# sourceMappingURL=server-cog.js.map\n","/**\n * /settings/mcp — external MCP servers admin (Stage 6).\n *\n * Front-end for the `/api/mcp/*` REST surface. List configured servers,\n * see their connection status + tool count, add stdio / HTTP / SSE\n * servers, probe per-server health, remove.\n *\n * The native agent loop consumes any tools advertised here; CLI agents\n * have their own MCP configs and ignore this list. See\n * docs/llm-backends.md § External MCP servers.\n */\n\nimport { useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Loader2, Plus, RefreshCcw, ServerCog, Trash2, Activity } 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, SelectContent, SelectItem, SelectTrigger, SelectValue,\n} from '@/components/ui/select'\nimport {\n Table, TableBody, TableCell, TableHead, TableHeader, TableRow,\n} from '@/components/ui/table'\nimport {\n useMcpList, useMcpAddServer, useMcpRemoveServer, useMcpHealth,\n type McpServerRow,\n} from '@/hooks/use-llm-admin'\n\nexport default function SettingsMcpRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const listQuery = useMcpList()\n return (\n <div className=\"mx-auto flex max-w-5xl flex-col gap-6\">\n <header className=\"flex items-center gap-3\">\n <ServerCog className=\"h-5 w-5 text-text-dim\" />\n <h1 className=\"text-xl font-semibold\">{t('mcp.title')}</h1>\n <Button\n variant=\"ghost\" size=\"sm\" className=\"ml-auto\"\n onClick={() => void listQuery.refetch()}\n disabled={listQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {listQuery.isFetching\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('mcp.refresh')}</span>\n </Button>\n </header>\n <p className=\"text-sm text-text-dim\">{t('mcp.subtitle')}</p>\n\n {listQuery.isLoading ? (\n <div className=\"h-48 rounded-md bg-surface-2 animate-pulse\" />\n ) : (\n <>\n <ServersCard data={listQuery.data} />\n <AddServerCard />\n </>\n )}\n </div>\n )\n}\n\n/* ─────────────── Servers list ─────────────── */\n\nfunction ServersCard({ data }: { data: ReturnType<typeof useMcpList>['data'] }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const removeServer = useMcpRemoveServer()\n const health = useMcpHealth()\n const [healthResults, setHealthResults] = useState<Record<string, string>>({})\n\n async function onRemove(name: string): Promise<void> {\n if (!confirm(t('mcp.removeConfirm', { name }))) return\n try {\n await removeServer.mutateAsync(name)\n toast.success(t('mcp.removedToast', { name }))\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n async function onHealth(name: string): Promise<void> {\n setHealthResults((m) => ({ ...m, [name]: t('mcp.probing') }))\n try {\n const r = await health.mutateAsync(name)\n const msg = r.connected\n ? `✓ ${r.toolCount === 1\n ? t('mcp.runtimeConnectedOne', { count: r.toolCount })\n : t('mcp.runtimeConnected', { count: r.toolCount })}`\n : `✗ ${r.lastError ?? t('mcp.runtimeDisconnected')}`\n setHealthResults((m) => ({ ...m, [name]: msg }))\n } catch (err) {\n setHealthResults((m) => ({ ...m, [name]: `✗ ${((err as Error)?.message ?? String(err))}` }))\n }\n }\n\n const rows = data?.servers ?? []\n const runtime = data?.runtime?.servers ?? []\n if (rows.length === 0) {\n return (\n <section className=\"rounded-md border border-border bg-surface p-6 text-center text-sm text-text-dim\">\n {t('mcp.serversEmpty')}\n </section>\n )\n }\n\n return (\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 <h2 className=\"text-sm font-semibold\">{t('mcp.serversTitle', { count: rows.length })}</h2>\n {data?.runtime && (\n <Badge variant=\"info\">{t('mcp.totalTools', { count: data.runtime.totalTools })}</Badge>\n )}\n </header>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>{t('mcp.col.name')}</TableHead>\n <TableHead>{t('mcp.col.transport')}</TableHead>\n <TableHead>{t('mcp.col.target')}</TableHead>\n <TableHead>{t('mcp.col.runtime')}</TableHead>\n <TableHead>{t('mcp.col.actions')}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {rows.map((s) => {\n const rt = runtime.find((r) => r.name === s.name)\n const transport = transportLabel(s, t)\n const target = s.command\n ? `${s.command} ${(s.args ?? []).join(' ')}`.trim()\n : (s.url ?? '—')\n const runtimeBadge = !rt\n ? <Badge variant=\"outline\">{t('mcp.runtimeUnknown')}</Badge>\n : rt.connected\n ? <Badge variant=\"success\">\n {rt.toolCount === 1\n ? t('mcp.runtimeConnectedOne', { count: rt.toolCount })\n : t('mcp.runtimeConnected', { count: rt.toolCount })}\n </Badge>\n : <Badge variant=\"danger\">{t('mcp.runtimeDisconnected')}</Badge>\n return (\n <TableRow key={s.name}>\n <TableCell className=\"font-mono text-xs\">{s.name}</TableCell>\n <TableCell>{transport}</TableCell>\n <TableCell className=\"break-all font-mono text-[11px] text-text-dim\">{target}</TableCell>\n <TableCell>{runtimeBadge}</TableCell>\n <TableCell className=\"flex flex-col gap-1 sm:flex-row sm:items-center\">\n <Button\n variant=\"ghost\" size=\"sm\"\n onClick={() => void onHealth(s.name)}\n disabled={health.isPending}\n >\n <Activity className=\"h-4 w-4\" />\n <span>{t('mcp.health')}</span>\n </Button>\n <Button\n variant=\"ghost\" size=\"sm\"\n onClick={() => void onRemove(s.name)}\n disabled={removeServer.isPending}\n className=\"text-danger hover:text-danger\"\n >\n <Trash2 className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">{t('mcp.remove')}</span>\n </Button>\n {healthResults[s.name] && (\n <span className=\"ml-2 text-[11px] text-text-dim\">{healthResults[s.name]}</span>\n )}\n </TableCell>\n </TableRow>\n )\n })}\n </TableBody>\n </Table>\n </section>\n )\n}\n\nfunction transportLabel(\n s: McpServerRow,\n t: (key: string) => string,\n): string {\n if (s.command) return t('mcp.transportStdio')\n if (s.url) return s.url.endsWith('/sse') ? t('mcp.transportSse') : t('mcp.transportHttp')\n return '—'\n}\n\n/* ─────────────── Add server form ─────────────── */\n\nfunction AddServerCard(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const addServer = useMcpAddServer()\n const [name, setName] = useState('')\n const [transport, setTransport] = useState<'stdio' | 'http'>('stdio')\n const [command, setCommand] = useState('')\n const [args, setArgs] = useState('')\n const [url, setUrl] = useState('')\n const [headersJson, setHeadersJson] = useState('')\n\n async function onSubmit(e: React.FormEvent): Promise<void> {\n e.preventDefault()\n if (!name.trim()) { toast.error(t('mcp.nameRequired')); return }\n let headers: Record<string, string> | undefined\n if (headersJson.trim()) {\n try { headers = JSON.parse(headersJson) }\n catch { toast.error(t('mcp.headersInvalid')); return }\n }\n const body: Parameters<typeof addServer.mutateAsync>[0] = { name: name.trim() }\n if (transport === 'stdio') {\n if (!command.trim()) { toast.error(t('mcp.commandRequired')); return }\n body.command = command.trim()\n const splitArgs = args.split(/\\s+/).filter(Boolean)\n if (splitArgs.length > 0) body.args = splitArgs\n } else {\n if (!url.trim()) { toast.error(t('mcp.urlRequired')); return }\n body.url = url.trim()\n if (headers) body.headers = headers\n }\n try {\n await addServer.mutateAsync(body)\n toast.success(t('mcp.addedToast', { name: name.trim() }))\n setName(''); setCommand(''); setArgs(''); setUrl(''); setHeadersJson('')\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n return (\n <section className=\"rounded-md border border-border bg-surface\">\n <header className=\"border-b border-border px-4 py-3\">\n <h2 className=\"text-sm font-semibold\">{t('mcp.addTitle')}</h2>\n </header>\n <form onSubmit={(e) => void onSubmit(e)} className=\"grid grid-cols-1 gap-3 p-4 sm:grid-cols-2\">\n <div>\n <Label className=\"text-xs font-medium\">{t('mcp.nameLabel')}</Label>\n <Input\n value={name} onChange={(e) => setName(e.target.value)}\n placeholder={t('mcp.namePlaceholder')}\n className=\"font-mono text-xs\"\n />\n </div>\n <div>\n <Label className=\"text-xs font-medium\">{t('mcp.transportLabel')}</Label>\n <Select value={transport} onValueChange={(v) => setTransport(v as 'stdio' | 'http')}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"stdio\">{t('mcp.transportStdioOption')}</SelectItem>\n <SelectItem value=\"http\">{t('mcp.transportHttpOption')}</SelectItem>\n </SelectContent>\n </Select>\n </div>\n {transport === 'stdio' ? (\n <>\n <div>\n <Label className=\"text-xs font-medium\">{t('mcp.commandLabel')}</Label>\n <Input\n value={command} onChange={(e) => setCommand(e.target.value)}\n placeholder={t('mcp.commandPlaceholder')}\n className=\"font-mono text-xs\"\n />\n </div>\n <div>\n <Label className=\"text-xs font-medium\">{t('mcp.argsLabel')}</Label>\n <Input\n value={args} onChange={(e) => setArgs(e.target.value)}\n placeholder=\"-y @modelcontextprotocol/server-filesystem /data\"\n className=\"font-mono text-xs\"\n />\n </div>\n </>\n ) : (\n <>\n <div className=\"sm:col-span-2\">\n <Label className=\"text-xs font-medium\">{t('mcp.urlLabel')}</Label>\n <Input\n value={url} onChange={(e) => setUrl(e.target.value)}\n placeholder={t('mcp.urlPlaceholder')}\n className=\"font-mono text-xs\"\n />\n </div>\n <div className=\"sm:col-span-2\">\n <Label className=\"text-xs font-medium\">{t('mcp.headersLabel')}</Label>\n <Input\n value={headersJson} onChange={(e) => setHeadersJson(e.target.value)}\n placeholder={t('mcp.headersPlaceholder')}\n className=\"font-mono text-xs\"\n />\n </div>\n </>\n )}\n <div className=\"sm:col-span-2 flex\">\n <Button type=\"submit\" disabled={addServer.isPending} className=\"ml-auto\">\n {addServer.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Plus className=\"h-4 w-4\" />}\n {t('mcp.addServer')}\n </Button>\n </div>\n </form>\n </section>\n )\n}\n"],"names":["ServerCog","createLucideIcon","SettingsMcpRoute","useTranslation","listQuery","useMcpList","jsxs","jsx","Button","Loader2","RefreshCcw","Fragment","ServersCard","AddServerCard","data","t","removeServer","useMcpRemoveServer","health","useMcpHealth","healthResults","setHealthResults","useState","onRemove","name","toast","err","onHealth","m","msg","rows","runtime","Badge","Table","TableHeader","TableRow","TableHead","TableBody","s","rt","r","transport","transportLabel","target","runtimeBadge","TableCell","Activity","Trash2","addServer","useMcpAddServer","setName","setTransport","command","setCommand","args","setArgs","url","setUrl","headersJson","setHeadersJson","onSubmit","e","headers","body","splitArgs","Label","Input","Select","v","SelectTrigger","SelectValue","SelectContent","SelectItem","Plus"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"mcp-vKajK1F8.js","sources":["../../node_modules/lucide-react/dist/esm/icons/server-cog.js","../../src/routes/settings/mcp.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 ServerCog = createLucideIcon(\"ServerCog\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"3\", key: \"1v7zrd\" }],\n [\n \"path\",\n {\n d: \"M4.5 10H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-.5\",\n key: \"tn8das\"\n }\n ],\n [\n \"path\",\n {\n d: \"M4.5 14H4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2h-.5\",\n key: \"1g2pve\"\n }\n ],\n [\"path\", { d: \"M6 6h.01\", key: \"1utrut\" }],\n [\"path\", { d: \"M6 18h.01\", key: \"uhywen\" }],\n [\"path\", { d: \"m15.7 13.4-.9-.3\", key: \"1jwmzr\" }],\n [\"path\", { d: \"m9.2 10.9-.9-.3\", key: \"qapnim\" }],\n [\"path\", { d: \"m10.6 15.7.3-.9\", key: \"quwk0k\" }],\n [\"path\", { d: \"m13.6 15.7-.4-1\", key: \"cb9xp7\" }],\n [\"path\", { d: \"m10.8 9.3-.4-1\", key: \"1uaiz5\" }],\n [\"path\", { d: \"m8.3 13.6 1-.4\", key: \"s6srou\" }],\n [\"path\", { d: \"m14.7 10.8 1-.4\", key: \"4d31cq\" }],\n [\"path\", { d: \"m13.4 8.3-.3.9\", key: \"1bm987\" }]\n]);\n\nexport { ServerCog as default };\n//# sourceMappingURL=server-cog.js.map\n","/**\n * /settings/mcp — external MCP servers admin (Stage 6).\n *\n * Front-end for the `/api/mcp/*` REST surface. List configured servers,\n * see their connection status + tool count, add stdio / HTTP / SSE\n * servers, probe per-server health, remove.\n *\n * The native agent loop consumes any tools advertised here; CLI agents\n * have their own MCP configs and ignore this list. See\n * docs/llm-backends.md § External MCP servers.\n */\n\nimport { useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Loader2, Plus, RefreshCcw, ServerCog, Trash2, Activity } 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, SelectContent, SelectItem, SelectTrigger, SelectValue,\n} from '@/components/ui/select'\nimport {\n Table, TableBody, TableCell, TableHead, TableHeader, TableRow,\n} from '@/components/ui/table'\nimport {\n useMcpList, useMcpAddServer, useMcpRemoveServer, useMcpHealth,\n type McpServerRow,\n} from '@/hooks/use-llm-admin'\n\nexport default function SettingsMcpRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const listQuery = useMcpList()\n return (\n <div className=\"mx-auto flex max-w-5xl flex-col gap-6\">\n <header className=\"flex items-center gap-3\">\n <ServerCog className=\"h-5 w-5 text-text-dim\" />\n <h1 className=\"text-xl font-semibold\">{t('mcp.title')}</h1>\n <Button\n variant=\"ghost\" size=\"sm\" className=\"ml-auto\"\n onClick={() => void listQuery.refetch()}\n disabled={listQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {listQuery.isFetching\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('mcp.refresh')}</span>\n </Button>\n </header>\n <p className=\"text-sm text-text-dim\">{t('mcp.subtitle')}</p>\n\n {listQuery.isLoading ? (\n <div className=\"h-48 rounded-md bg-surface-2 animate-pulse\" />\n ) : (\n <>\n <ServersCard data={listQuery.data} />\n <AddServerCard />\n </>\n )}\n </div>\n )\n}\n\n/* ─────────────── Servers list ─────────────── */\n\nfunction ServersCard({ data }: { data: ReturnType<typeof useMcpList>['data'] }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const removeServer = useMcpRemoveServer()\n const health = useMcpHealth()\n const [healthResults, setHealthResults] = useState<Record<string, string>>({})\n\n async function onRemove(name: string): Promise<void> {\n if (!confirm(t('mcp.removeConfirm', { name }))) return\n try {\n await removeServer.mutateAsync(name)\n toast.success(t('mcp.removedToast', { name }))\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n async function onHealth(name: string): Promise<void> {\n setHealthResults((m) => ({ ...m, [name]: t('mcp.probing') }))\n try {\n const r = await health.mutateAsync(name)\n const msg = r.connected\n ? `✓ ${r.toolCount === 1\n ? t('mcp.runtimeConnectedOne', { count: r.toolCount })\n : t('mcp.runtimeConnected', { count: r.toolCount })}`\n : `✗ ${r.lastError ?? t('mcp.runtimeDisconnected')}`\n setHealthResults((m) => ({ ...m, [name]: msg }))\n } catch (err) {\n setHealthResults((m) => ({ ...m, [name]: `✗ ${((err as Error)?.message ?? String(err))}` }))\n }\n }\n\n const rows = data?.servers ?? []\n const runtime = data?.runtime?.servers ?? []\n if (rows.length === 0) {\n return (\n <section className=\"rounded-md border border-border bg-surface p-6 text-center text-sm text-text-dim\">\n {t('mcp.serversEmpty')}\n </section>\n )\n }\n\n return (\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 <h2 className=\"text-sm font-semibold\">{t('mcp.serversTitle', { count: rows.length })}</h2>\n {data?.runtime && (\n <Badge variant=\"info\">{t('mcp.totalTools', { count: data.runtime.totalTools })}</Badge>\n )}\n </header>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>{t('mcp.col.name')}</TableHead>\n <TableHead>{t('mcp.col.transport')}</TableHead>\n <TableHead>{t('mcp.col.target')}</TableHead>\n <TableHead>{t('mcp.col.runtime')}</TableHead>\n <TableHead>{t('mcp.col.actions')}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {rows.map((s) => {\n const rt = runtime.find((r) => r.name === s.name)\n const transport = transportLabel(s, t)\n const target = s.command\n ? `${s.command} ${(s.args ?? []).join(' ')}`.trim()\n : (s.url ?? '—')\n const runtimeBadge = !rt\n ? <Badge variant=\"outline\">{t('mcp.runtimeUnknown')}</Badge>\n : rt.connected\n ? <Badge variant=\"success\">\n {rt.toolCount === 1\n ? t('mcp.runtimeConnectedOne', { count: rt.toolCount })\n : t('mcp.runtimeConnected', { count: rt.toolCount })}\n </Badge>\n : <Badge variant=\"danger\">{t('mcp.runtimeDisconnected')}</Badge>\n return (\n <TableRow key={s.name}>\n <TableCell className=\"font-mono text-xs\">{s.name}</TableCell>\n <TableCell>{transport}</TableCell>\n <TableCell className=\"break-all font-mono text-[11px] text-text-dim\">{target}</TableCell>\n <TableCell>{runtimeBadge}</TableCell>\n <TableCell className=\"flex flex-col gap-1 sm:flex-row sm:items-center\">\n <Button\n variant=\"ghost\" size=\"sm\"\n onClick={() => void onHealth(s.name)}\n disabled={health.isPending}\n >\n <Activity className=\"h-4 w-4\" />\n <span>{t('mcp.health')}</span>\n </Button>\n <Button\n variant=\"ghost\" size=\"sm\"\n onClick={() => void onRemove(s.name)}\n disabled={removeServer.isPending}\n className=\"text-danger hover:text-danger\"\n >\n <Trash2 className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">{t('mcp.remove')}</span>\n </Button>\n {healthResults[s.name] && (\n <span className=\"ml-2 text-[11px] text-text-dim\">{healthResults[s.name]}</span>\n )}\n </TableCell>\n </TableRow>\n )\n })}\n </TableBody>\n </Table>\n </section>\n )\n}\n\nfunction transportLabel(\n s: McpServerRow,\n t: (key: string) => string,\n): string {\n if (s.command) return t('mcp.transportStdio')\n if (s.url) return s.url.endsWith('/sse') ? t('mcp.transportSse') : t('mcp.transportHttp')\n return '—'\n}\n\n/* ─────────────── Add server form ─────────────── */\n\nfunction AddServerCard(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const addServer = useMcpAddServer()\n const [name, setName] = useState('')\n const [transport, setTransport] = useState<'stdio' | 'http'>('stdio')\n const [command, setCommand] = useState('')\n const [args, setArgs] = useState('')\n const [url, setUrl] = useState('')\n const [headersJson, setHeadersJson] = useState('')\n\n async function onSubmit(e: React.FormEvent): Promise<void> {\n e.preventDefault()\n if (!name.trim()) { toast.error(t('mcp.nameRequired')); return }\n let headers: Record<string, string> | undefined\n if (headersJson.trim()) {\n try { headers = JSON.parse(headersJson) }\n catch { toast.error(t('mcp.headersInvalid')); return }\n }\n const body: Parameters<typeof addServer.mutateAsync>[0] = { name: name.trim() }\n if (transport === 'stdio') {\n if (!command.trim()) { toast.error(t('mcp.commandRequired')); return }\n body.command = command.trim()\n const splitArgs = args.split(/\\s+/).filter(Boolean)\n if (splitArgs.length > 0) body.args = splitArgs\n } else {\n if (!url.trim()) { toast.error(t('mcp.urlRequired')); return }\n body.url = url.trim()\n if (headers) body.headers = headers\n }\n try {\n await addServer.mutateAsync(body)\n toast.success(t('mcp.addedToast', { name: name.trim() }))\n setName(''); setCommand(''); setArgs(''); setUrl(''); setHeadersJson('')\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n return (\n <section className=\"rounded-md border border-border bg-surface\">\n <header className=\"border-b border-border px-4 py-3\">\n <h2 className=\"text-sm font-semibold\">{t('mcp.addTitle')}</h2>\n </header>\n <form onSubmit={(e) => void onSubmit(e)} className=\"grid grid-cols-1 gap-3 p-4 sm:grid-cols-2\">\n <div>\n <Label className=\"text-xs font-medium\">{t('mcp.nameLabel')}</Label>\n <Input\n value={name} onChange={(e) => setName(e.target.value)}\n placeholder={t('mcp.namePlaceholder')}\n className=\"font-mono text-xs\"\n />\n </div>\n <div>\n <Label className=\"text-xs font-medium\">{t('mcp.transportLabel')}</Label>\n <Select value={transport} onValueChange={(v) => setTransport(v as 'stdio' | 'http')}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"stdio\">{t('mcp.transportStdioOption')}</SelectItem>\n <SelectItem value=\"http\">{t('mcp.transportHttpOption')}</SelectItem>\n </SelectContent>\n </Select>\n </div>\n {transport === 'stdio' ? (\n <>\n <div>\n <Label className=\"text-xs font-medium\">{t('mcp.commandLabel')}</Label>\n <Input\n value={command} onChange={(e) => setCommand(e.target.value)}\n placeholder={t('mcp.commandPlaceholder')}\n className=\"font-mono text-xs\"\n />\n </div>\n <div>\n <Label className=\"text-xs font-medium\">{t('mcp.argsLabel')}</Label>\n <Input\n value={args} onChange={(e) => setArgs(e.target.value)}\n placeholder=\"-y @modelcontextprotocol/server-filesystem /data\"\n className=\"font-mono text-xs\"\n />\n </div>\n </>\n ) : (\n <>\n <div className=\"sm:col-span-2\">\n <Label className=\"text-xs font-medium\">{t('mcp.urlLabel')}</Label>\n <Input\n value={url} onChange={(e) => setUrl(e.target.value)}\n placeholder={t('mcp.urlPlaceholder')}\n className=\"font-mono text-xs\"\n />\n </div>\n <div className=\"sm:col-span-2\">\n <Label className=\"text-xs font-medium\">{t('mcp.headersLabel')}</Label>\n <Input\n value={headersJson} onChange={(e) => setHeadersJson(e.target.value)}\n placeholder={t('mcp.headersPlaceholder')}\n className=\"font-mono text-xs\"\n />\n </div>\n </>\n )}\n <div className=\"sm:col-span-2 flex\">\n <Button type=\"submit\" disabled={addServer.isPending} className=\"ml-auto\">\n {addServer.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Plus className=\"h-4 w-4\" />}\n {t('mcp.addServer')}\n </Button>\n </div>\n </form>\n </section>\n )\n}\n"],"names":["ServerCog","createLucideIcon","SettingsMcpRoute","useTranslation","listQuery","useMcpList","jsxs","jsx","Button","Loader2","RefreshCcw","Fragment","ServersCard","AddServerCard","data","t","removeServer","useMcpRemoveServer","health","useMcpHealth","healthResults","setHealthResults","useState","onRemove","name","toast","err","onHealth","m","r","msg","rows","runtime","Badge","Table","TableHeader","TableRow","TableHead","TableBody","s","rt","transport","transportLabel","target","runtimeBadge","TableCell","Activity","Trash2","addServer","useMcpAddServer","setName","setTransport","command","setCommand","args","setArgs","url","setUrl","headersJson","setHeadersJson","onSubmit","e","headers","body","splitArgs","Label","Input","Select","v","SelectTrigger","SelectValue","SelectContent","SelectItem","Plus"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import{h as A,r as I,s as v,t as O,v as F,u as k,i as B,j as e,d as K,e as b,T as Q,I as w,w as y,p as C,q as z}from"./index-DCfdN5R7.js";import{r as o}from"./react-DlP5eolq.js";import{D as H}from"./data-table-BkUshOZz.js";import{E as U}from"./empty-state-CuiqdZiB.js";import{C as $}from"./confirm-dialog-BDb0NLny.js";import{D as V,a as Y,b as G,c as J}from"./dropdown-menu-BNH5SrVb.js";import{T as W}from"./trash-2-D2x2UPuZ.js";import{R as X}from"./refresh-ccw-DlAd-eTQ.js";import{S as Z}from"./search-CAICU3aU.js";import{M as ee}from"./map-pin-C_jAxukI.js";import"./table-sCMZBe_Z.js";import"./arrow-up-Dm0U4-6U.js";import"./arrow-down-7i0xwCI2.js";import"./chevron-right-CFRb-SM_.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 te=A("NotebookText",[["path",{d:"M2 6h4",key:"aawbzj"}],["path",{d:"M2 10h4",key:"l0bgd4"}],["path",{d:"M2 14h4",key:"1gsvsf"}],["path",{d:"M2 18h4",key:"1bu2t1"}],["rect",{width:"16",height:"20",x:"4",y:"2",rx:"2",key:"1nb95v"}],["path",{d:"M9.5 8h5",key:"11mslq"}],["path",{d:"M9.5 12H16",key:"ktog6x"}],["path",{d:"M9.5 16H14",key:"p1seyn"}]]),D={all:["memos"],list:s=>["memos","list",s]};function se(s){return I({queryKey:D.list(s),queryFn:()=>v.listMemos(s)})}function ae(){const s=O();return F({mutationFn:a=>v.deleteMemo(a),onSuccess:()=>s.invalidateQueries({queryKey:D.all})})}const le=300;function be(){const{t:s}=k(["memos","common"]),[a,m]=B(),n=a.get("q")??"",l=a.get("who")??"",r=a.get("what")??"",h=a.get("has_location")==="1",x=a.get("include_expired")==="1",[d,_]=o.useState(n);o.useEffect(()=>{if(d===n)return;const t=window.setTimeout(()=>{c({q:d||null})},le);return()=>window.clearTimeout(t)},[d]);const T=o.useMemo(()=>({...n?{query:n}:{},...l?{who:l}:{},...r?{what:r}:{},...h?{has_location:!0}:{},...x?{include_expired:!0}:{},limit:200}),[n,l,r,h,x]),{data:E,isLoading:S,isFetching:g,refetch:q}=se(T),L=E?.memos??[],p=ae(),[u,j]=o.useState(null);function c(t){const i=new URLSearchParams(a);for(const[N,f]of Object.entries(t))f==null||f===""?i.delete(N):i.set(N,f);m(i,{replace:!0})}async function P(){if(u!=null)try{await p.mutateAsync(u),C.success(s("toast.deleted"))}catch(t){const{message:i}=z(t,s);throw C.error(i),t}}const R=o.useMemo(()=>[{id:"id",header:s("col.id"),cell:t=>e.jsxs("span",{className:"tabular-nums text-text-dim",children:["#",t.id]}),headClassName:"w-16"},{id:"what",header:s("col.what"),cell:t=>e.jsx("span",{className:"line-clamp-2",children:t.memo?e.jsx("span",{className:"text-text",children:t.memo}):e.jsx("span",{className:"font-medium text-text",children:t.what})}),asCardTitle:!0},{id:"who",header:s("col.who"),cell:t=>t.who?e.jsx(K,{variant:"secondary",children:t.who}):e.jsx("span",{className:"text-text-muted",children:"—"}),headClassName:"w-32"},{id:"when",header:s("col.when"),cell:t=>e.jsx("span",{className:"text-text-dim",children:t.whenText||(t.whenAt?M(t.whenAt):"—")}),headClassName:"w-36"},{id:"where",header:s("col.where"),cell:t=>t.where_label||t.where_lat!=null&&t.where_lng!=null?e.jsx(ie,{memo:t}):e.jsx("span",{className:"text-text-muted",children:"—"}),headClassName:"w-44"},{id:"platform",header:s("col.platform"),cell:t=>e.jsx("span",{className:"text-text-dim",children:t.platform}),headClassName:"w-24",hideOnMobile:!0},{id:"createdAt",header:s("col.createdAt"),cell:t=>e.jsx("span",{className:"text-text-dim",children:M(t.createdAt)}),headClassName:"w-36",hideOnMobile:!0},{id:"actions",header:"",cell:t=>e.jsx("div",{className:"flex justify-end",children:e.jsxs(b,{variant:"ghost",size:"sm",onClick:i=>{i.stopPropagation(),j(t.id)},disabled:p.isPending,"aria-label":s("action.delete"),children:[e.jsx(W,{className:"h-3 w-3"}),e.jsx("span",{className:"sr-only sm:not-sr-only sm:ml-1",children:s("action.delete")})]})}),headClassName:"w-24"}],[s,p.isPending]);return e.jsxs("div",{className:"flex min-h-dvh flex-col bg-bg",children:[e.jsx(Q,{}),e.jsxs("main",{className:"mx-auto flex w-full max-w-7xl flex-1 flex-col gap-4 px-3 py-4 sm:px-4 pb-safe",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("pageTitle")}),e.jsxs(b,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>q(),disabled:g,"aria-label":s("actions.refresh",{ns:"common"}),children:[e.jsx(X,{className:`h-4 w-4 ${g?"animate-spin":""}`}),e.jsx("span",{className:"hidden sm:inline",children:s("actions.refresh",{ns:"common"})})]})]}),e.jsx("p",{className:"text-sm text-text-dim",children:s("subtitle")})]}),e.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row sm:items-end",children:[e.jsxs("div",{className:"relative flex-1 max-w-md",children:[e.jsx(Z,{className:"pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-text-muted"}),e.jsx(w,{value:d,onChange:t=>_(t.target.value),placeholder:s("search.placeholder"),className:"pl-7"})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 sm:flex sm:items-end",children:[e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(y,{htmlFor:"who-filter",className:"text-xs text-text-dim",children:s("search.who")}),e.jsx(w,{id:"who-filter",value:l,onChange:t=>c({who:t.target.value||null}),className:"w-36"})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(y,{htmlFor:"what-filter",className:"text-xs text-text-dim",children:s("search.what")}),e.jsx(w,{id:"what-filter",value:r,onChange:t=>c({what:t.target.value||null}),className:"w-36"})]})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("label",{className:"inline-flex items-center gap-1 text-sm text-text-dim",children:[e.jsx("input",{type:"checkbox",checked:h,onChange:t=>c({has_location:t.target.checked?"1":null}),className:"h-4 w-4 accent-accent"}),s("search.hasLocation")]}),e.jsxs("label",{className:"inline-flex items-center gap-1 text-sm text-text-dim",children:[e.jsx("input",{type:"checkbox",checked:x,onChange:t=>c({include_expired:t.target.checked?"1":null}),className:"h-4 w-4 accent-accent"}),s("search.includeExpired")]})]})]}),e.jsx(H,{columns:R,rows:L,getRowId:t=>String(t.id),loading:S,emptyState:e.jsx(U,{icon:e.jsx(te,{}),title:s("empty.title"),description:s("empty.description")})}),e.jsx($,{open:u!=null,onOpenChange:t=>{t||j(null)},title:s("action.confirmDelete"),description:s("action.confirmDeleteDesc"),intent:"danger",confirmLabel:s("action.delete"),onConfirm:P})]})]})}const ne={baidu:"openMap.baidu",apple:"openMap.apple",google:"openMap.google",osm:"openMap.osm"};function ie({memo:s}){const{t:a}=k("memos"),m=s.where_label||`${s.where_lat}, ${s.where_lng}`,n=Object.entries(s.mapUrls??{});return n.length===0?e.jsx("span",{className:"text-text-dim",children:m}):e.jsxs(V,{children:[e.jsx(Y,{asChild:!0,children:e.jsxs("button",{type:"button",className:"inline-flex items-center gap-1 text-sm text-text-dim hover:text-accent",onClick:l=>l.stopPropagation(),children:[e.jsx(ee,{className:"h-3 w-3"}),e.jsx("span",{className:"line-clamp-1 underline-offset-2 hover:underline",children:m})]})}),e.jsx(G,{children:n.map(([l,r])=>e.jsx(J,{asChild:!0,children:e.jsx("a",{href:r,target:"_blank",rel:"noopener noreferrer",children:a(ne[l]??"openMap.label",{defaultValue:l})})},l))})]})}function M(s){try{const a=new Date(s);return Number.isNaN(a.getTime())?s:a.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return s}}export{be as default};
|
|
7
|
+
//# sourceMappingURL=memos-DAt4k3DO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memos-DAt4k3DO.js","sources":["../../node_modules/lucide-react/dist/esm/icons/notebook-text.js","../../src/hooks/use-memos.ts","../../src/routes/memos.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 NotebookText = createLucideIcon(\"NotebookText\", [\n [\"path\", { d: \"M2 6h4\", key: \"aawbzj\" }],\n [\"path\", { d: \"M2 10h4\", key: \"l0bgd4\" }],\n [\"path\", { d: \"M2 14h4\", key: \"1gsvsf\" }],\n [\"path\", { d: \"M2 18h4\", key: \"1bu2t1\" }],\n [\"rect\", { width: \"16\", height: \"20\", x: \"4\", y: \"2\", rx: \"2\", key: \"1nb95v\" }],\n [\"path\", { d: \"M9.5 8h5\", key: \"11mslq\" }],\n [\"path\", { d: \"M9.5 12H16\", key: \"ktog6x\" }],\n [\"path\", { d: \"M9.5 16H14\", key: \"p1seyn\" }]\n]);\n\nexport { NotebookText as default };\n//# sourceMappingURL=notebook-text.js.map\n","/**\n * useMemos — react-query wrappers for memos search + delete.\n *\n * useMemos(query) — search/list\n * useDeleteMemo() — DELETE /api/memos/:id\n *\n * No SSE channel for memos (they're operator-created from chat, not\n * from autonomous agent activity), and no background poll: the page\n * shows search results which are inherently user-triggered.\n * Mutation onSuccess invalidates so a delete removes the row\n * immediately without a manual refresh.\n */\n\nimport { useQueryClient, useQuery, useMutation } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type {\n DeleteMemoResponse,\n ListMemosQuery,\n ListMemosResponse,\n} from '@/types/api'\n\nexport const memosKeys = {\n all: ['memos'] as const,\n list: (q: ListMemosQuery) => ['memos', 'list', q] as const,\n}\n\nexport function useMemos(query: ListMemosQuery) {\n return useQuery<ListMemosResponse>({\n queryKey: memosKeys.list(query),\n queryFn: () => api.listMemos(query),\n })\n}\n\nexport function useInvalidateMemos() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: memosKeys.all })\n}\n\nexport function useDeleteMemo() {\n const qc = useQueryClient()\n return useMutation<DeleteMemoResponse, Error, number>({\n mutationFn: (id) => api.deleteMemo(id),\n onSuccess: () => qc.invalidateQueries({ queryKey: memosKeys.all }),\n })\n}\n","/**\n * /memos — searchable memo list. Free-form text + who/what filters +\n * has-location toggle. Delete is the one mutation.\n *\n * Memos with location surface a small \"Open map\" dropdown that\n * routes to the provider URLs the backend prepared in `mapUrls`\n * (Baidu / Apple / Google / OSM).\n *\n * Searches are user-triggered (input + debounce) rather than poll-\n * driven — the query is read straight from URL params so deep-link\n * sharing works (\"memos about taxes between Jan and April\").\n *\n * Debounce: 300ms between the last keystroke and URL/query commit\n * — keeps the backend's FTS5 from running on every keypress.\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { MapPin, NotebookText, RefreshCcw, Search, Trash2 } from 'lucide-react'\n\nimport { Topbar } from '@/components/shell/topbar'\nimport { DataTable, type DataTableColumn } from '@/components/common/data-table'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\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 DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu'\nimport { useMemos, useDeleteMemo } from '@/hooks/use-memos'\nimport { describeError } from '@/lib/api/errors'\nimport type { Memo, ListMemosQuery } from '@/types/api'\n\nconst SEARCH_DEBOUNCE_MS = 300\n\nexport default function MemosRoute(): JSX.Element {\n const { t } = useTranslation(['memos', 'common'])\n const [params, setParams] = useSearchParams()\n\n // URL-driven filter state (read once per render).\n const q = params.get('q') ?? ''\n const who = params.get('who') ?? ''\n const what = params.get('what') ?? ''\n const hasLoc = params.get('has_location') === '1'\n const incExpired = params.get('include_expired') === '1'\n\n // Local-only echo of the text input. Effects below sync the URL\n // after the debounce so each keypress doesn't kick a fetch.\n const [qDraft, setQDraft] = useState(q)\n\n useEffect(() => {\n if (qDraft === q) return\n const timer = window.setTimeout(() => {\n patchParams({ q: qDraft || null })\n }, SEARCH_DEBOUNCE_MS)\n return () => window.clearTimeout(timer)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [qDraft])\n\n const query: ListMemosQuery = useMemo(\n () => ({\n ...(q ? { query: q } : {}),\n ...(who ? { who } : {}),\n ...(what ? { what } : {}),\n ...(hasLoc ? { has_location: true } : {}),\n ...(incExpired ? { include_expired: true } : {}),\n limit: 200,\n }),\n [q, who, what, hasLoc, incExpired],\n )\n\n const { data, isLoading, isFetching, refetch } = useMemos(query)\n const memos = data?.memos ?? []\n\n const del = useDeleteMemo()\n const [confirmDeleteId, setConfirmDeleteId] = useState<number | null>(null)\n\n function patchParams(patch: Record<string, string | null>): void {\n const next = new URLSearchParams(params)\n for (const [k, v] of Object.entries(patch)) {\n if (v == null || v === '') next.delete(k)\n else next.set(k, v)\n }\n setParams(next, { replace: true })\n }\n\n async function onConfirmDelete(): Promise<void> {\n if (confirmDeleteId == null) return\n try {\n await del.mutateAsync(confirmDeleteId)\n toast.success(t('toast.deleted'))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err\n }\n }\n\n const columns: DataTableColumn<Memo>[] = useMemo(\n () => [\n {\n id: 'id',\n header: t('col.id'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">#{r.id}</span>,\n headClassName: 'w-16',\n },\n {\n id: 'what',\n header: t('col.what'),\n cell: (r) => (\n <span className=\"line-clamp-2\">\n {r.memo ? <span className=\"text-text\">{r.memo}</span> : <span className=\"font-medium text-text\">{r.what}</span>}\n </span>\n ),\n asCardTitle: true,\n },\n {\n id: 'who',\n header: t('col.who'),\n cell: (r) =>\n r.who ? (\n <Badge variant=\"secondary\">{r.who}</Badge>\n ) : (\n <span className=\"text-text-muted\">—</span>\n ),\n headClassName: 'w-32',\n },\n {\n id: 'when',\n header: t('col.when'),\n cell: (r) => (\n <span className=\"text-text-dim\">\n {r.whenText || (r.whenAt ? formatTime(r.whenAt) : '—')}\n </span>\n ),\n headClassName: 'w-36',\n },\n {\n id: 'where',\n header: t('col.where'),\n cell: (r) =>\n r.where_label || (r.where_lat != null && r.where_lng != null) ? (\n <MapCell memo={r} />\n ) : (\n <span className=\"text-text-muted\">—</span>\n ),\n headClassName: 'w-44',\n },\n {\n id: 'platform',\n header: t('col.platform'),\n cell: (r) => <span className=\"text-text-dim\">{r.platform}</span>,\n headClassName: 'w-24',\n hideOnMobile: true,\n },\n {\n id: 'createdAt',\n header: t('col.createdAt'),\n cell: (r) => <span className=\"text-text-dim\">{formatTime(r.createdAt)}</span>,\n headClassName: 'w-36',\n hideOnMobile: true,\n },\n {\n id: 'actions',\n header: '',\n cell: (r) => (\n <div className=\"flex justify-end\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={(e) => {\n e.stopPropagation()\n setConfirmDeleteId(r.id)\n }}\n disabled={del.isPending}\n aria-label={t('action.delete')}\n >\n <Trash2 className=\"h-3 w-3\" />\n <span className=\"sr-only sm:not-sr-only sm:ml-1\">{t('action.delete')}</span>\n </Button>\n </div>\n ),\n headClassName: 'w-24',\n },\n ],\n [t, del.isPending],\n )\n\n return (\n <div className=\"flex min-h-dvh flex-col bg-bg\">\n <Topbar />\n\n <main className=\"mx-auto flex w-full max-w-7xl flex-1 flex-col gap-4 px-3 py-4 sm:px-4 pb-safe\">\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('pageTitle')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => refetch()}\n disabled={isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n <RefreshCcw className={`h-4 w-4 ${isFetching ? 'animate-spin' : ''}`} />\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('subtitle')}</p>\n </header>\n\n {/* Search bar */}\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-end\">\n <div className=\"relative flex-1 max-w-md\">\n <Search className=\"pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-text-muted\" />\n <Input\n value={qDraft}\n onChange={(e) => setQDraft(e.target.value)}\n placeholder={t('search.placeholder')}\n className=\"pl-7\"\n />\n </div>\n <div className=\"grid grid-cols-2 gap-2 sm:flex sm:items-end\">\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"who-filter\" className=\"text-xs text-text-dim\">\n {t('search.who')}\n </Label>\n <Input\n id=\"who-filter\"\n value={who}\n onChange={(e) => patchParams({ who: e.target.value || null })}\n className=\"w-36\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"what-filter\" className=\"text-xs text-text-dim\">\n {t('search.what')}\n </Label>\n <Input\n id=\"what-filter\"\n value={what}\n onChange={(e) => patchParams({ what: e.target.value || null })}\n className=\"w-36\"\n />\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n <label className=\"inline-flex items-center gap-1 text-sm text-text-dim\">\n <input\n type=\"checkbox\"\n checked={hasLoc}\n onChange={(e) => patchParams({ has_location: e.target.checked ? '1' : null })}\n className=\"h-4 w-4 accent-accent\"\n />\n {t('search.hasLocation')}\n </label>\n <label className=\"inline-flex items-center gap-1 text-sm text-text-dim\">\n <input\n type=\"checkbox\"\n checked={incExpired}\n onChange={(e) => patchParams({ include_expired: e.target.checked ? '1' : null })}\n className=\"h-4 w-4 accent-accent\"\n />\n {t('search.includeExpired')}\n </label>\n </div>\n </div>\n\n <DataTable\n columns={columns}\n rows={memos}\n getRowId={(r) => String(r.id)}\n loading={isLoading}\n emptyState={\n <EmptyState\n icon={<NotebookText />}\n title={t('empty.title')}\n description={t('empty.description')}\n />\n }\n />\n\n <ConfirmDialog\n open={confirmDeleteId != null}\n onOpenChange={(open) => {\n if (!open) setConfirmDeleteId(null)\n }}\n title={t('action.confirmDelete')}\n description={t('action.confirmDeleteDesc')}\n intent=\"danger\"\n confirmLabel={t('action.delete')}\n onConfirm={onConfirmDelete}\n />\n </main>\n </div>\n )\n}\n\ninterface MapCellProps {\n memo: Memo\n}\n\nconst PROVIDER_LABEL_KEY: Record<string, string> = {\n baidu: 'openMap.baidu',\n apple: 'openMap.apple',\n google: 'openMap.google',\n osm: 'openMap.osm',\n}\n\nfunction MapCell({ memo }: MapCellProps): JSX.Element {\n const { t } = useTranslation('memos')\n const label = memo.where_label || `${memo.where_lat}, ${memo.where_lng}`\n const entries = Object.entries(memo.mapUrls ?? {})\n if (entries.length === 0) {\n return <span className=\"text-text-dim\">{label}</span>\n }\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 text-sm text-text-dim hover:text-accent\"\n onClick={(e) => e.stopPropagation()}\n >\n <MapPin className=\"h-3 w-3\" />\n <span className=\"line-clamp-1 underline-offset-2 hover:underline\">{label}</span>\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent>\n {entries.map(([provider, url]) => (\n <DropdownMenuItem key={provider} asChild>\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {t(PROVIDER_LABEL_KEY[provider] ?? 'openMap.label', { defaultValue: provider })}\n </a>\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n\nfunction formatTime(iso: string): string {\n try {\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return iso\n return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch {\n return iso\n }\n}\n"],"names":["NotebookText","createLucideIcon","memosKeys","q","useMemos","query","useQuery","api","useDeleteMemo","qc","useQueryClient","useMutation","id","SEARCH_DEBOUNCE_MS","MemosRoute","t","useTranslation","params","setParams","useSearchParams","who","what","hasLoc","incExpired","qDraft","setQDraft","useState","useEffect","timer","patchParams","useMemo","data","isLoading","isFetching","refetch","memos","del","confirmDeleteId","setConfirmDeleteId","patch","next","k","v","onConfirmDelete","toast","err","message","describeError","columns","r","jsxs","jsx","Badge","formatTime","MapCell","Button","e","Trash2","Topbar","RefreshCcw","Search","Input","Label","DataTable","EmptyState","ConfirmDialog","open","PROVIDER_LABEL_KEY","memo","label","entries","DropdownMenu","DropdownMenuTrigger","MapPin","DropdownMenuContent","provider","url","DropdownMenuItem","iso","d"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{u as C,j as e,e as k,d as I,X as Q,p as w,q as D,C as _,P as T,f as z,L as U,M as X,R as E,w as L,I as R,D as K,E as Y,F as Z,G as ee,H as se}from"./index-DCfdN5R7.js";import{r as f}from"./react-DlP5eolq.js";import{u as ae,d as le,a as te,e as ne,f as ie,g as re,h as ce}from"./use-settings-DGIjmUX0.js";import{L as A}from"./loader-circle-DDdmcH0k.js";import{R as de}from"./refresh-ccw-DlAd-eTQ.js";import{S as oe}from"./save-BDOtZrfp.js";import{Q as O}from"./qr-code-YrEuhMPC.js";import{A as me}from"./arrow-right-A889Wof8.js";import{P as $}from"./play-DX5wp4WH.js";function P(s){const r=new Set(s?.messengers??[]);return{"wechat-ilink":{enabled:r.has("wechat-ilink")},telegram:{enabled:r.has("telegram"),telegram:{...s?.telegram??{}}},feishu:{enabled:r.has("feishu"),feishu:{...s?.feishu??{}}},dingtalk:{enabled:r.has("dingtalk"),dingtalk:{...s?.dingtalk??{}}},discord:{enabled:r.has("discord"),discord:{...s?.discord??{}}}}}function ge(s,r){const i=[];for(const a of Object.keys(s))s[a].enabled&&i.push(a);const o={messengers:i,...Object.fromEntries(Object.entries(r).filter(([a])=>!["messengers","telegram","feishu","dingtalk","discord"].includes(a)))};return s.telegram.enabled&&s.telegram.telegram&&(o.telegram=s.telegram.telegram),s.feishu.enabled&&s.feishu.feishu&&(o.feishu=s.feishu.feishu),s.dingtalk.enabled&&s.dingtalk.dingtalk&&(o.dingtalk=s.dingtalk.dingtalk),s.discord.enabled&&s.discord.discord&&(o.discord=s.discord.discord),o}function qe(){const{t:s}=C(["settings","common"]),r=ae(),i=le(),o=te(),a=ne(),m=ie(),[l,h]=f.useState(()=>P(r.data)),[n,c]=f.useState(!1);f.useEffect(()=>{n||r.data&&(h(P(r.data)),c(!0))},[r.data,n]);const d=r.data,b=f.useMemo(()=>d?JSON.stringify(P(d))!==JSON.stringify(l):!1,[d,l]),[p,j]=f.useState(!1),[x,B]=f.useState(null),[M,F]=f.useState(!1),H=new Set(d?.features?.blacklistedPlatforms??[]),N=t=>H.has(t);function g(t,v){h(q=>({...q,[t]:{...q[t],...v}}))}function W(t){g(t,{enabled:!0}),B(t),requestAnimationFrame(()=>{document.getElementById(`messenger-${t}`)?.scrollIntoView({behavior:"smooth",block:"start"})})}async function G(){if(d)try{await i.mutateAsync(ge(l,d)),w.success(s("messengers.savedToast")),F(!0),c(!1)}catch(t){w.error(D(t,s).message)}}function J(){d&&h(P(d))}async function V(){const t=o.data,v=!!(t&&t.mode!=="none");try{v?await m.mutateAsync():await a.mutateAsync(),w.success(s("messengers.apply.appliedToast")),F(!1)}catch(q){w.error(D(q,s).message)}}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("messengers.title")}),e.jsxs(k,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>r.refetch(),disabled:r.isFetching,"aria-label":s("actions.refresh",{ns:"common"}),children:[r.isFetching?e.jsx(A,{className:"h-4 w-4 animate-spin"}):e.jsx(de,{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("messengers.subtitle")})]}),r.isLoading?null:d?e.jsx(he,{cfg:d,isBlocked:N,onScanWechat:()=>j(!0),onPickPlatform:W}):null,e.jsx("div",{className:"flex flex-wrap items-center gap-2",children:b?e.jsxs(e.Fragment,{children:[e.jsx(I,{variant:"info",children:s("messengers.dirtyHint")}),e.jsxs(k,{type:"button",variant:"secondary",size:"sm",onClick:J,disabled:i.isPending,children:[e.jsx(Q,{className:"h-4 w-4"}),s("messengers.discardAll")]}),e.jsxs(k,{type:"button",size:"sm",onClick:()=>void G(),disabled:i.isPending,children:[i.isPending?e.jsx(A,{className:"h-4 w-4 animate-spin"}):e.jsx(oe,{className:"h-4 w-4"}),i.isPending?s("messengers.saving"):s("messengers.saveAll")]})]}):e.jsx("span",{className:"text-xs text-text-muted",children:s("env.noChanges")})}),M?e.jsx(ue,{serviceMode:o.data?.mode,isLoading:o.isLoading,isPending:a.isPending||m.isPending,onApply:()=>void V()}):null,r.isLoading?e.jsx("div",{className:"h-96 rounded-md bg-surface-2 animate-pulse"}):d?e.jsxs("div",{className:"flex flex-col gap-3",children:[N("wechat-ilink")?null:e.jsx(S,{slot:"wechat-ilink",label:s("messengers.platform.wechat"),hint:s("messengers.hint.wechat"),enabled:l["wechat-ilink"].enabled,onToggle:t=>g("wechat-ilink",{enabled:t}),focused:x==="wechat-ilink",children:e.jsxs(k,{type:"button",variant:"secondary",size:"sm",onClick:()=>j(!0),children:[e.jsx(O,{className:"h-4 w-4"}),s("messengers.scanQr")]})}),d.features?.globalIm&&!N("telegram")?e.jsxs(S,{slot:"telegram",label:s("messengers.platform.telegram"),hint:s("messengers.hint.telegram"),enabled:l.telegram.enabled,onToggle:t=>g("telegram",{enabled:t}),focused:x==="telegram",children:[e.jsx(u,{id:"tg-token",label:s("messengers.fields.botToken"),value:l.telegram.telegram?.botToken??"",type:"password",onChange:t=>g("telegram",{telegram:{...l.telegram.telegram,botToken:t}})}),e.jsx(u,{id:"tg-channel",label:s("messengers.fields.channelId"),value:l.telegram.telegram?.channelId??"",onChange:t=>g("telegram",{telegram:{...l.telegram.telegram,channelId:t}})})]}):null,N("feishu")?null:e.jsxs(S,{slot:"feishu",label:s("messengers.platform.feishu"),hint:s("messengers.hint.feishu"),enabled:l.feishu.enabled,onToggle:t=>g("feishu",{enabled:t}),focused:x==="feishu",children:[e.jsx(u,{id:"fs-appid",label:s("messengers.fields.appId"),value:l.feishu.feishu?.appId??"",onChange:t=>g("feishu",{feishu:{...l.feishu.feishu,appId:t}})}),e.jsx(u,{id:"fs-secret",label:s("messengers.fields.appSecret"),value:l.feishu.feishu?.appSecret??"",type:"password",onChange:t=>g("feishu",{feishu:{...l.feishu.feishu,appSecret:t}})}),e.jsx(u,{id:"fs-channel",label:s("messengers.fields.channelId"),value:l.feishu.feishu?.channelId??"",onChange:t=>g("feishu",{feishu:{...l.feishu.feishu,channelId:t}})})]}),N("dingtalk")?null:e.jsxs(S,{slot:"dingtalk",label:s("messengers.platform.dingtalk"),hint:s("messengers.hint.dingtalk"),enabled:l.dingtalk.enabled,onToggle:t=>g("dingtalk",{enabled:t}),focused:x==="dingtalk",children:[e.jsx(u,{id:"dt-cid",label:s("messengers.fields.clientId"),value:l.dingtalk.dingtalk?.clientId??"",onChange:t=>g("dingtalk",{dingtalk:{...l.dingtalk.dingtalk,clientId:t}})}),e.jsx(u,{id:"dt-secret",label:s("messengers.fields.clientSecret"),value:l.dingtalk.dingtalk?.clientSecret??"",type:"password",onChange:t=>g("dingtalk",{dingtalk:{...l.dingtalk.dingtalk,clientSecret:t}})}),e.jsx(u,{id:"dt-channel",label:s("messengers.fields.channelId"),value:l.dingtalk.dingtalk?.channelId??"",onChange:t=>g("dingtalk",{dingtalk:{...l.dingtalk.dingtalk,channelId:t}})}),e.jsx(y,{id:"dt-dm-policy",label:s("messengers.dingtalk.dmPolicy"),value:l.dingtalk.dingtalk?.dmPolicy??"open",onChange:t=>g("dingtalk",{dingtalk:{...l.dingtalk.dingtalk,dmPolicy:t}}),options:[{value:"open",label:s("messengers.dingtalk.policy.open")},{value:"pairing",label:s("messengers.dingtalk.policy.pairing")},{value:"allowlist",label:s("messengers.dingtalk.policy.allowlist")}]}),e.jsx(y,{id:"dt-group-policy",label:s("messengers.dingtalk.groupPolicy"),value:l.dingtalk.dingtalk?.groupPolicy??"open",onChange:t=>g("dingtalk",{dingtalk:{...l.dingtalk.dingtalk,groupPolicy:t}}),options:[{value:"open",label:s("messengers.dingtalk.policy.open")},{value:"allowlist",label:s("messengers.dingtalk.policy.allowlist")},{value:"disabled",label:s("messengers.dingtalk.policy.disabled")}]}),e.jsx(u,{id:"dt-allow-from",label:s("messengers.dingtalk.allowFrom"),value:(l.dingtalk.dingtalk?.allowFrom??[]).join(","),onChange:t=>g("dingtalk",{dingtalk:{...l.dingtalk.dingtalk,allowFrom:t.split(",").map(v=>v.trim()).filter(Boolean)}})}),e.jsx(u,{id:"dt-group-allow-from",label:s("messengers.dingtalk.groupAllowFrom"),value:(l.dingtalk.dingtalk?.groupAllowFrom??[]).join(","),onChange:t=>g("dingtalk",{dingtalk:{...l.dingtalk.dingtalk,groupAllowFrom:t.split(",").map(v=>v.trim()).filter(Boolean)}})}),e.jsx(y,{id:"dt-ack",label:s("messengers.dingtalk.ackReaction"),value:l.dingtalk.dingtalk?.ackReaction??"off",onChange:t=>g("dingtalk",{dingtalk:{...l.dingtalk.dingtalk,ackReaction:t}}),options:[{value:"off",label:s("messengers.dingtalk.ack.off")},{value:"emoji",label:s("messengers.dingtalk.ack.emoji")},{value:"kaomoji",label:s("messengers.dingtalk.ack.kaomoji")}]}),e.jsx(pe,{accounts:l.dingtalk.dingtalk?.accounts??{},onChange:t=>g("dingtalk",{dingtalk:{...l.dingtalk.dingtalk,accounts:t}})})]}),d.features?.globalIm&&!N("discord")?e.jsxs(S,{slot:"discord",label:s("messengers.platform.discord"),hint:s("messengers.hint.discord"),enabled:l.discord.enabled,onToggle:t=>g("discord",{enabled:t}),focused:x==="discord",children:[e.jsx(u,{id:"dc-token",label:s("messengers.fields.botToken"),value:l.discord.discord?.botToken??"",type:"password",onChange:t=>g("discord",{discord:{...l.discord.discord,botToken:t}})}),e.jsx(u,{id:"dc-channel",label:s("messengers.fields.channelId"),value:l.discord.discord?.channelId??"",onChange:t=>g("discord",{discord:{...l.discord.discord,channelId:t}})})]}):null]}):null,e.jsx(fe,{open:p,onOpenChange:j,onConfirmed:()=>{r.refetch(),c(!1),F(!0)}})]})}function ue({serviceMode:s,isLoading:r,isPending:i,onApply:o}){const{t:a}=C("settings"),m=s!=null&&s!=="none";return e.jsx("section",{className:"rounded-md border border-warning/40 bg-warning-bg p-4",children:e.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-center",children:[e.jsx("span",{className:"flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-surface text-warning",children:m?e.jsx(E,{className:"h-4 w-4"}):e.jsx($,{className:"h-4 w-4"})}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("h2",{className:"text-sm font-semibold",children:a("messengers.apply.title")}),e.jsx(I,{variant:"warning",children:a("messengers.apply.badge")})]}),e.jsx("p",{className:"mt-1 text-sm text-text-dim",children:a(m?"messengers.apply.restartDetail":"messengers.apply.startDetail")})]}),e.jsxs(k,{type:"button",size:"sm",disabled:r||i,onClick:o,children:[i?e.jsx(A,{className:"h-4 w-4 animate-spin"}):m?e.jsx(E,{className:"h-4 w-4"}):e.jsx($,{className:"h-4 w-4"}),e.jsx("span",{children:a(i?m?"messengers.apply.restarting":"messengers.apply.starting":m?"messengers.apply.restart":"messengers.apply.start")})]})]})})}function he({cfg:s,isBlocked:r,onScanWechat:i,onPickPlatform:o}){const{t:a}=C("settings"),m=s.messengers??[],l=m.length>0,h=s.features?.globalIm===!0,n=[];return r("wechat-ilink")||n.push({slot:"wechat-ilink",label:a("messengers.platform.wechat"),title:a("messengers.quick.option.wechat.title"),detail:a("messengers.quick.option.wechat.detail"),kind:"qr"}),r("feishu")||n.push({slot:"feishu",label:a("messengers.platform.feishu"),title:a("messengers.quick.option.feishu.title"),detail:a("messengers.quick.option.feishu.detail"),kind:"config"}),r("dingtalk")||n.push({slot:"dingtalk",label:a("messengers.platform.dingtalk"),title:a("messengers.quick.option.dingtalk.title"),detail:a("messengers.quick.option.dingtalk.detail"),kind:"config"}),h&&!r("telegram")&&n.push({slot:"telegram",label:a("messengers.platform.telegram"),title:a("messengers.quick.option.telegram.title"),detail:a("messengers.quick.option.telegram.detail"),kind:"config"}),h&&!r("discord")&&n.push({slot:"discord",label:a("messengers.platform.discord"),title:a("messengers.quick.option.discord.title"),detail:a("messengers.quick.option.discord.detail"),kind:"config"}),e.jsx("section",{className:"rounded-md border border-border bg-surface p-4",children:e.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-start",children:[e.jsx("span",{className:z("flex h-10 w-10 shrink-0 items-center justify-center rounded-full",l?"bg-success-bg text-success":"bg-accent-bg text-accent"),children:l?e.jsx(_,{className:"h-5 w-5"}):e.jsx(T,{className:"h-5 w-5"})}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("h2",{className:"text-sm font-semibold",children:a(l?"messengers.quick.connectedTitle":"messengers.quick.title")}),e.jsx(I,{variant:l?"success":"info",children:a(l?"messengers.quick.connectedBadge":"messengers.quick.nextBadge")})]}),e.jsx("p",{className:"mt-1 text-sm text-text-dim",children:l?a("messengers.quick.connectedDetail",{platforms:m.map(c=>xe(c,a)).join(", ")}):a("messengers.quick.subtitle")}),l?e.jsxs("div",{className:"mt-3 flex flex-wrap gap-2",children:[e.jsx(k,{asChild:!0,size:"sm",children:e.jsxs(U,{to:"/?welcome=1",children:[e.jsx(X,{className:"h-4 w-4"}),e.jsx("span",{children:a("messengers.quick.webChat")})]})}),e.jsxs(k,{type:"button",variant:"secondary",size:"sm",onClick:()=>{const c=n.find(d=>!m.includes(d.slot))??n[0];c&&(c.kind==="qr"?i():o(c.slot))},children:[e.jsx(T,{className:"h-4 w-4"}),e.jsx("span",{children:a("messengers.quick.addAnother")})]})]}):e.jsx("div",{className:"mt-4 grid gap-2 sm:grid-cols-2",children:n.map(c=>e.jsxs("div",{className:"rounded-md border border-border bg-surface-2 p-3",children:[e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx("span",{className:"mt-0.5 text-text-dim",children:c.kind==="qr"?e.jsx(O,{className:"h-4 w-4"}):e.jsx(T,{className:"h-4 w-4"})}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("h3",{className:"text-sm font-medium",children:c.title}),e.jsx("p",{className:"mt-1 text-xs text-text-dim",children:c.detail})]})]}),e.jsxs(k,{type:"button",variant:c.kind==="qr"?"default":"secondary",size:"sm",className:"mt-3",onClick:()=>{c.kind==="qr"?i():o(c.slot)},children:[e.jsx("span",{children:c.kind==="qr"?a("messengers.quick.scanWechat"):a("messengers.quick.configurePlatform",{platform:c.label})}),e.jsx(me,{className:"h-4 w-4"})]})]},c.slot))})]})]})})}function S({slot:s,label:r,hint:i,enabled:o,onToggle:a,children:m,focused:l=!1}){const{t:h}=C("settings");return e.jsxs("div",{id:`messenger-${s}`,className:z("scroll-mt-20 rounded-md border border-border bg-surface p-4",l&&"border-accent ring-2 ring-accent/30"),children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsxs("div",{className:"flex-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"font-medium text-text",children:r}),e.jsx(I,{variant:o?"success":"outline",children:h(o?"messengers.enabled":"messengers.disabled")})]}),e.jsx("p",{className:"mt-1 text-xs text-text-dim",children:i})]}),e.jsx("label",{className:"inline-flex items-center gap-2 text-sm",children:e.jsx("input",{type:"checkbox",checked:o,onChange:n=>a(n.target.checked),className:"h-4 w-4 accent-accent cursor-pointer"})})]}),o&&m&&e.jsx("div",{className:"mt-3 flex flex-col gap-2",children:m})]})}function xe(s,r){return{"wechat-ilink":r("messengers.platform.wechat"),telegram:r("messengers.platform.telegram"),feishu:r("messengers.platform.feishu"),dingtalk:r("messengers.platform.dingtalk"),discord:r("messengers.platform.discord")}[s]??s}function u({id:s,label:r,value:i,onChange:o,type:a="text"}){return e.jsxs("div",{className:"grid grid-cols-1 gap-1 sm:grid-cols-[180px_1fr] sm:items-center sm:gap-2",children:[e.jsx(L,{htmlFor:s,className:"text-xs text-text-dim",children:r}),e.jsx(R,{id:s,type:a,value:i,onChange:m=>o(m.target.value),autoComplete:"off",className:"font-mono text-xs"})]})}function y({id:s,label:r,value:i,onChange:o,options:a}){return e.jsxs("div",{className:"grid grid-cols-1 gap-1 sm:grid-cols-[180px_1fr] sm:items-center sm:gap-2",children:[e.jsx(L,{htmlFor:s,className:"text-xs text-text-dim",children:r}),e.jsx("select",{id:s,value:i,onChange:m=>o(m.target.value),className:"rounded-md border border-border bg-surface px-2 py-1 text-xs text-text",children:a.map(m=>e.jsx("option",{value:m.value,children:m.label},m.value))})]})}function fe({open:s,onOpenChange:r,onConfirmed:i}){const{t:o}=C(["settings","common"]),a=re(),[m,l]=f.useState(null),[h,n]=f.useState(null),[c,d]=f.useState(null);f.useEffect(()=>{if(!s){l(null),n(null),d(null);return}let j=!0;return a.mutateAsync().then(x=>{j&&(n(x.qrImage),l(x.qrToken))}).catch(x=>{j&&d(x instanceof Error?x.message:String(x))}),()=>{j=!1}},[s]);const p=ce(s?m:null).data?.status;return f.useEffect(()=>{p==="confirmed"&&(w.success(o("messengers.qr.confirmed")),i(),r(!1)),p==="expired"&&w.error(o("messengers.qr.expired"))},[p]),e.jsx(K,{open:s,onOpenChange:r,children:e.jsxs(Y,{children:[e.jsxs(Z,{children:[e.jsx(ee,{children:o("messengers.qr.title")}),e.jsx(se,{children:o("messengers.qr.description")})]}),e.jsx("div",{className:"flex flex-col items-center gap-3",children:a.isPending&&!h?e.jsxs(e.Fragment,{children:[e.jsx(A,{className:"h-8 w-8 animate-spin text-text-dim"}),e.jsx("p",{className:"text-sm text-text-dim",children:o("messengers.qr.starting")})]}):c?e.jsxs("p",{className:"text-sm text-danger",children:[o("messengers.qr.loadFailed"),": ",c]}):h?e.jsxs(e.Fragment,{children:[e.jsx("img",{src:h,alt:o("messengers.qr.title"),className:"rounded-md border border-border"}),p==="expired"?e.jsx("p",{className:"text-xs text-danger",children:o("messengers.qr.expired")}):e.jsx("p",{className:"text-xs text-text-dim",children:p?`· ${p} ·`:""})]}):null})]})})}function pe({accounts:s,onChange:r}){const{t:i}=C(["settings","common"]),o=Object.entries(s),a=(n,c)=>{r({...s,[n]:{...s[n],...c}})},m=n=>{const c={...s};delete c[n],r(c)},l=(n,c)=>{if(!c||c===n)return;if(s[c]){w.error(i("messengers.dingtalk.accountRenameCollision",{id:c}));return}const d={};for(const[b,p]of Object.entries(s))d[b===n?c:b]=p;r(d)},h=()=>{let n=o.length+1,c=`account-${n}`;for(;s[c];)n+=1,c=`account-${n}`;r({...s,[c]:{enabled:!0}})};return e.jsxs("div",{className:"mt-3 border-t border-border pt-3",children:[e.jsxs("div",{className:"mb-2 flex items-center justify-between",children:[e.jsx("div",{className:"text-xs font-semibold text-text-dim",children:i("messengers.dingtalk.accountsTitle")}),e.jsxs(k,{type:"button",size:"sm",variant:"outline",onClick:h,children:["+ ",i("messengers.dingtalk.addAccount")]})]}),o.length===0?e.jsx("div",{className:"text-xs text-text-dim italic",children:i("messengers.dingtalk.accountsEmpty")}):e.jsx("div",{className:"space-y-3",children:o.map(([n,c])=>e.jsxs("div",{className:"rounded-md border border-border bg-surface-2/45 p-2",children:[e.jsxs("div",{className:"mb-2 flex items-center gap-2",children:[e.jsx(R,{id:`acct-id-${n}`,defaultValue:n,onBlur:d=>l(n,d.target.value.trim()),className:"font-mono text-xs w-40",placeholder:"account-id"}),e.jsx(R,{id:`acct-name-${n}`,value:c.name??"",onChange:d=>a(n,{name:d.target.value}),className:"text-xs flex-1",placeholder:i("messengers.dingtalk.accountName")}),e.jsxs("label",{className:"flex items-center gap-1 text-xs",children:[e.jsx("input",{type:"checkbox",checked:c.enabled!==!1,onChange:d=>a(n,{enabled:d.target.checked})}),i("messengers.enabled")]}),e.jsx(k,{type:"button",size:"sm",variant:"ghost",onClick:()=>m(n),className:"text-danger",children:e.jsx(Q,{className:"size-4"})})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(u,{id:`acct-cid-${n}`,label:i("messengers.fields.clientId"),value:c.clientId??"",onChange:d=>a(n,{clientId:d})}),e.jsx(u,{id:`acct-secret-${n}`,label:i("messengers.fields.clientSecret"),value:c.clientSecret??"",type:"password",onChange:d=>a(n,{clientSecret:d})}),e.jsx(y,{id:`acct-dm-${n}`,label:i("messengers.dingtalk.dmPolicy"),value:c.dmPolicy??"open",onChange:d=>a(n,{dmPolicy:d}),options:[{value:"open",label:i("messengers.dingtalk.policy.open")},{value:"pairing",label:i("messengers.dingtalk.policy.pairing")},{value:"allowlist",label:i("messengers.dingtalk.policy.allowlist")}]}),e.jsx(y,{id:`acct-group-${n}`,label:i("messengers.dingtalk.groupPolicy"),value:c.groupPolicy??"open",onChange:d=>a(n,{groupPolicy:d}),options:[{value:"open",label:i("messengers.dingtalk.policy.open")},{value:"allowlist",label:i("messengers.dingtalk.policy.allowlist")},{value:"disabled",label:i("messengers.dingtalk.policy.disabled")}]}),e.jsx(u,{id:`acct-allow-${n}`,label:i("messengers.dingtalk.allowFrom"),value:(c.allowFrom??[]).join(","),onChange:d=>a(n,{allowFrom:d.split(",").map(b=>b.trim()).filter(Boolean)})}),e.jsx(u,{id:`acct-gallow-${n}`,label:i("messengers.dingtalk.groupAllowFrom"),value:(c.groupAllowFrom??[]).join(","),onChange:d=>a(n,{groupAllowFrom:d.split(",").map(b=>b.trim()).filter(Boolean)})}),e.jsx(y,{id:`acct-ack-${n}`,label:i("messengers.dingtalk.ackReaction"),value:c.ackReaction??"off",onChange:d=>a(n,{ackReaction:d}),options:[{value:"off",label:i("messengers.dingtalk.ack.off")},{value:"emoji",label:i("messengers.dingtalk.ack.emoji")},{value:"kaomoji",label:i("messengers.dingtalk.ack.kaomoji")}]})]})]},n))}),e.jsx("div",{className:"mt-1 text-xs text-text-dim",children:i("messengers.dingtalk.accountsHint")})]})}export{qe as default};
|
|
2
|
+
//# sourceMappingURL=messengers-GYVTFlAj.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messengers-GYVTFlAj.js","sources":["../../src/routes/settings/messengers.tsx"],"sourcesContent":["/**\n * /settings/messengers — per-IM-platform connection config.\n *\n * Layout: one card per platform (WeChat / Telegram / Feishu /\n * DingTalk / Discord). Each card has:\n * * Title + hint\n * * Enable / disable toggle (reads / writes config.messengers[])\n * * When enabled, the platform's config fields (texted)\n * * For WeChat: a \"Scan QR\" button → modal with QR + 2s polling\n *\n * Save All button at the top batches every dirty platform into one\n * PUT /api/config. The discard button reverts the local draft to\n * server-side values.\n *\n * The WeChat QR flow is special: enabling WeChat requires scanning\n * a QR code (the slot in config.messengers gets added by the\n * backend on `confirmed`, so we just open the modal and re-fetch\n * config after a successful scan).\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { Link } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport {\n ArrowRight,\n CheckCircle2,\n Loader2,\n MessageSquare,\n Play,\n Plug,\n QrCode,\n RefreshCcw,\n RotateCcw,\n Save,\n X,\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 Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/dialog'\nimport {\n useConfig,\n useRestartService,\n useServiceStatus,\n useStartService,\n useUpdateConfig,\n useStartWechatQr,\n useWechatQrStatus,\n} from '@/hooks/use-settings'\nimport { describeError } from '@/lib/api/errors'\nimport type { AppConfig } from '@/types/api'\nimport { cn } from '@/lib/utils'\n\n/** Slot names match what `config.messengers[]` contains.\n * WeChat uses 'wechat-ilink' (the iLink adapter ID). */\ntype Slot = 'wechat-ilink' | 'telegram' | 'feishu' | 'dingtalk' | 'discord'\n\ninterface PlatformDraft {\n enabled: boolean\n telegram?: { botToken?: string; channelId?: string }\n feishu?: { appId?: string; appSecret?: string; channelId?: string }\n dingtalk?: {\n clientId?: string\n clientSecret?: string\n channelId?: string\n // v1.2.37 (batch 1)\n dmPolicy?: 'open' | 'pairing' | 'allowlist'\n groupPolicy?: 'open' | 'allowlist' | 'disabled'\n allowFrom?: string[]\n groupAllowFrom?: string[]\n ackReaction?: 'off' | 'emoji' | 'kaomoji'\n // v1.2.41 (batch 4 follow-up) — full multi-account editor\n accounts?: Record<string, DingTalkAccountDraft>\n }\n discord?: { botToken?: string; channelId?: string }\n}\n\ntype Draft = Record<Slot, PlatformDraft>\n\nfunction buildDraft(cfg: AppConfig | undefined): Draft {\n const m = new Set(cfg?.messengers ?? [])\n return {\n 'wechat-ilink': { enabled: m.has('wechat-ilink') },\n telegram: { enabled: m.has('telegram'), telegram: { ...(cfg?.telegram ?? {}) } },\n feishu: { enabled: m.has('feishu'), feishu: { ...(cfg?.feishu ?? {}) } },\n dingtalk: { enabled: m.has('dingtalk'), dingtalk: { ...(cfg?.dingtalk ?? {}) } },\n discord: { enabled: m.has('discord'), discord: { ...(cfg?.discord ?? {}) } },\n }\n}\n\nfunction buildPatch(draft: Draft, cfg: AppConfig): Partial<AppConfig> {\n const messengers: string[] = []\n for (const k of Object.keys(draft) as Slot[]) if (draft[k].enabled) messengers.push(k)\n const patch: Partial<AppConfig> = {\n messengers,\n // Preserve unknown extra fields the AppConfig type permits.\n ...Object.fromEntries(\n Object.entries(cfg).filter(([k]) => ![\n 'messengers', 'telegram', 'feishu', 'dingtalk', 'discord',\n ].includes(k)),\n ),\n }\n // Only include platform blocks that are enabled. Omitting disabled\n // platforms avoids PUT /api/config merging `{}` and failing zod\n // (telegram.botToken / feishu.appSecret / discord.botToken require\n // min(1) when the key is present).\n if (draft.telegram.enabled && draft.telegram.telegram) {\n patch.telegram = draft.telegram.telegram\n }\n if (draft.feishu.enabled && draft.feishu.feishu) {\n patch.feishu = draft.feishu.feishu\n }\n if (draft.dingtalk.enabled && draft.dingtalk.dingtalk) {\n patch.dingtalk = draft.dingtalk.dingtalk\n }\n if (draft.discord.enabled && draft.discord.discord) {\n patch.discord = draft.discord.discord\n }\n return patch\n}\n\nexport default function SettingsMessengersRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const cfgQuery = useConfig()\n const updateCfg = useUpdateConfig()\n const serviceQuery = useServiceStatus()\n const startService = useStartService()\n const restartService = useRestartService()\n\n const [draft, setDraft] = useState<Draft>(() => buildDraft(cfgQuery.data))\n // Sync the draft once cfg lands. We don't re-sync on every cfg\n // refetch — that would discard unsaved edits.\n const [synced, setSynced] = useState(false)\n useEffect(() => {\n if (synced) return\n if (!cfgQuery.data) return\n setDraft(buildDraft(cfgQuery.data))\n setSynced(true)\n }, [cfgQuery.data, synced])\n\n const cfg = cfgQuery.data\n const isDirty = useMemo(() => {\n if (!cfg) return false\n return JSON.stringify(buildDraft(cfg)) !== JSON.stringify(draft)\n }, [cfg, draft])\n\n // WeChat QR modal state\n const [qrOpen, setQrOpen] = useState(false)\n const [focusedSlot, setFocusedSlot] = useState<Slot | null>(null)\n const [needsApply, setNeedsApply] = useState(false)\n\n // v1.2.71 — AGIM_PLATFORM_BLACKLIST gate. Backend sends the\n // alias-expanded set in features.blacklistedPlatforms; we hide the\n // matching PlatformCard so blacklisted IMs disappear from the page\n // entirely (not just have empty data).\n const blockedPlatforms = new Set(cfg?.features?.blacklistedPlatforms ?? [])\n const isBlocked = (slot: Slot): boolean => blockedPlatforms.has(slot)\n\n function patchSlot(slot: Slot, partial: Partial<PlatformDraft>): void {\n setDraft((prev) => ({ ...prev, [slot]: { ...prev[slot], ...partial } }))\n }\n\n function pickPlatform(slot: Slot): void {\n patchSlot(slot, { enabled: true })\n setFocusedSlot(slot)\n requestAnimationFrame(() => {\n document.getElementById(`messenger-${slot}`)?.scrollIntoView({\n behavior: 'smooth',\n block: 'start',\n })\n })\n }\n\n async function onSave(): Promise<void> {\n if (!cfg) return\n try {\n await updateCfg.mutateAsync(buildPatch(draft, cfg))\n toast.success(t('messengers.savedToast'))\n setNeedsApply(true)\n setSynced(false) // rebuild draft from refreshed cfg on next paint\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n function onDiscard(): void {\n if (cfg) setDraft(buildDraft(cfg))\n }\n\n async function onApplyChanges(): Promise<void> {\n const service = serviceQuery.data\n const isRunning = Boolean(service && service.mode !== 'none')\n try {\n if (isRunning) {\n await restartService.mutateAsync()\n } else {\n await startService.mutateAsync()\n }\n toast.success(t('messengers.apply.appliedToast'))\n setNeedsApply(false)\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\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('messengers.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => cfgQuery.refetch()}\n disabled={cfgQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {cfgQuery.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('messengers.subtitle')}</p>\n </header>\n\n {cfgQuery.isLoading ? null : cfg ? (\n <MessengerQuickStartCard\n cfg={cfg}\n isBlocked={isBlocked}\n onScanWechat={() => setQrOpen(true)}\n onPickPlatform={pickPlatform}\n />\n ) : null}\n\n {/* Save bar */}\n <div className=\"flex flex-wrap items-center gap-2\">\n {isDirty ? (\n <>\n <Badge variant=\"info\">{t('messengers.dirtyHint')}</Badge>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n onClick={onDiscard}\n disabled={updateCfg.isPending}\n >\n <X className=\"h-4 w-4\" />\n {t('messengers.discardAll')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => void onSave()}\n disabled={updateCfg.isPending}\n >\n {updateCfg.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Save className=\"h-4 w-4\" />}\n {updateCfg.isPending ? t('messengers.saving') : t('messengers.saveAll')}\n </Button>\n </>\n ) : (\n <span className=\"text-xs text-text-muted\">{t('env.noChanges')}</span>\n )}\n </div>\n\n {needsApply ? (\n <ApplyChangesCard\n serviceMode={serviceQuery.data?.mode}\n isLoading={serviceQuery.isLoading}\n isPending={startService.isPending || restartService.isPending}\n onApply={() => void onApplyChanges()}\n />\n ) : null}\n\n {cfgQuery.isLoading ? (\n <div className=\"h-96 rounded-md bg-surface-2 animate-pulse\" />\n ) : !cfg ? null : (\n <div className=\"flex flex-col gap-3\">\n {!isBlocked('wechat-ilink') ? (\n <PlatformCard\n slot=\"wechat-ilink\"\n label={t('messengers.platform.wechat')}\n hint={t('messengers.hint.wechat')}\n enabled={draft['wechat-ilink'].enabled}\n onToggle={(v) => patchSlot('wechat-ilink', { enabled: v })}\n focused={focusedSlot === 'wechat-ilink'}\n >\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => setQrOpen(true)}\n >\n <QrCode className=\"h-4 w-4\" />\n {t('messengers.scanQr')}\n </Button>\n </PlatformCard>\n ) : null}\n\n {cfg.features?.globalIm && !isBlocked('telegram') ? (\n <PlatformCard\n slot=\"telegram\"\n label={t('messengers.platform.telegram')}\n hint={t('messengers.hint.telegram')}\n enabled={draft.telegram.enabled}\n onToggle={(v) => patchSlot('telegram', { enabled: v })}\n focused={focusedSlot === 'telegram'}\n >\n <FieldRow\n id=\"tg-token\" label={t('messengers.fields.botToken')}\n value={draft.telegram.telegram?.botToken ?? ''}\n type=\"password\"\n onChange={(v) => patchSlot('telegram', { telegram: { ...draft.telegram.telegram, botToken: v } })}\n />\n <FieldRow\n id=\"tg-channel\" label={t('messengers.fields.channelId')}\n value={draft.telegram.telegram?.channelId ?? ''}\n onChange={(v) => patchSlot('telegram', { telegram: { ...draft.telegram.telegram, channelId: v } })}\n />\n </PlatformCard>\n ) : null}\n\n {!isBlocked('feishu') ? (\n <PlatformCard\n slot=\"feishu\"\n label={t('messengers.platform.feishu')}\n hint={t('messengers.hint.feishu')}\n enabled={draft.feishu.enabled}\n onToggle={(v) => patchSlot('feishu', { enabled: v })}\n focused={focusedSlot === 'feishu'}\n >\n <FieldRow\n id=\"fs-appid\" label={t('messengers.fields.appId')}\n value={draft.feishu.feishu?.appId ?? ''}\n onChange={(v) => patchSlot('feishu', { feishu: { ...draft.feishu.feishu, appId: v } })}\n />\n <FieldRow\n id=\"fs-secret\" label={t('messengers.fields.appSecret')}\n value={draft.feishu.feishu?.appSecret ?? ''}\n type=\"password\"\n onChange={(v) => patchSlot('feishu', { feishu: { ...draft.feishu.feishu, appSecret: v } })}\n />\n <FieldRow\n id=\"fs-channel\" label={t('messengers.fields.channelId')}\n value={draft.feishu.feishu?.channelId ?? ''}\n onChange={(v) => patchSlot('feishu', { feishu: { ...draft.feishu.feishu, channelId: v } })}\n />\n </PlatformCard>\n ) : null}\n\n {!isBlocked('dingtalk') ? (\n <PlatformCard\n slot=\"dingtalk\"\n label={t('messengers.platform.dingtalk')}\n hint={t('messengers.hint.dingtalk')}\n enabled={draft.dingtalk.enabled}\n onToggle={(v) => patchSlot('dingtalk', { enabled: v })}\n focused={focusedSlot === 'dingtalk'}\n >\n <FieldRow\n id=\"dt-cid\" label={t('messengers.fields.clientId')}\n value={draft.dingtalk.dingtalk?.clientId ?? ''}\n onChange={(v) => patchSlot('dingtalk', { dingtalk: { ...draft.dingtalk.dingtalk, clientId: v } })}\n />\n <FieldRow\n id=\"dt-secret\" label={t('messengers.fields.clientSecret')}\n value={draft.dingtalk.dingtalk?.clientSecret ?? ''}\n type=\"password\"\n onChange={(v) => patchSlot('dingtalk', { dingtalk: { ...draft.dingtalk.dingtalk, clientSecret: v } })}\n />\n <FieldRow\n id=\"dt-channel\" label={t('messengers.fields.channelId')}\n value={draft.dingtalk.dingtalk?.channelId ?? ''}\n onChange={(v) => patchSlot('dingtalk', { dingtalk: { ...draft.dingtalk.dingtalk, channelId: v } })}\n />\n {/* v1.2.37 (batch 1) — access policy + ack-reaction */}\n <SelectRow<'open' | 'pairing' | 'allowlist'>\n id=\"dt-dm-policy\" label={t('messengers.dingtalk.dmPolicy')}\n value={draft.dingtalk.dingtalk?.dmPolicy ?? 'open'}\n onChange={(v) => patchSlot('dingtalk', { dingtalk: { ...draft.dingtalk.dingtalk, dmPolicy: v } })}\n options={[\n { value: 'open', label: t('messengers.dingtalk.policy.open') },\n { value: 'pairing', label: t('messengers.dingtalk.policy.pairing') },\n { value: 'allowlist', label: t('messengers.dingtalk.policy.allowlist') },\n ]}\n />\n <SelectRow<'open' | 'allowlist' | 'disabled'>\n id=\"dt-group-policy\" label={t('messengers.dingtalk.groupPolicy')}\n value={draft.dingtalk.dingtalk?.groupPolicy ?? 'open'}\n onChange={(v) => patchSlot('dingtalk', { dingtalk: { ...draft.dingtalk.dingtalk, groupPolicy: v } })}\n options={[\n { value: 'open', label: t('messengers.dingtalk.policy.open') },\n { value: 'allowlist', label: t('messengers.dingtalk.policy.allowlist') },\n { value: 'disabled', label: t('messengers.dingtalk.policy.disabled') },\n ]}\n />\n <FieldRow\n id=\"dt-allow-from\" label={t('messengers.dingtalk.allowFrom')}\n value={(draft.dingtalk.dingtalk?.allowFrom ?? []).join(',')}\n onChange={(v) => patchSlot('dingtalk', {\n dingtalk: {\n ...draft.dingtalk.dingtalk,\n allowFrom: v.split(',').map((s) => s.trim()).filter(Boolean),\n },\n })}\n />\n <FieldRow\n id=\"dt-group-allow-from\" label={t('messengers.dingtalk.groupAllowFrom')}\n value={(draft.dingtalk.dingtalk?.groupAllowFrom ?? []).join(',')}\n onChange={(v) => patchSlot('dingtalk', {\n dingtalk: {\n ...draft.dingtalk.dingtalk,\n groupAllowFrom: v.split(',').map((s) => s.trim()).filter(Boolean),\n },\n })}\n />\n <SelectRow<'off' | 'emoji' | 'kaomoji'>\n id=\"dt-ack\" label={t('messengers.dingtalk.ackReaction')}\n value={draft.dingtalk.dingtalk?.ackReaction ?? 'off'}\n onChange={(v) => patchSlot('dingtalk', { dingtalk: { ...draft.dingtalk.dingtalk, ackReaction: v } })}\n options={[\n { value: 'off', label: t('messengers.dingtalk.ack.off') },\n { value: 'emoji', label: t('messengers.dingtalk.ack.emoji') },\n { value: 'kaomoji', label: t('messengers.dingtalk.ack.kaomoji') },\n ]}\n />\n {/* v1.2.41 (batch 4 follow-up) — multi-account CRUD editor. */}\n <DingTalkAccountsEditor\n accounts={draft.dingtalk.dingtalk?.accounts ?? {}}\n onChange={(next) => patchSlot('dingtalk', {\n dingtalk: { ...draft.dingtalk.dingtalk, accounts: next },\n })}\n />\n </PlatformCard>\n ) : null}\n\n {cfg.features?.globalIm && !isBlocked('discord') ? (\n <PlatformCard\n slot=\"discord\"\n label={t('messengers.platform.discord')}\n hint={t('messengers.hint.discord')}\n enabled={draft.discord.enabled}\n onToggle={(v) => patchSlot('discord', { enabled: v })}\n focused={focusedSlot === 'discord'}\n >\n <FieldRow\n id=\"dc-token\" label={t('messengers.fields.botToken')}\n value={draft.discord.discord?.botToken ?? ''}\n type=\"password\"\n onChange={(v) => patchSlot('discord', { discord: { ...draft.discord.discord, botToken: v } })}\n />\n <FieldRow\n id=\"dc-channel\" label={t('messengers.fields.channelId')}\n value={draft.discord.discord?.channelId ?? ''}\n onChange={(v) => patchSlot('discord', { discord: { ...draft.discord.discord, channelId: v } })}\n />\n </PlatformCard>\n ) : null}\n </div>\n )}\n\n <WechatQrDialog\n open={qrOpen}\n onOpenChange={setQrOpen}\n onConfirmed={() => {\n void cfgQuery.refetch()\n setSynced(false)\n setNeedsApply(true)\n }}\n />\n </div>\n )\n}\n\ninterface ApplyChangesCardProps {\n serviceMode: string | undefined\n isLoading: boolean\n isPending: boolean\n onApply: () => void\n}\n\nfunction ApplyChangesCard({\n serviceMode,\n isLoading,\n isPending,\n onApply,\n}: ApplyChangesCardProps): JSX.Element {\n const { t } = useTranslation('settings')\n const isRunning = serviceMode != null && serviceMode !== 'none'\n return (\n <section className=\"rounded-md border border-warning/40 bg-warning-bg p-4\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center\">\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-surface text-warning\">\n {isRunning ? <RotateCcw className=\"h-4 w-4\" /> : <Play className=\"h-4 w-4\" />}\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"text-sm font-semibold\">{t('messengers.apply.title')}</h2>\n <Badge variant=\"warning\">{t('messengers.apply.badge')}</Badge>\n </div>\n <p className=\"mt-1 text-sm text-text-dim\">\n {isRunning ? t('messengers.apply.restartDetail') : t('messengers.apply.startDetail')}\n </p>\n </div>\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={isLoading || isPending}\n onClick={onApply}\n >\n {isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : isRunning\n ? <RotateCcw className=\"h-4 w-4\" />\n : <Play className=\"h-4 w-4\" />}\n <span>\n {isPending\n ? isRunning\n ? t('messengers.apply.restarting')\n : t('messengers.apply.starting')\n : isRunning\n ? t('messengers.apply.restart')\n : t('messengers.apply.start')}\n </span>\n </Button>\n </div>\n </section>\n )\n}\n\ninterface MessengerQuickStartCardProps {\n cfg: AppConfig\n isBlocked: (slot: Slot) => boolean\n onScanWechat: () => void\n onPickPlatform: (slot: Slot) => void\n}\n\nfunction MessengerQuickStartCard({\n cfg,\n isBlocked,\n onScanWechat,\n onPickPlatform,\n}: MessengerQuickStartCardProps): JSX.Element {\n const { t } = useTranslation('settings')\n const connected = cfg.messengers ?? []\n const hasConnected = connected.length > 0\n const showGlobalIm = cfg.features?.globalIm === true\n const options: Array<{\n slot: Slot\n label: string\n title: string\n detail: string\n kind: 'qr' | 'config'\n }> = []\n if (!isBlocked('wechat-ilink')) {\n options.push({\n slot: 'wechat-ilink',\n label: t('messengers.platform.wechat'),\n title: t('messengers.quick.option.wechat.title'),\n detail: t('messengers.quick.option.wechat.detail'),\n kind: 'qr',\n })\n }\n if (!isBlocked('feishu')) {\n options.push({\n slot: 'feishu',\n label: t('messengers.platform.feishu'),\n title: t('messengers.quick.option.feishu.title'),\n detail: t('messengers.quick.option.feishu.detail'),\n kind: 'config',\n })\n }\n if (!isBlocked('dingtalk')) {\n options.push({\n slot: 'dingtalk',\n label: t('messengers.platform.dingtalk'),\n title: t('messengers.quick.option.dingtalk.title'),\n detail: t('messengers.quick.option.dingtalk.detail'),\n kind: 'config',\n })\n }\n if (showGlobalIm && !isBlocked('telegram')) {\n options.push({\n slot: 'telegram',\n label: t('messengers.platform.telegram'),\n title: t('messengers.quick.option.telegram.title'),\n detail: t('messengers.quick.option.telegram.detail'),\n kind: 'config',\n })\n }\n if (showGlobalIm && !isBlocked('discord')) {\n options.push({\n slot: 'discord',\n label: t('messengers.platform.discord'),\n title: t('messengers.quick.option.discord.title'),\n detail: t('messengers.quick.option.discord.detail'),\n kind: 'config',\n })\n }\n\n return (\n <section className=\"rounded-md border border-border bg-surface p-4\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-start\">\n <span className={cn(\n 'flex h-10 w-10 shrink-0 items-center justify-center rounded-full',\n hasConnected ? 'bg-success-bg text-success' : 'bg-accent-bg text-accent',\n )}>\n {hasConnected ? <CheckCircle2 className=\"h-5 w-5\" /> : <Plug className=\"h-5 w-5\" />}\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"text-sm font-semibold\">\n {hasConnected ? t('messengers.quick.connectedTitle') : t('messengers.quick.title')}\n </h2>\n <Badge variant={hasConnected ? 'success' : 'info'}>\n {hasConnected ? t('messengers.quick.connectedBadge') : t('messengers.quick.nextBadge')}\n </Badge>\n </div>\n <p className=\"mt-1 text-sm text-text-dim\">\n {hasConnected\n ? t('messengers.quick.connectedDetail', {\n platforms: connected.map((p) => platformLabel(p, t)).join(', '),\n })\n : t('messengers.quick.subtitle')}\n </p>\n\n {hasConnected ? (\n <div className=\"mt-3 flex flex-wrap gap-2\">\n <Button asChild size=\"sm\">\n <Link to=\"/?welcome=1\">\n <MessageSquare className=\"h-4 w-4\" />\n <span>{t('messengers.quick.webChat')}</span>\n </Link>\n </Button>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => {\n const first = options.find((option) => !connected.includes(option.slot)) ?? options[0]\n if (!first) return\n if (first.kind === 'qr') onScanWechat()\n else onPickPlatform(first.slot)\n }}\n >\n <Plug className=\"h-4 w-4\" />\n <span>{t('messengers.quick.addAnother')}</span>\n </Button>\n </div>\n ) : (\n <div className=\"mt-4 grid gap-2 sm:grid-cols-2\">\n {options.map((option) => (\n <div key={option.slot} className=\"rounded-md border border-border bg-surface-2 p-3\">\n <div className=\"flex items-start gap-2\">\n <span className=\"mt-0.5 text-text-dim\">\n {option.kind === 'qr' ? <QrCode className=\"h-4 w-4\" /> : <Plug className=\"h-4 w-4\" />}\n </span>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"text-sm font-medium\">{option.title}</h3>\n <p className=\"mt-1 text-xs text-text-dim\">{option.detail}</p>\n </div>\n </div>\n <Button\n type=\"button\"\n variant={option.kind === 'qr' ? 'default' : 'secondary'}\n size=\"sm\"\n className=\"mt-3\"\n onClick={() => {\n if (option.kind === 'qr') onScanWechat()\n else onPickPlatform(option.slot)\n }}\n >\n <span>\n {option.kind === 'qr'\n ? t('messengers.quick.scanWechat')\n : t('messengers.quick.configurePlatform', { platform: option.label })}\n </span>\n <ArrowRight className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n </section>\n )\n}\n\ninterface PlatformCardProps {\n slot: Slot\n label: string\n hint: string\n enabled: boolean\n onToggle: (v: boolean) => void\n children?: React.ReactNode\n focused?: boolean\n}\n\nfunction PlatformCard({\n slot,\n label,\n hint,\n enabled,\n onToggle,\n children,\n focused = false,\n}: PlatformCardProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <div\n id={`messenger-${slot}`}\n className={cn(\n 'scroll-mt-20 rounded-md border border-border bg-surface p-4',\n focused && 'border-accent ring-2 ring-accent/30',\n )}\n >\n <div className=\"flex items-start gap-3\">\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium text-text\">{label}</span>\n <Badge variant={enabled ? 'success' : 'outline'}>\n {enabled ? t('messengers.enabled') : t('messengers.disabled')}\n </Badge>\n </div>\n <p className=\"mt-1 text-xs text-text-dim\">{hint}</p>\n </div>\n <label className=\"inline-flex items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={enabled}\n onChange={(e) => onToggle(e.target.checked)}\n className=\"h-4 w-4 accent-accent cursor-pointer\"\n />\n </label>\n </div>\n {enabled && children && (\n <div className=\"mt-3 flex flex-col gap-2\">\n {children}\n </div>\n )}\n </div>\n )\n}\n\nfunction platformLabel(id: string, t: ReturnType<typeof useTranslation>['t']): string {\n const labels: Record<string, string> = {\n 'wechat-ilink': t('messengers.platform.wechat'),\n telegram: t('messengers.platform.telegram'),\n feishu: t('messengers.platform.feishu'),\n dingtalk: t('messengers.platform.dingtalk'),\n discord: t('messengers.platform.discord'),\n }\n return labels[id] ?? id\n}\n\ninterface FieldRowProps {\n id: string\n label: string\n value: string\n onChange: (v: string) => void\n type?: 'text' | 'password'\n}\n\nfunction FieldRow({ id, label, value, onChange, type = 'text' }: FieldRowProps): JSX.Element {\n return (\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[180px_1fr] sm:items-center sm:gap-2\">\n <Label htmlFor={id} className=\"text-xs text-text-dim\">{label}</Label>\n <Input\n id={id}\n type={type}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n autoComplete=\"off\"\n className=\"font-mono text-xs\"\n />\n </div>\n )\n}\n\n// v1.2.37 (batch 1) — dropdown sibling of FieldRow for enum settings.\ninterface SelectRowProps<T extends string> {\n id: string\n label: string\n value: T\n onChange: (v: T) => void\n options: Array<{ value: T; label: string }>\n}\nfunction SelectRow<T extends string>({ id, label, value, onChange, options }: SelectRowProps<T>): JSX.Element {\n return (\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[180px_1fr] sm:items-center sm:gap-2\">\n <Label htmlFor={id} className=\"text-xs text-text-dim\">{label}</Label>\n <select\n id={id}\n value={value}\n onChange={(e) => onChange(e.target.value as T)}\n className=\"rounded-md border border-border bg-surface px-2 py-1 text-xs text-text\"\n >\n {options.map((o) => (\n <option key={o.value} value={o.value}>{o.label}</option>\n ))}\n </select>\n </div>\n )\n}\n\ninterface WechatQrDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n onConfirmed: () => void\n}\n\nfunction WechatQrDialog({ open, onOpenChange, onConfirmed }: WechatQrDialogProps): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const start = useStartWechatQr()\n const [token, setToken] = useState<string | null>(null)\n const [qrImage, setQrImage] = useState<string | null>(null)\n const [startError, setStartError] = useState<string | null>(null)\n\n // Kick off the start mutation each time the dialog opens; reset on close.\n useEffect(() => {\n if (!open) {\n setToken(null)\n setQrImage(null)\n setStartError(null)\n return\n }\n let active = true\n start.mutateAsync().then((r) => {\n if (!active) return\n setQrImage(r.qrImage)\n setToken(r.qrToken)\n }).catch((err) => {\n if (!active) return\n setStartError(err instanceof Error ? err.message : String(err))\n })\n return () => { active = false }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open])\n\n const statusQuery = useWechatQrStatus(open ? token : null)\n const status = statusQuery.data?.status\n\n useEffect(() => {\n if (status === 'confirmed') {\n toast.success(t('messengers.qr.confirmed'))\n onConfirmed()\n onOpenChange(false)\n }\n if (status === 'expired') {\n toast.error(t('messengers.qr.expired'))\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [status])\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{t('messengers.qr.title')}</DialogTitle>\n <DialogDescription>{t('messengers.qr.description')}</DialogDescription>\n </DialogHeader>\n <div className=\"flex flex-col items-center gap-3\">\n {start.isPending && !qrImage ? (\n <>\n <Loader2 className=\"h-8 w-8 animate-spin text-text-dim\" />\n <p className=\"text-sm text-text-dim\">{t('messengers.qr.starting')}</p>\n </>\n ) : startError ? (\n <p className=\"text-sm text-danger\">{t('messengers.qr.loadFailed')}: {startError}</p>\n ) : qrImage ? (\n <>\n <img\n src={qrImage}\n alt={t('messengers.qr.title')}\n className=\"rounded-md border border-border\"\n />\n {status === 'expired'\n ? <p className=\"text-xs text-danger\">{t('messengers.qr.expired')}</p>\n : <p className=\"text-xs text-text-dim\">{status ? `· ${status} ·` : ''}</p>}\n </>\n ) : null}\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n\n// ─── v1.2.41 — DingTalk multi-account CRUD editor ───────────────────\n// Renders below the main DingTalk card. Owns the in-memory accounts\n// dict and bubbles every change up via `onChange` so the page-level\n// dirty/save logic notices and lights up the Save button.\n//\n// Each row shows: id (read-only after creation), name, clientId,\n// clientSecret (password mode, masked on echo), dmPolicy / groupPolicy /\n// ackReaction selectors, allowFrom / groupAllowFrom CSVs, enabled\n// toggle, and a delete button. \"Add account\" appends a fresh row with\n// a generated id the operator can rename inline.\n\nexport interface DingTalkAccountDraft {\n name?: string\n clientId?: string\n clientSecret?: string\n dmPolicy?: 'open' | 'pairing' | 'allowlist'\n groupPolicy?: 'open' | 'allowlist' | 'disabled'\n allowFrom?: string[]\n groupAllowFrom?: string[]\n ackReaction?: 'off' | 'emoji' | 'kaomoji'\n enabled?: boolean\n}\n\ninterface DingTalkAccountsEditorProps {\n accounts: Record<string, DingTalkAccountDraft>\n onChange: (next: Record<string, DingTalkAccountDraft>) => void\n}\n\nfunction DingTalkAccountsEditor({ accounts, onChange }: DingTalkAccountsEditorProps): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const entries = Object.entries(accounts)\n\n const updateAccount = (id: string, patch: Partial<DingTalkAccountDraft>) => {\n onChange({ ...accounts, [id]: { ...accounts[id], ...patch } })\n }\n const deleteAccount = (id: string) => {\n const next = { ...accounts }\n delete next[id]\n onChange(next)\n }\n const renameAccount = (oldId: string, newId: string) => {\n if (!newId || newId === oldId) return\n if (accounts[newId]) {\n toast.error(t('messengers.dingtalk.accountRenameCollision', { id: newId }))\n return\n }\n const next: Record<string, DingTalkAccountDraft> = {}\n for (const [k, v] of Object.entries(accounts)) {\n next[k === oldId ? newId : k] = v\n }\n onChange(next)\n }\n const addAccount = () => {\n // Find an unused id of shape account-N.\n let n = entries.length + 1\n let candidate = `account-${n}`\n while (accounts[candidate]) { n += 1; candidate = `account-${n}` }\n onChange({ ...accounts, [candidate]: { enabled: true } })\n }\n\n return (\n <div className=\"mt-3 border-t border-border pt-3\">\n <div className=\"mb-2 flex items-center justify-between\">\n <div className=\"text-xs font-semibold text-text-dim\">\n {t('messengers.dingtalk.accountsTitle')}\n </div>\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={addAccount}>\n + {t('messengers.dingtalk.addAccount')}\n </Button>\n </div>\n\n {entries.length === 0 ? (\n <div className=\"text-xs text-text-dim italic\">\n {t('messengers.dingtalk.accountsEmpty')}\n </div>\n ) : (\n <div className=\"space-y-3\">\n {entries.map(([id, acct]) => (\n <div key={id} className=\"rounded-md border border-border bg-surface-2/45 p-2\">\n <div className=\"mb-2 flex items-center gap-2\">\n <Input\n id={`acct-id-${id}`}\n defaultValue={id}\n onBlur={(e) => renameAccount(id, e.target.value.trim())}\n className=\"font-mono text-xs w-40\"\n placeholder=\"account-id\"\n />\n <Input\n id={`acct-name-${id}`}\n value={acct.name ?? ''}\n onChange={(e) => updateAccount(id, { name: e.target.value })}\n className=\"text-xs flex-1\"\n placeholder={t('messengers.dingtalk.accountName')}\n />\n <label className=\"flex items-center gap-1 text-xs\">\n <input\n type=\"checkbox\"\n checked={acct.enabled !== false}\n onChange={(e) => updateAccount(id, { enabled: e.target.checked })}\n />\n {t('messengers.enabled')}\n </label>\n <Button\n type=\"button\" size=\"sm\" variant=\"ghost\"\n onClick={() => deleteAccount(id)}\n className=\"text-danger\"\n >\n <X className=\"size-4\" />\n </Button>\n </div>\n <div className=\"space-y-1\">\n <FieldRow\n id={`acct-cid-${id}`} label={t('messengers.fields.clientId')}\n value={acct.clientId ?? ''}\n onChange={(v) => updateAccount(id, { clientId: v })}\n />\n <FieldRow\n id={`acct-secret-${id}`} label={t('messengers.fields.clientSecret')}\n value={acct.clientSecret ?? ''}\n type=\"password\"\n onChange={(v) => updateAccount(id, { clientSecret: v })}\n />\n <SelectRow<'open' | 'pairing' | 'allowlist'>\n id={`acct-dm-${id}`} label={t('messengers.dingtalk.dmPolicy')}\n value={acct.dmPolicy ?? 'open'}\n onChange={(v) => updateAccount(id, { dmPolicy: v })}\n options={[\n { value: 'open', label: t('messengers.dingtalk.policy.open') },\n { value: 'pairing', label: t('messengers.dingtalk.policy.pairing') },\n { value: 'allowlist', label: t('messengers.dingtalk.policy.allowlist') },\n ]}\n />\n <SelectRow<'open' | 'allowlist' | 'disabled'>\n id={`acct-group-${id}`} label={t('messengers.dingtalk.groupPolicy')}\n value={acct.groupPolicy ?? 'open'}\n onChange={(v) => updateAccount(id, { groupPolicy: v })}\n options={[\n { value: 'open', label: t('messengers.dingtalk.policy.open') },\n { value: 'allowlist', label: t('messengers.dingtalk.policy.allowlist') },\n { value: 'disabled', label: t('messengers.dingtalk.policy.disabled') },\n ]}\n />\n <FieldRow\n id={`acct-allow-${id}`} label={t('messengers.dingtalk.allowFrom')}\n value={(acct.allowFrom ?? []).join(',')}\n onChange={(v) => updateAccount(id, {\n allowFrom: v.split(',').map((s) => s.trim()).filter(Boolean),\n })}\n />\n <FieldRow\n id={`acct-gallow-${id}`} label={t('messengers.dingtalk.groupAllowFrom')}\n value={(acct.groupAllowFrom ?? []).join(',')}\n onChange={(v) => updateAccount(id, {\n groupAllowFrom: v.split(',').map((s) => s.trim()).filter(Boolean),\n })}\n />\n <SelectRow<'off' | 'emoji' | 'kaomoji'>\n id={`acct-ack-${id}`} label={t('messengers.dingtalk.ackReaction')}\n value={acct.ackReaction ?? 'off'}\n onChange={(v) => updateAccount(id, { ackReaction: v })}\n options={[\n { value: 'off', label: t('messengers.dingtalk.ack.off') },\n { value: 'emoji', label: t('messengers.dingtalk.ack.emoji') },\n { value: 'kaomoji', label: t('messengers.dingtalk.ack.kaomoji') },\n ]}\n />\n </div>\n </div>\n ))}\n </div>\n )}\n <div className=\"mt-1 text-xs text-text-dim\">{t('messengers.dingtalk.accountsHint')}</div>\n </div>\n )\n}\n"],"names":["buildDraft","cfg","m","buildPatch","draft","messengers","k","patch","SettingsMessengersRoute","t","useTranslation","cfgQuery","useConfig","updateCfg","useUpdateConfig","serviceQuery","useServiceStatus","startService","useStartService","restartService","useRestartService","setDraft","useState","synced","setSynced","useEffect","isDirty","useMemo","qrOpen","setQrOpen","focusedSlot","setFocusedSlot","needsApply","setNeedsApply","blockedPlatforms","isBlocked","slot","patchSlot","partial","prev","pickPlatform","onSave","toast","err","describeError","onDiscard","onApplyChanges","service","isRunning","jsxs","jsx","Button","Loader2","RefreshCcw","MessengerQuickStartCard","Fragment","Badge","X","Save","ApplyChangesCard","PlatformCard","v","QrCode","FieldRow","SelectRow","s","DingTalkAccountsEditor","next","WechatQrDialog","serviceMode","isLoading","isPending","onApply","RotateCcw","Play","onScanWechat","onPickPlatform","connected","hasConnected","showGlobalIm","options","cn","CheckCircle2","Plug","p","platformLabel","Link","MessageSquare","first","option","ArrowRight","label","hint","enabled","onToggle","children","focused","e","id","value","onChange","type","Label","Input","o","open","onOpenChange","onConfirmed","start","useStartWechatQr","token","setToken","qrImage","setQrImage","startError","setStartError","active","r","status","useWechatQrStatus","Dialog","DialogContent","DialogHeader","DialogTitle","DialogDescription","accounts","entries","updateAccount","deleteAccount","renameAccount","oldId","newId","addAccount","candidate","acct"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{h as j,u as g,v as N,p as i,s as v,j as e,w as m,I as x,e as n,d as h}from"./index-DCfdN5R7.js";import{r as c}from"./react-DlP5eolq.js";import{L as w}from"./loader-circle-DDdmcH0k.js";import{R as y}from"./refresh-ccw-DlAd-eTQ.js";import{Q as b}from"./qr-code-YrEuhMPC.js";import{E as k,a as C}from"./eye-BfPyNFzk.js";import{C as L}from"./copy-CD4A7VD8.js";import{S as U}from"./shield-alert-DOKK9EnJ.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
|
-
*/const S=j("Smartphone",[["rect",{width:"14",height:"20",x:"5",y:"2",rx:"2",ry:"2",key:"1yt0o3"}],["path",{d:"M12 18h.01",key:"mhygvu"}]]);function
|
|
7
|
-
//# sourceMappingURL=mobile-
|
|
6
|
+
*/const S=j("Smartphone",[["rect",{width:"14",height:"20",x:"5",y:"2",rx:"2",ry:"2",key:"1yt0o3"}],["path",{d:"M12 18h.01",key:"mhygvu"}]]);function T(){const{t:s}=g(["settings","common"]),[t,u]=c.useState(null),[r,d]=c.useState(!1),[o,p]=c.useState(""),l=N({mutationFn:()=>v.generateMobileQR(o.trim()?{host:o.trim()}:void 0),onSuccess:a=>{u(a),d(!1),i.success(s("mobile.generatedToast"))},onError:a=>i.error(a.message)});async function f(){if(t)try{await navigator.clipboard.writeText(t.loginUrl),i.success(s("mobile.copied"))}catch{i.error(s("mobile.copyFailed"))}}return e.jsxs("div",{className:"mx-auto flex max-w-4xl flex-col gap-6",children:[e.jsx("header",{className:"flex items-center gap-3",children:e.jsx("h1",{className:"text-xl font-semibold",children:s("mobile.title")})}),e.jsx("p",{className:"text-sm text-text-dim",children:s("mobile.subtitle")}),e.jsxs("section",{className:"rounded-md border border-border bg-surface p-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(S,{className:"h-4 w-4 text-text-dim"}),e.jsx("h2",{className:"text-sm font-semibold",children:s("mobile.generateCard")})]}),e.jsx("p",{className:"mt-1 text-xs text-text-dim",children:s("mobile.generateDesc")}),e.jsxs("div",{className:"mt-4 flex flex-col gap-2",children:[e.jsx(m,{className:"text-xs font-medium",children:s("mobile.hostLabel")}),e.jsx(x,{value:o,onChange:a=>p(a.target.value),placeholder:s("mobile.hostPlaceholder",{defaultValue:"auto-detect (leave blank)"}),className:"font-mono text-xs"}),e.jsx("p",{className:"text-[11px] text-text-dim",children:s("mobile.hostHint")})]}),e.jsxs("div",{className:"mt-4 flex items-center gap-2",children:[e.jsxs(n,{onClick:()=>l.mutate(),disabled:l.isPending,size:"sm",children:[l.isPending?e.jsx(w,{className:"h-4 w-4 animate-spin"}):t?e.jsx(y,{className:"h-4 w-4"}):e.jsx(b,{className:"h-4 w-4"}),e.jsx("span",{className:"ml-1",children:s(t?"mobile.regenerate":"mobile.generate")})]}),l.isPending&&e.jsx(h,{variant:"info",children:s("mobile.generating")})]})]}),t&&e.jsxs("section",{className:"rounded-md border border-border bg-surface p-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(b,{className:"h-4 w-4 text-text-dim"}),e.jsx("h2",{className:"text-sm font-semibold",children:s("mobile.scanCard")}),e.jsxs(h,{variant:"success",className:"ml-auto",children:[s("mobile.tokenLabel"),": ",e.jsx("span",{className:"ml-1 font-mono",children:t.label})]})]}),e.jsx("p",{className:"mt-1 text-xs text-text-dim",children:s("mobile.scanDesc")}),e.jsxs("div",{className:"mt-4 flex flex-col items-center gap-3 sm:flex-row sm:items-start",children:[e.jsx("div",{className:"shrink-0 rounded-md border border-border bg-white p-2",children:e.jsx("img",{src:t.qrDataUrl,alt:s("mobile.qrAlt",{defaultValue:"QR code for mobile chat"}),width:280,height:280,className:"block h-[280px] w-[280px]"})}),e.jsxs("div",{className:"flex w-full flex-col gap-3",children:[e.jsxs("div",{children:[e.jsx(m,{className:"text-xs font-medium",children:s("mobile.urlLabel")}),e.jsxs("div",{className:"mt-1 flex items-center gap-2",children:[e.jsx(x,{type:r?"text":"password",readOnly:!0,value:t.loginUrl,className:"font-mono text-[11px]"}),e.jsx(n,{size:"sm",variant:"ghost",onClick:()=>d(a=>!a),"aria-label":r?s("mobile.hideUrl",{defaultValue:"Hide URL"}):s("mobile.showUrl",{defaultValue:"Show URL"}),children:r?e.jsx(k,{className:"h-4 w-4"}):e.jsx(C,{className:"h-4 w-4"})}),e.jsx(n,{size:"sm",variant:"ghost",onClick:()=>void f(),"aria-label":s("mobile.copyUrl",{defaultValue:"Copy URL"}),children:e.jsx(L,{className:"h-4 w-4"})})]}),e.jsx("p",{className:"mt-1 text-[11px] text-text-dim",children:s("mobile.urlHint")})]}),e.jsxs("div",{children:[e.jsx(m,{className:"text-xs font-medium",children:s("mobile.tokenIdLabel")}),e.jsx("div",{className:"mt-1 font-mono text-xs",children:t.tokenId}),e.jsx("p",{className:"mt-1 text-[11px] text-text-dim",children:s("mobile.tokenIdHint")})]})]})]}),e.jsxs("div",{className:"mt-4 flex items-start gap-2 rounded-md border border-warning/40 bg-warning/5 p-3",children:[e.jsx(U,{className:"mt-0.5 h-4 w-4 shrink-0 text-warning"}),e.jsxs("div",{className:"text-xs",children:[e.jsx("div",{className:"font-medium",children:s("mobile.warningTitle")}),e.jsx("p",{className:"mt-1 text-text-dim",children:s("mobile.warningBody")}),e.jsx("a",{href:t.revokeHint,className:"mt-1 inline-block underline text-accent",children:s("mobile.revokeLink")})]})]})]})]})}export{T as default};
|
|
7
|
+
//# sourceMappingURL=mobile-VUyTo40E.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mobile-Bq0FH9JV.js","sources":["../../node_modules/lucide-react/dist/esm/icons/smartphone.js","../../src/routes/settings/mobile.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 Smartphone = createLucideIcon(\"Smartphone\", [\n [\"rect\", { width: \"14\", height: \"20\", x: \"5\", y: \"2\", rx: \"2\", ry: \"2\", key: \"1yt0o3\" }],\n [\"path\", { d: \"M12 18h.01\", key: \"mhygvu\" }]\n]);\n\nexport { Smartphone as default };\n//# sourceMappingURL=smartphone.js.map\n","/**\n * /settings/mobile — admin generates a QR an operator scans on a\n * phone to land directly inside /m/chat (v1.2.129).\n *\n * Flow:\n * 1. Click \"Generate QR\" → POST /api/mobile/qr → fresh role=user\n * token + QR PNG (data URL).\n * 2. Render QR, the embedded URL, and the token id.\n * 3. Phone scans → /m/login auto-submits the token cookie → /m/chat.\n *\n * Revoke: the link points the admin at /settings/security/tokens\n * where every token can be killed (the same UI works for the QR\n * tokens because they're stored in the same table with a\n * mobile-via-qr-* label).\n */\n\nimport { useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useMutation } from '@tanstack/react-query'\nimport { toast } from 'sonner'\nimport {\n Copy, Eye, EyeOff, Loader2, QrCode, RefreshCcw, ShieldAlert, Smartphone,\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 { api } from '@/lib/api/endpoints'\nimport type { MobileQRResponse } from '@/types/api'\n\nexport default function SettingsMobileRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const [result, setResult] = useState<MobileQRResponse | null>(null)\n const [showUrl, setShowUrl] = useState(false)\n const [host, setHost] = useState('')\n\n const generate = useMutation<MobileQRResponse, Error>({\n mutationFn: () =>\n api.generateMobileQR(host.trim() ? { host: host.trim() } : undefined),\n onSuccess: (r) => {\n setResult(r)\n setShowUrl(false)\n toast.success(t('mobile.generatedToast'))\n },\n onError: (e) => toast.error(e.message),\n })\n\n async function copyUrl(): Promise<void> {\n if (!result) return\n try {\n await navigator.clipboard.writeText(result.loginUrl)\n toast.success(t('mobile.copied'))\n } catch {\n toast.error(t('mobile.copyFailed'))\n }\n }\n\n return (\n <div className=\"mx-auto flex max-w-4xl flex-col gap-6\">\n <header className=\"flex items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('mobile.title')}</h1>\n </header>\n <p className=\"text-sm text-text-dim\">{t('mobile.subtitle')}</p>\n\n <section className=\"rounded-md border border-border bg-surface p-4\">\n <div className=\"flex items-center gap-2\">\n <Smartphone className=\"h-4 w-4 text-text-dim\" />\n <h2 className=\"text-sm font-semibold\">{t('mobile.generateCard')}</h2>\n </div>\n <p className=\"mt-1 text-xs text-text-dim\">{t('mobile.generateDesc')}</p>\n\n <div className=\"mt-4 flex flex-col gap-2\">\n <Label className=\"text-xs font-medium\">{t('mobile.hostLabel')}</Label>\n <Input\n value={host}\n onChange={(e) => setHost(e.target.value)}\n placeholder={t('mobile.hostPlaceholder', { defaultValue: 'auto-detect (leave blank)' })}\n className=\"font-mono text-xs\"\n />\n <p className=\"text-[11px] text-text-dim\">{t('mobile.hostHint')}</p>\n </div>\n\n <div className=\"mt-4 flex items-center gap-2\">\n <Button\n onClick={() => generate.mutate()}\n disabled={generate.isPending}\n size=\"sm\"\n >\n {generate.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : result ? <RefreshCcw className=\"h-4 w-4\" /> : <QrCode className=\"h-4 w-4\" />}\n <span className=\"ml-1\">\n {result ? t('mobile.regenerate') : t('mobile.generate')}\n </span>\n </Button>\n {generate.isPending && (\n <Badge variant=\"info\">{t('mobile.generating')}</Badge>\n )}\n </div>\n </section>\n\n {result && (\n <section className=\"rounded-md border border-border bg-surface p-4\">\n <div className=\"flex items-center gap-2\">\n <QrCode className=\"h-4 w-4 text-text-dim\" />\n <h2 className=\"text-sm font-semibold\">{t('mobile.scanCard')}</h2>\n <Badge variant=\"success\" className=\"ml-auto\">\n {t('mobile.tokenLabel')}: <span className=\"ml-1 font-mono\">{result.label}</span>\n </Badge>\n </div>\n <p className=\"mt-1 text-xs text-text-dim\">{t('mobile.scanDesc')}</p>\n\n <div className=\"mt-4 flex flex-col items-center gap-3 sm:flex-row sm:items-start\">\n <div className=\"shrink-0 rounded-md border border-border bg-white p-2\">\n <img\n src={result.qrDataUrl}\n alt={t('mobile.qrAlt', { defaultValue: 'QR code for mobile chat' })}\n width={280}\n height={280}\n className=\"block h-[280px] w-[280px]\"\n />\n </div>\n <div className=\"flex w-full flex-col gap-3\">\n <div>\n <Label className=\"text-xs font-medium\">{t('mobile.urlLabel')}</Label>\n <div className=\"mt-1 flex items-center gap-2\">\n <Input\n type={showUrl ? 'text' : 'password'}\n readOnly\n value={result.loginUrl}\n className=\"font-mono text-[11px]\"\n />\n <Button\n size=\"sm\" variant=\"ghost\"\n onClick={() => setShowUrl((v) => !v)}\n aria-label={showUrl\n ? t('mobile.hideUrl', { defaultValue: 'Hide URL' })\n : t('mobile.showUrl', { defaultValue: 'Show URL' })}\n >\n {showUrl ? <EyeOff className=\"h-4 w-4\" /> : <Eye className=\"h-4 w-4\" />}\n </Button>\n <Button\n size=\"sm\" variant=\"ghost\"\n onClick={() => void copyUrl()}\n aria-label={t('mobile.copyUrl', { defaultValue: 'Copy URL' })}\n >\n <Copy className=\"h-4 w-4\" />\n </Button>\n </div>\n <p className=\"mt-1 text-[11px] text-text-dim\">{t('mobile.urlHint')}</p>\n </div>\n <div>\n <Label className=\"text-xs font-medium\">{t('mobile.tokenIdLabel')}</Label>\n <div className=\"mt-1 font-mono text-xs\">{result.tokenId}</div>\n <p className=\"mt-1 text-[11px] text-text-dim\">{t('mobile.tokenIdHint')}</p>\n </div>\n </div>\n </div>\n\n <div className=\"mt-4 flex items-start gap-2 rounded-md border border-warning/40 bg-warning/5 p-3\">\n <ShieldAlert className=\"mt-0.5 h-4 w-4 shrink-0 text-warning\" />\n <div className=\"text-xs\">\n <div className=\"font-medium\">{t('mobile.warningTitle')}</div>\n <p className=\"mt-1 text-text-dim\">{t('mobile.warningBody')}</p>\n <a\n href={result.revokeHint}\n className=\"mt-1 inline-block underline text-accent\"\n >\n {t('mobile.revokeLink')}\n </a>\n </div>\n </div>\n </section>\n )}\n </div>\n )\n}\n"],"names":["Smartphone","createLucideIcon","SettingsMobileRoute","t","useTranslation","result","setResult","useState","showUrl","setShowUrl","host","setHost","generate","useMutation","api","r","toast","e","copyUrl","jsxs","jsx","Label","Input","Button","Loader2","RefreshCcw","QrCode","Badge","v","EyeOff","Eye","Copy","ShieldAlert"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"mobile-VUyTo40E.js","sources":["../../node_modules/lucide-react/dist/esm/icons/smartphone.js","../../src/routes/settings/mobile.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 Smartphone = createLucideIcon(\"Smartphone\", [\n [\"rect\", { width: \"14\", height: \"20\", x: \"5\", y: \"2\", rx: \"2\", ry: \"2\", key: \"1yt0o3\" }],\n [\"path\", { d: \"M12 18h.01\", key: \"mhygvu\" }]\n]);\n\nexport { Smartphone as default };\n//# sourceMappingURL=smartphone.js.map\n","/**\n * /settings/mobile — admin generates a QR an operator scans on a\n * phone to land directly inside /m/chat (v1.2.129).\n *\n * Flow:\n * 1. Click \"Generate QR\" → POST /api/mobile/qr → fresh role=user\n * token + QR PNG (data URL).\n * 2. Render QR, the embedded URL, and the token id.\n * 3. Phone scans → /m/login auto-submits the token cookie → /m/chat.\n *\n * Revoke: the link points the admin at /settings/security/tokens\n * where every token can be killed (the same UI works for the QR\n * tokens because they're stored in the same table with a\n * mobile-via-qr-* label).\n */\n\nimport { useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useMutation } from '@tanstack/react-query'\nimport { toast } from 'sonner'\nimport {\n Copy, Eye, EyeOff, Loader2, QrCode, RefreshCcw, ShieldAlert, Smartphone,\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 { api } from '@/lib/api/endpoints'\nimport type { MobileQRResponse } from '@/types/api'\n\nexport default function SettingsMobileRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const [result, setResult] = useState<MobileQRResponse | null>(null)\n const [showUrl, setShowUrl] = useState(false)\n const [host, setHost] = useState('')\n\n const generate = useMutation<MobileQRResponse, Error>({\n mutationFn: () =>\n api.generateMobileQR(host.trim() ? { host: host.trim() } : undefined),\n onSuccess: (r) => {\n setResult(r)\n setShowUrl(false)\n toast.success(t('mobile.generatedToast'))\n },\n onError: (e) => toast.error(e.message),\n })\n\n async function copyUrl(): Promise<void> {\n if (!result) return\n try {\n await navigator.clipboard.writeText(result.loginUrl)\n toast.success(t('mobile.copied'))\n } catch {\n toast.error(t('mobile.copyFailed'))\n }\n }\n\n return (\n <div className=\"mx-auto flex max-w-4xl flex-col gap-6\">\n <header className=\"flex items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('mobile.title')}</h1>\n </header>\n <p className=\"text-sm text-text-dim\">{t('mobile.subtitle')}</p>\n\n <section className=\"rounded-md border border-border bg-surface p-4\">\n <div className=\"flex items-center gap-2\">\n <Smartphone className=\"h-4 w-4 text-text-dim\" />\n <h2 className=\"text-sm font-semibold\">{t('mobile.generateCard')}</h2>\n </div>\n <p className=\"mt-1 text-xs text-text-dim\">{t('mobile.generateDesc')}</p>\n\n <div className=\"mt-4 flex flex-col gap-2\">\n <Label className=\"text-xs font-medium\">{t('mobile.hostLabel')}</Label>\n <Input\n value={host}\n onChange={(e) => setHost(e.target.value)}\n placeholder={t('mobile.hostPlaceholder', { defaultValue: 'auto-detect (leave blank)' })}\n className=\"font-mono text-xs\"\n />\n <p className=\"text-[11px] text-text-dim\">{t('mobile.hostHint')}</p>\n </div>\n\n <div className=\"mt-4 flex items-center gap-2\">\n <Button\n onClick={() => generate.mutate()}\n disabled={generate.isPending}\n size=\"sm\"\n >\n {generate.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : result ? <RefreshCcw className=\"h-4 w-4\" /> : <QrCode className=\"h-4 w-4\" />}\n <span className=\"ml-1\">\n {result ? t('mobile.regenerate') : t('mobile.generate')}\n </span>\n </Button>\n {generate.isPending && (\n <Badge variant=\"info\">{t('mobile.generating')}</Badge>\n )}\n </div>\n </section>\n\n {result && (\n <section className=\"rounded-md border border-border bg-surface p-4\">\n <div className=\"flex items-center gap-2\">\n <QrCode className=\"h-4 w-4 text-text-dim\" />\n <h2 className=\"text-sm font-semibold\">{t('mobile.scanCard')}</h2>\n <Badge variant=\"success\" className=\"ml-auto\">\n {t('mobile.tokenLabel')}: <span className=\"ml-1 font-mono\">{result.label}</span>\n </Badge>\n </div>\n <p className=\"mt-1 text-xs text-text-dim\">{t('mobile.scanDesc')}</p>\n\n <div className=\"mt-4 flex flex-col items-center gap-3 sm:flex-row sm:items-start\">\n <div className=\"shrink-0 rounded-md border border-border bg-white p-2\">\n <img\n src={result.qrDataUrl}\n alt={t('mobile.qrAlt', { defaultValue: 'QR code for mobile chat' })}\n width={280}\n height={280}\n className=\"block h-[280px] w-[280px]\"\n />\n </div>\n <div className=\"flex w-full flex-col gap-3\">\n <div>\n <Label className=\"text-xs font-medium\">{t('mobile.urlLabel')}</Label>\n <div className=\"mt-1 flex items-center gap-2\">\n <Input\n type={showUrl ? 'text' : 'password'}\n readOnly\n value={result.loginUrl}\n className=\"font-mono text-[11px]\"\n />\n <Button\n size=\"sm\" variant=\"ghost\"\n onClick={() => setShowUrl((v) => !v)}\n aria-label={showUrl\n ? t('mobile.hideUrl', { defaultValue: 'Hide URL' })\n : t('mobile.showUrl', { defaultValue: 'Show URL' })}\n >\n {showUrl ? <EyeOff className=\"h-4 w-4\" /> : <Eye className=\"h-4 w-4\" />}\n </Button>\n <Button\n size=\"sm\" variant=\"ghost\"\n onClick={() => void copyUrl()}\n aria-label={t('mobile.copyUrl', { defaultValue: 'Copy URL' })}\n >\n <Copy className=\"h-4 w-4\" />\n </Button>\n </div>\n <p className=\"mt-1 text-[11px] text-text-dim\">{t('mobile.urlHint')}</p>\n </div>\n <div>\n <Label className=\"text-xs font-medium\">{t('mobile.tokenIdLabel')}</Label>\n <div className=\"mt-1 font-mono text-xs\">{result.tokenId}</div>\n <p className=\"mt-1 text-[11px] text-text-dim\">{t('mobile.tokenIdHint')}</p>\n </div>\n </div>\n </div>\n\n <div className=\"mt-4 flex items-start gap-2 rounded-md border border-warning/40 bg-warning/5 p-3\">\n <ShieldAlert className=\"mt-0.5 h-4 w-4 shrink-0 text-warning\" />\n <div className=\"text-xs\">\n <div className=\"font-medium\">{t('mobile.warningTitle')}</div>\n <p className=\"mt-1 text-text-dim\">{t('mobile.warningBody')}</p>\n <a\n href={result.revokeHint}\n className=\"mt-1 inline-block underline text-accent\"\n >\n {t('mobile.revokeLink')}\n </a>\n </div>\n </div>\n </section>\n )}\n </div>\n )\n}\n"],"names":["Smartphone","createLucideIcon","SettingsMobileRoute","t","useTranslation","result","setResult","useState","showUrl","setShowUrl","host","setHost","generate","useMutation","api","r","toast","e","copyUrl","jsxs","jsx","Label","Input","Button","Loader2","RefreshCcw","QrCode","Badge","v","EyeOff","Eye","Copy","ShieldAlert"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{h as e}from"./index-DCfdN5R7.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 h=e("Network",[["rect",{x:"16",y:"16",width:"6",height:"6",rx:"1",key:"4q2zg0"}],["rect",{x:"2",y:"16",width:"6",height:"6",rx:"1",key:"8cvhb9"}],["rect",{x:"9",y:"2",width:"6",height:"6",rx:"1",key:"1egb70"}],["path",{d:"M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3",key:"1jsf9p"}],["path",{d:"M12 12V8",key:"2874zd"}]]);export{h as N};
|
|
7
|
-
//# sourceMappingURL=network
|
|
7
|
+
//# sourceMappingURL=network-BUeWK3bs.js.map
|