agim-cli 1.2.43 → 1.2.44

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.
Files changed (132) hide show
  1. package/dist/web/public/assets/{a2a-Dvz7ig4m.js → a2a-Bg_mT0z1.js} +2 -2
  2. package/dist/web/public/assets/{a2a-Dvz7ig4m.js.map → a2a-Bg_mT0z1.js.map} +1 -1
  3. package/dist/web/public/assets/{activity-BJqk7b-v.js → activity-U9AaNlDt.js} +2 -2
  4. package/dist/web/public/assets/{activity-BJqk7b-v.js.map → activity-U9AaNlDt.js.map} +1 -1
  5. package/dist/web/public/assets/{admins-DeiNQcMh.js → admins-BTC_YEK9.js} +2 -2
  6. package/dist/web/public/assets/{admins-DeiNQcMh.js.map → admins-BTC_YEK9.js.map} +1 -1
  7. package/dist/web/public/assets/{agents-DJGdXKLv.js → agents-o9odac79.js} +2 -2
  8. package/dist/web/public/assets/{agents-DJGdXKLv.js.map → agents-o9odac79.js.map} +1 -1
  9. package/dist/web/public/assets/{approvals-BOJ9et5G.js → approvals-Boj7iXz4.js} +2 -2
  10. package/dist/web/public/assets/{approvals-BOJ9et5G.js.map → approvals-Boj7iXz4.js.map} +1 -1
  11. package/dist/web/public/assets/{audit-Dnnevx6v.js → audit-MprCFoy_.js} +2 -2
  12. package/dist/web/public/assets/{audit-Dnnevx6v.js.map → audit-MprCFoy_.js.map} +1 -1
  13. package/dist/web/public/assets/{bgjobs-BZAxNFpA.js → bgjobs-B6XvxURz.js} +2 -2
  14. package/dist/web/public/assets/{bgjobs-BZAxNFpA.js.map → bgjobs-B6XvxURz.js.map} +1 -1
  15. package/dist/web/public/assets/{brain-fC59o4ZL.js → brain-C5HejASN.js} +2 -2
  16. package/dist/web/public/assets/{brain-fC59o4ZL.js.map → brain-C5HejASN.js.map} +1 -1
  17. package/dist/web/public/assets/{briefcase-DJRv77W6.js → briefcase-DkCTxO1A.js} +2 -2
  18. package/dist/web/public/assets/{briefcase-DJRv77W6.js.map → briefcase-DkCTxO1A.js.map} +1 -1
  19. package/dist/web/public/assets/{chevron-right-DzyVDoQs.js → chevron-right-DEyrYFz4.js} +2 -2
  20. package/dist/web/public/assets/{chevron-right-DzyVDoQs.js.map → chevron-right-DEyrYFz4.js.map} +1 -1
  21. package/dist/web/public/assets/{circle-check-B7B_CkmJ.js → circle-check-bADFEXGw.js} +2 -2
  22. package/dist/web/public/assets/{circle-check-B7B_CkmJ.js.map → circle-check-bADFEXGw.js.map} +1 -1
  23. package/dist/web/public/assets/{circle-check-big-dmFsJv6U.js → circle-check-big-U4xrkHiS.js} +2 -2
  24. package/dist/web/public/assets/{circle-check-big-dmFsJv6U.js.map → circle-check-big-U4xrkHiS.js.map} +1 -1
  25. package/dist/web/public/assets/{circle-x-epC-av6L.js → circle-x-C6qY5UUl.js} +2 -2
  26. package/dist/web/public/assets/{circle-x-epC-av6L.js.map → circle-x-C6qY5UUl.js.map} +1 -1
  27. package/dist/web/public/assets/{confirm-dialog-BEzhDlk7.js → confirm-dialog-B53cbWzX.js} +2 -2
  28. package/dist/web/public/assets/{confirm-dialog-BEzhDlk7.js.map → confirm-dialog-B53cbWzX.js.map} +1 -1
  29. package/dist/web/public/assets/{data-table-B_BxQrSj.js → data-table-BKTemkw9.js} +2 -2
  30. package/dist/web/public/assets/{data-table-B_BxQrSj.js.map → data-table-BKTemkw9.js.map} +1 -1
  31. package/dist/web/public/assets/{dialog-BAZNQtMt.js → dialog-Cevi7KvQ.js} +2 -2
  32. package/dist/web/public/assets/{dialog-BAZNQtMt.js.map → dialog-Cevi7KvQ.js.map} +1 -1
  33. package/dist/web/public/assets/{download-C08F-eA4.js → download-DwJNwdwV.js} +2 -2
  34. package/dist/web/public/assets/{download-C08F-eA4.js.map → download-DwJNwdwV.js.map} +1 -1
  35. package/dist/web/public/assets/{email-qzOnhITw.js → email-CZVaRhG_.js} +2 -2
  36. package/dist/web/public/assets/{email-qzOnhITw.js.map → email-CZVaRhG_.js.map} +1 -1
  37. package/dist/web/public/assets/{empty-state-BKs1qKHx.js → empty-state-C87S9Wor.js} +2 -2
  38. package/dist/web/public/assets/{empty-state-BKs1qKHx.js.map → empty-state-C87S9Wor.js.map} +1 -1
  39. package/dist/web/public/assets/{external-link-HML--jya.js → external-link-CIM1wjHP.js} +2 -2
  40. package/dist/web/public/assets/{external-link-HML--jya.js.map → external-link-CIM1wjHP.js.map} +1 -1
  41. package/dist/web/public/assets/{eye-C20O3zvh.js → eye-TUAOhz72.js} +2 -2
  42. package/dist/web/public/assets/{eye-C20O3zvh.js.map → eye-TUAOhz72.js.map} +1 -1
  43. package/dist/web/public/assets/{facts-B7VlqoVs.js → facts-ByM1VHCp.js} +2 -2
  44. package/dist/web/public/assets/{facts-B7VlqoVs.js.map → facts-ByM1VHCp.js.map} +1 -1
  45. package/dist/web/public/assets/{health-IF_VcgWW.js → health-B4GF06J-.js} +2 -2
  46. package/dist/web/public/assets/{health-IF_VcgWW.js.map → health-B4GF06J-.js.map} +1 -1
  47. package/dist/web/public/assets/{hot-D-aKQ8y2.js → hot-O9Z19xXa.js} +2 -2
  48. package/dist/web/public/assets/{hot-D-aKQ8y2.js.map → hot-O9Z19xXa.js.map} +1 -1
  49. package/dist/web/public/assets/{index-B48azMO-.js → index-CITyis5g.js} +4 -4
  50. package/dist/web/public/assets/{index-B48azMO-.js.map → index-CITyis5g.js.map} +1 -1
  51. package/dist/web/public/assets/{installed-CkiQRc89.js → installed-CM34mlDU.js} +2 -2
  52. package/dist/web/public/assets/{installed-CkiQRc89.js.map → installed-CM34mlDU.js.map} +1 -1
  53. package/dist/web/public/assets/{jobs-g1Wl8_zd.js → jobs-DwA9Ip87.js} +2 -2
  54. package/dist/web/public/assets/{jobs-g1Wl8_zd.js.map → jobs-DwA9Ip87.js.map} +1 -1
  55. package/dist/web/public/assets/{layout-D_CUXsIR.js → layout-BxrFilDN.js} +2 -2
  56. package/dist/web/public/assets/{layout-D_CUXsIR.js.map → layout-BxrFilDN.js.map} +1 -1
  57. package/dist/web/public/assets/{layout-ChcpcCB8.js → layout-CR5gLapT.js} +2 -2
  58. package/dist/web/public/assets/{layout-ChcpcCB8.js.map → layout-CR5gLapT.js.map} +1 -1
  59. package/dist/web/public/assets/{layout-CjLzz--E.js → layout-CcJQxFci.js} +2 -2
  60. package/dist/web/public/assets/{layout-CjLzz--E.js.map → layout-CcJQxFci.js.map} +1 -1
  61. package/dist/web/public/assets/{layout-CS9s-Q0a.js → layout-DRRveTaR.js} +2 -2
  62. package/dist/web/public/assets/{layout-CS9s-Q0a.js.map → layout-DRRveTaR.js.map} +1 -1
  63. package/dist/web/public/assets/{layout-fTZD9lJN.js → layout-zotlJ5fW.js} +2 -2
  64. package/dist/web/public/assets/{layout-fTZD9lJN.js.map → layout-zotlJ5fW.js.map} +1 -1
  65. package/dist/web/public/assets/{loader-circle-DBf4xFjo.js → loader-circle-BFp6Oc8_.js} +2 -2
  66. package/dist/web/public/assets/{loader-circle-DBf4xFjo.js.map → loader-circle-BFp6Oc8_.js.map} +1 -1
  67. package/dist/web/public/assets/{map-pin-BYR0Sf5r.js → map-pin-DPqnsBIG.js} +2 -2
  68. package/dist/web/public/assets/{map-pin-BYR0Sf5r.js.map → map-pin-DPqnsBIG.js.map} +1 -1
  69. package/dist/web/public/assets/{memos-ChfapnyG.js → memos-DCACQN26.js} +2 -2
  70. package/dist/web/public/assets/{memos-ChfapnyG.js.map → memos-DCACQN26.js.map} +1 -1
  71. package/dist/web/public/assets/{messengers-zBIYakPW.js → messengers-CwWP1qI4.js} +2 -2
  72. package/dist/web/public/assets/{messengers-zBIYakPW.js.map → messengers-CwWP1qI4.js.map} +1 -1
  73. package/dist/web/public/assets/{network-CEqTiog6.js → network-CrMEVz4-.js} +2 -2
  74. package/dist/web/public/assets/{network-CEqTiog6.js.map → network-CrMEVz4-.js.map} +1 -1
  75. package/dist/web/public/assets/{outbox-D4IQcACJ.js → outbox-C7FpZzwS.js} +2 -2
  76. package/dist/web/public/assets/{outbox-D4IQcACJ.js.map → outbox-C7FpZzwS.js.map} +1 -1
  77. package/dist/web/public/assets/{pagination-R9mql8VB.js → pagination-Cgt8W6EX.js} +2 -2
  78. package/dist/web/public/assets/{pagination-R9mql8VB.js.map → pagination-Cgt8W6EX.js.map} +1 -1
  79. package/dist/web/public/assets/{persona-Cj_C5frK.js → persona-Bjty6uqM.js} +2 -2
  80. package/dist/web/public/assets/{persona-Cj_C5frK.js.map → persona-Bjty6uqM.js.map} +1 -1
  81. package/dist/web/public/assets/{play-CTWqoMcj.js → play-CEoS1N8t.js} +2 -2
  82. package/dist/web/public/assets/{play-CTWqoMcj.js.map → play-CEoS1N8t.js.map} +1 -1
  83. package/dist/web/public/assets/{policy-BKEZ2ziu.js → policy-DwI-ov9J.js} +2 -2
  84. package/dist/web/public/assets/{policy-BKEZ2ziu.js.map → policy-DwI-ov9J.js.map} +1 -1
  85. package/dist/web/public/assets/{refresh-ccw-Clj5sQNF.js → refresh-ccw-CPSYEbgh.js} +2 -2
  86. package/dist/web/public/assets/{refresh-ccw-Clj5sQNF.js.map → refresh-ccw-CPSYEbgh.js.map} +1 -1
  87. package/dist/web/public/assets/{reminders-C5bVkLgj.js → reminders-X-QFSWvZ.js} +2 -2
  88. package/dist/web/public/assets/{reminders-C5bVkLgj.js.map → reminders-X-QFSWvZ.js.map} +1 -1
  89. package/dist/web/public/assets/{save-CAFra1jb.js → save-tS3IBPf3.js} +2 -2
  90. package/dist/web/public/assets/{save-CAFra1jb.js.map → save-tS3IBPf3.js.map} +1 -1
  91. package/dist/web/public/assets/{schedules-KQCD7978.js → schedules-CfCNvhCV.js} +2 -2
  92. package/dist/web/public/assets/{schedules-KQCD7978.js.map → schedules-CfCNvhCV.js.map} +1 -1
  93. package/dist/web/public/assets/{search-bDqizeZv.js → search-BPvPCccn.js} +2 -2
  94. package/dist/web/public/assets/{search-bDqizeZv.js.map → search-BPvPCccn.js.map} +1 -1
  95. package/dist/web/public/assets/{service-DTeMmX2u.js → service-DSitDFzD.js} +2 -2
  96. package/dist/web/public/assets/{service-DTeMmX2u.js.map → service-DSitDFzD.js.map} +1 -1
  97. package/dist/web/public/assets/{status-badge-_3Ve0Jef.js → status-badge-HSHkhdur.js} +2 -2
  98. package/dist/web/public/assets/{status-badge-_3Ve0Jef.js.map → status-badge-HSHkhdur.js.map} +1 -1
  99. package/dist/web/public/assets/{subtasks-DROeZcfT.js → subtasks-eKq_P0v6.js} +2 -2
  100. package/dist/web/public/assets/{subtasks-DROeZcfT.js.map → subtasks-eKq_P0v6.js.map} +1 -1
  101. package/dist/web/public/assets/{table-CZwKizat.js → table-BBISYTH-.js} +2 -2
  102. package/dist/web/public/assets/{table-CZwKizat.js.map → table-BBISYTH-.js.map} +1 -1
  103. package/dist/web/public/assets/{topn-DpErN6N8.js → topn-JA8llaUI.js} +2 -2
  104. package/dist/web/public/assets/{topn-DpErN6N8.js.map → topn-JA8llaUI.js.map} +1 -1
  105. package/dist/web/public/assets/{trash-2-BkZrVFdH.js → trash-2-D8F96aYm.js} +2 -2
  106. package/dist/web/public/assets/{trash-2-BkZrVFdH.js.map → trash-2-D8F96aYm.js.map} +1 -1
  107. package/dist/web/public/assets/{use-memory-CElm89Hg.js → use-memory-BDa1R8Tf.js} +2 -2
  108. package/dist/web/public/assets/{use-memory-CElm89Hg.js.map → use-memory-BDa1R8Tf.js.map} +1 -1
  109. package/dist/web/public/assets/{use-observability-D8qHfj0S.js → use-observability-XgxLMQsY.js} +2 -2
  110. package/dist/web/public/assets/{use-observability-D8qHfj0S.js.map → use-observability-XgxLMQsY.js.map} +1 -1
  111. package/dist/web/public/assets/{use-settings-DgU8YmGj.js → use-settings-Bc4s-JUD.js} +2 -2
  112. package/dist/web/public/assets/{use-settings-DgU8YmGj.js.map → use-settings-Bc4s-JUD.js.map} +1 -1
  113. package/dist/web/public/assets/{use-skills-Cp_ok0Uq.js → use-skills-DCOYAQ8s.js} +2 -2
  114. package/dist/web/public/assets/{use-skills-Cp_ok0Uq.js.map → use-skills-DCOYAQ8s.js.map} +1 -1
  115. package/dist/web/public/assets/{use-workspace-Dc6rNi5d.js → use-workspace-JalfqH6H.js} +2 -2
  116. package/dist/web/public/assets/{use-workspace-Dc6rNi5d.js.map → use-workspace-JalfqH6H.js.map} +1 -1
  117. package/dist/web/public/assets/{useQuery-BjFqOBV3.js → useQuery-DFryK9Pn.js} +2 -2
  118. package/dist/web/public/assets/{useQuery-BjFqOBV3.js.map → useQuery-DFryK9Pn.js.map} +1 -1
  119. package/dist/web/public/assets/{vector-Bb3l7TOa.js → vector-G2dN_aut.js} +2 -2
  120. package/dist/web/public/assets/{vector-Bb3l7TOa.js.map → vector-G2dN_aut.js.map} +1 -1
  121. package/dist/web/public/assets/viewer-DliYQkQQ.js +12 -0
  122. package/dist/web/public/assets/viewer-DliYQkQQ.js.map +1 -0
  123. package/dist/web/public/assets/{workspace-Du8va-tD.js → workspace-BaLZIgGn.js} +2 -2
  124. package/dist/web/public/assets/{workspace-Du8va-tD.js.map → workspace-BaLZIgGn.js.map} +1 -1
  125. package/dist/web/public/assets/{workspaces-BjgDtEnF.js → workspaces-cX_rV523.js} +2 -2
  126. package/dist/web/public/assets/{workspaces-BjgDtEnF.js.map → workspaces-cX_rV523.js.map} +1 -1
  127. package/dist/web/public/assets/{x-CHe1y-sG.js → x-D5196-9X.js} +2 -2
  128. package/dist/web/public/assets/{x-CHe1y-sG.js.map → x-D5196-9X.js.map} +1 -1
  129. package/dist/web/public/index.html +1 -1
  130. package/package.json +1 -1
  131. package/dist/web/public/assets/viewer-BeyW50lw.js +0 -12
  132. package/dist/web/public/assets/viewer-BeyW50lw.js.map +0 -1
@@ -1,7 +1,7 @@
1
- import{x as A,ac as w,Q as e,c as f,B as F,a2 as y,z as q,L as P,I as C}from"./index-B48azMO-.js";import{e as p}from"./react-C9F3QeMB.js";import{D,a as R,d as E,e as Q,b as $}from"./dialog-BAZNQtMt.js";import{b as M,m as z,i as O,q as B}from"./use-settings-DgU8YmGj.js";import{L as S}from"./loader-circle-DBf4xFjo.js";import{R as L}from"./refresh-ccw-Clj5sQNF.js";import{X as T}from"./x-CHe1y-sG.js";import{S as H}from"./save-CAFra1jb.js";import"./useQuery-BjFqOBV3.js";/**
1
+ import{x as A,ac as w,Q as e,c as f,B as F,a2 as y,z as q,L as P,I as C}from"./index-CITyis5g.js";import{e as p}from"./react-C9F3QeMB.js";import{D,a as R,d as E,e as Q,b as $}from"./dialog-Cevi7KvQ.js";import{b as M,m as z,i as O,q as B}from"./use-settings-Bc4s-JUD.js";import{L as S}from"./loader-circle-BFp6Oc8_.js";import{R as L}from"./refresh-ccw-CPSYEbgh.js";import{X as T}from"./x-D5196-9X.js";import{S as H}from"./save-tS3IBPf3.js";import"./useQuery-DFryK9Pn.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 W=A("QrCode",[["rect",{width:"5",height:"5",x:"3",y:"3",rx:"1",key:"1tu5fj"}],["rect",{width:"5",height:"5",x:"16",y:"3",rx:"1",key:"1v8r4q"}],["rect",{width:"5",height:"5",x:"3",y:"16",rx:"1",key:"1x03jg"}],["path",{d:"M21 16h-3a2 2 0 0 0-2 2v3",key:"177gqh"}],["path",{d:"M21 21v.01",key:"ents32"}],["path",{d:"M12 7v3a2 2 0 0 1-2 2H7",key:"8crl2c"}],["path",{d:"M3 12h.01",key:"nlz23k"}],["path",{d:"M12 3h.01",key:"n36tog"}],["path",{d:"M12 16v.01",key:"133mhm"}],["path",{d:"M16 12h1",key:"1slzba"}],["path",{d:"M21 12v.01",key:"1lwtk9"}],["path",{d:"M12 21v-1",key:"1880an"}]]);function N(s){const i=new Set(s?.messengers??[]);return{"wechat-ilink":{enabled:i.has("wechat-ilink")},telegram:{enabled:i.has("telegram"),telegram:{...s?.telegram??{}}},feishu:{enabled:i.has("feishu"),feishu:{...s?.feishu??{}}},dingtalk:{enabled:i.has("dingtalk"),dingtalk:{...s?.dingtalk??{}}},discord:{enabled:i.has("discord"),discord:{...s?.discord??{}}}}}function J(s,i){const t=[];for(const a of Object.keys(s))s[a].enabled&&t.push(a);return{messengers:t,telegram:s.telegram.telegram,feishu:s.feishu.feishu,dingtalk:s.dingtalk.dingtalk,discord:s.discord.discord,...Object.fromEntries(Object.entries(i).filter(([a])=>!["messengers","telegram","feishu","dingtalk","discord"].includes(a)))}}function le(){const{t:s}=w(["settings","common"]),i=M(),t=z(),[a,c]=p.useState(()=>N(i.data)),[g,h]=p.useState(!1);p.useEffect(()=>{g||i.data&&(c(N(i.data)),h(!0))},[i.data,g]);const m=i.data,n=p.useMemo(()=>m?JSON.stringify(N(m))!==JSON.stringify(a):!1,[m,a]),[r,o]=p.useState(!1);function d(l,j){c(I=>({...I,[l]:{...I[l],...j}}))}async function x(){if(m)try{await t.mutateAsync(J(a,m)),y.success(s("messengers.savedToast")),h(!1)}catch(l){y.error(q(l,s).message)}}function b(){m&&c(N(m))}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(f,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>i.refetch(),disabled:i.isFetching,"aria-label":s("actions.refresh",{ns:"common"}),children:[i.isFetching?e.jsx(S,{className:"h-4 w-4 animate-spin"}):e.jsx(L,{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")})]}),e.jsx("div",{className:"flex flex-wrap items-center gap-2",children:n?e.jsxs(e.Fragment,{children:[e.jsx(F,{variant:"info",children:s("messengers.dirtyHint")}),e.jsxs(f,{type:"button",variant:"secondary",size:"sm",onClick:b,disabled:t.isPending,children:[e.jsx(T,{className:"h-4 w-4"}),s("messengers.discardAll")]}),e.jsxs(f,{type:"button",size:"sm",onClick:()=>void x(),disabled:t.isPending,children:[t.isPending?e.jsx(S,{className:"h-4 w-4 animate-spin"}):e.jsx(H,{className:"h-4 w-4"}),t.isPending?s("messengers.saving"):s("messengers.saveAll")]})]}):e.jsx("span",{className:"text-xs text-text-muted",children:s("env.noChanges")})}),i.isLoading?e.jsx("div",{className:"h-96 rounded-md bg-surface-2 animate-pulse"}):m?e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx(v,{slot:"wechat-ilink",label:s("messengers.platform.wechat"),hint:s("messengers.hint.wechat"),enabled:a["wechat-ilink"].enabled,onToggle:l=>d("wechat-ilink",{enabled:l}),children:e.jsxs(f,{type:"button",variant:"secondary",size:"sm",onClick:()=>o(!0),children:[e.jsx(W,{className:"h-4 w-4"}),s("messengers.scanQr")]})}),m.features?.globalIm?e.jsxs(v,{slot:"telegram",label:s("messengers.platform.telegram"),hint:s("messengers.hint.telegram"),enabled:a.telegram.enabled,onToggle:l=>d("telegram",{enabled:l}),children:[e.jsx(u,{id:"tg-token",label:s("messengers.fields.botToken"),value:a.telegram.telegram?.botToken??"",type:"password",onChange:l=>d("telegram",{telegram:{...a.telegram.telegram,botToken:l}})}),e.jsx(u,{id:"tg-channel",label:s("messengers.fields.channelId"),value:a.telegram.telegram?.channelId??"",onChange:l=>d("telegram",{telegram:{...a.telegram.telegram,channelId:l}})})]}):null,e.jsxs(v,{slot:"feishu",label:s("messengers.platform.feishu"),hint:s("messengers.hint.feishu"),enabled:a.feishu.enabled,onToggle:l=>d("feishu",{enabled:l}),children:[e.jsx(u,{id:"fs-appid",label:s("messengers.fields.appId"),value:a.feishu.feishu?.appId??"",onChange:l=>d("feishu",{feishu:{...a.feishu.feishu,appId:l}})}),e.jsx(u,{id:"fs-secret",label:s("messengers.fields.appSecret"),value:a.feishu.feishu?.appSecret??"",type:"password",onChange:l=>d("feishu",{feishu:{...a.feishu.feishu,appSecret:l}})}),e.jsx(u,{id:"fs-channel",label:s("messengers.fields.channelId"),value:a.feishu.feishu?.channelId??"",onChange:l=>d("feishu",{feishu:{...a.feishu.feishu,channelId:l}})})]}),e.jsxs(v,{slot:"dingtalk",label:s("messengers.platform.dingtalk"),hint:s("messengers.hint.dingtalk"),enabled:a.dingtalk.enabled,onToggle:l=>d("dingtalk",{enabled:l}),children:[e.jsx(u,{id:"dt-cid",label:s("messengers.fields.clientId"),value:a.dingtalk.dingtalk?.clientId??"",onChange:l=>d("dingtalk",{dingtalk:{...a.dingtalk.dingtalk,clientId:l}})}),e.jsx(u,{id:"dt-secret",label:s("messengers.fields.clientSecret"),value:a.dingtalk.dingtalk?.clientSecret??"",type:"password",onChange:l=>d("dingtalk",{dingtalk:{...a.dingtalk.dingtalk,clientSecret:l}})}),e.jsx(u,{id:"dt-channel",label:s("messengers.fields.channelId"),value:a.dingtalk.dingtalk?.channelId??"",onChange:l=>d("dingtalk",{dingtalk:{...a.dingtalk.dingtalk,channelId:l}})}),e.jsx(k,{id:"dt-dm-policy",label:s("messengers.dingtalk.dmPolicy"),value:a.dingtalk.dingtalk?.dmPolicy??"open",onChange:l=>d("dingtalk",{dingtalk:{...a.dingtalk.dingtalk,dmPolicy:l}}),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(k,{id:"dt-group-policy",label:s("messengers.dingtalk.groupPolicy"),value:a.dingtalk.dingtalk?.groupPolicy??"open",onChange:l=>d("dingtalk",{dingtalk:{...a.dingtalk.dingtalk,groupPolicy:l}}),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:(a.dingtalk.dingtalk?.allowFrom??[]).join(","),onChange:l=>d("dingtalk",{dingtalk:{...a.dingtalk.dingtalk,allowFrom:l.split(",").map(j=>j.trim()).filter(Boolean)}})}),e.jsx(u,{id:"dt-group-allow-from",label:s("messengers.dingtalk.groupAllowFrom"),value:(a.dingtalk.dingtalk?.groupAllowFrom??[]).join(","),onChange:l=>d("dingtalk",{dingtalk:{...a.dingtalk.dingtalk,groupAllowFrom:l.split(",").map(j=>j.trim()).filter(Boolean)}})}),e.jsx(k,{id:"dt-ack",label:s("messengers.dingtalk.ackReaction"),value:a.dingtalk.dingtalk?.ackReaction??"off",onChange:l=>d("dingtalk",{dingtalk:{...a.dingtalk.dingtalk,ackReaction:l}}),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(U,{accounts:a.dingtalk.dingtalk?.accounts??{},onChange:l=>d("dingtalk",{dingtalk:{...a.dingtalk.dingtalk,accounts:l}})})]}),m.features?.globalIm?e.jsxs(v,{slot:"discord",label:s("messengers.platform.discord"),hint:s("messengers.hint.discord"),enabled:a.discord.enabled,onToggle:l=>d("discord",{enabled:l}),children:[e.jsx(u,{id:"dc-token",label:s("messengers.fields.botToken"),value:a.discord.discord?.botToken??"",type:"password",onChange:l=>d("discord",{discord:{...a.discord.discord,botToken:l}})}),e.jsx(u,{id:"dc-channel",label:s("messengers.fields.channelId"),value:a.discord.discord?.channelId??"",onChange:l=>d("discord",{discord:{...a.discord.discord,channelId:l}})})]}):null]}):null,e.jsx(_,{open:r,onOpenChange:o,onConfirmed:()=>{i.refetch(),h(!1)}})]})}function v({label:s,hint:i,enabled:t,onToggle:a,children:c}){const{t:g}=w("settings");return e.jsxs("div",{className:"rounded-md border border-border bg-surface p-4",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:s}),e.jsx(F,{variant:t?"success":"outline",children:g(t?"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:t,onChange:h=>a(h.target.checked),className:"h-4 w-4 accent-accent cursor-pointer"})})]}),t&&c&&e.jsx("div",{className:"mt-3 flex flex-col gap-2",children:c})]})}function u({id:s,label:i,value:t,onChange:a,type:c="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(P,{htmlFor:s,className:"text-xs text-text-dim",children:i}),e.jsx(C,{id:s,type:c,value:t,onChange:g=>a(g.target.value),autoComplete:"off",className:"font-mono text-xs"})]})}function k({id:s,label:i,value:t,onChange:a,options:c}){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(P,{htmlFor:s,className:"text-xs text-text-dim",children:i}),e.jsx("select",{id:s,value:t,onChange:g=>a(g.target.value),className:"rounded-md border border-input bg-background px-2 py-1 text-xs",children:c.map(g=>e.jsx("option",{value:g.value,children:g.label},g.value))})]})}function _({open:s,onOpenChange:i,onConfirmed:t}){const{t:a}=w(["settings","common"]),c=O(),[g,h]=p.useState(null),[m,n]=p.useState(null),[r,o]=p.useState(null);p.useEffect(()=>{if(!s){h(null),n(null),o(null);return}let b=!0;return c.mutateAsync().then(l=>{b&&(n(l.qrImage),h(l.qrToken))}).catch(l=>{b&&o(l instanceof Error?l.message:String(l))}),()=>{b=!1}},[s]);const x=B(s?g:null).data?.status;return p.useEffect(()=>{x==="confirmed"&&(y.success(a("messengers.qr.confirmed")),t(),i(!1)),x==="expired"&&y.error(a("messengers.qr.expired"))},[x]),e.jsx(D,{open:s,onOpenChange:i,children:e.jsxs(R,{children:[e.jsxs(E,{children:[e.jsx(Q,{children:a("messengers.qr.title")}),e.jsx($,{children:a("messengers.qr.description")})]}),e.jsx("div",{className:"flex flex-col items-center gap-3",children:c.isPending&&!m?e.jsxs(e.Fragment,{children:[e.jsx(S,{className:"h-8 w-8 animate-spin text-text-dim"}),e.jsx("p",{className:"text-sm text-text-dim",children:a("messengers.qr.starting")})]}):r?e.jsxs("p",{className:"text-sm text-danger",children:[a("messengers.qr.loadFailed"),": ",r]}):m?e.jsxs(e.Fragment,{children:[e.jsx("img",{src:m,alt:a("messengers.qr.title"),className:"rounded-md border border-border"}),x==="expired"?e.jsx("p",{className:"text-xs text-danger",children:a("messengers.qr.expired")}):e.jsx("p",{className:"text-xs text-text-dim",children:x?`· ${x} ·`:""})]}):null})]})})}function U({accounts:s,onChange:i}){const{t}=w(["settings","common"]),a=Object.entries(s),c=(n,r)=>{i({...s,[n]:{...s[n],...r}})},g=n=>{const r={...s};delete r[n],i(r)},h=(n,r)=>{if(!r||r===n)return;if(s[r]){y.error(t("messengers.dingtalk.accountRenameCollision",{id:r}));return}const o={};for(const[d,x]of Object.entries(s))o[d===n?r:d]=x;i(o)},m=()=>{let n=a.length+1,r=`account-${n}`;for(;s[r];)n+=1,r=`account-${n}`;i({...s,[r]:{enabled:!0}})};return e.jsxs("div",{className:"mt-3 border-t border-input 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:t("messengers.dingtalk.accountsTitle")}),e.jsxs(f,{type:"button",size:"sm",variant:"outline",onClick:m,children:["+ ",t("messengers.dingtalk.addAccount")]})]}),a.length===0?e.jsx("div",{className:"text-xs text-text-dim italic",children:t("messengers.dingtalk.accountsEmpty")}):e.jsx("div",{className:"space-y-3",children:a.map(([n,r])=>e.jsxs("div",{className:"rounded-md border border-input p-2",children:[e.jsxs("div",{className:"mb-2 flex items-center gap-2",children:[e.jsx(C,{id:`acct-id-${n}`,defaultValue:n,onBlur:o=>h(n,o.target.value.trim()),className:"font-mono text-xs w-40",placeholder:"account-id"}),e.jsx(C,{id:`acct-name-${n}`,value:r.name??"",onChange:o=>c(n,{name:o.target.value}),className:"text-xs flex-1",placeholder:t("messengers.dingtalk.accountName")}),e.jsxs("label",{className:"flex items-center gap-1 text-xs",children:[e.jsx("input",{type:"checkbox",checked:r.enabled!==!1,onChange:o=>c(n,{enabled:o.target.checked})}),t("messengers.enabled")]}),e.jsx(f,{type:"button",size:"sm",variant:"ghost",onClick:()=>g(n),className:"text-danger",children:e.jsx(T,{className:"size-4"})})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(u,{id:`acct-cid-${n}`,label:t("messengers.fields.clientId"),value:r.clientId??"",onChange:o=>c(n,{clientId:o})}),e.jsx(u,{id:`acct-secret-${n}`,label:t("messengers.fields.clientSecret"),value:r.clientSecret??"",type:"password",onChange:o=>c(n,{clientSecret:o})}),e.jsx(k,{id:`acct-dm-${n}`,label:t("messengers.dingtalk.dmPolicy"),value:r.dmPolicy??"open",onChange:o=>c(n,{dmPolicy:o}),options:[{value:"open",label:t("messengers.dingtalk.policy.open")},{value:"pairing",label:t("messengers.dingtalk.policy.pairing")},{value:"allowlist",label:t("messengers.dingtalk.policy.allowlist")}]}),e.jsx(k,{id:`acct-group-${n}`,label:t("messengers.dingtalk.groupPolicy"),value:r.groupPolicy??"open",onChange:o=>c(n,{groupPolicy:o}),options:[{value:"open",label:t("messengers.dingtalk.policy.open")},{value:"allowlist",label:t("messengers.dingtalk.policy.allowlist")},{value:"disabled",label:t("messengers.dingtalk.policy.disabled")}]}),e.jsx(u,{id:`acct-allow-${n}`,label:t("messengers.dingtalk.allowFrom"),value:(r.allowFrom??[]).join(","),onChange:o=>c(n,{allowFrom:o.split(",").map(d=>d.trim()).filter(Boolean)})}),e.jsx(u,{id:`acct-gallow-${n}`,label:t("messengers.dingtalk.groupAllowFrom"),value:(r.groupAllowFrom??[]).join(","),onChange:o=>c(n,{groupAllowFrom:o.split(",").map(d=>d.trim()).filter(Boolean)})}),e.jsx(k,{id:`acct-ack-${n}`,label:t("messengers.dingtalk.ackReaction"),value:r.ackReaction??"off",onChange:o=>c(n,{ackReaction:o}),options:[{value:"off",label:t("messengers.dingtalk.ack.off")},{value:"emoji",label:t("messengers.dingtalk.ack.emoji")},{value:"kaomoji",label:t("messengers.dingtalk.ack.kaomoji")}]})]})]},n))}),e.jsx("div",{className:"mt-1 text-xs text-text-dim",children:t("messengers.dingtalk.accountsHint")})]})}export{le as default};
7
- //# sourceMappingURL=messengers-zBIYakPW.js.map
7
+ //# sourceMappingURL=messengers-CwWP1qI4.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"messengers-zBIYakPW.js","sources":["../../node_modules/lucide-react/dist/esm/icons/qr-code.js","../../src/routes/settings/messengers.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 QrCode = createLucideIcon(\"QrCode\", [\n [\"rect\", { width: \"5\", height: \"5\", x: \"3\", y: \"3\", rx: \"1\", key: \"1tu5fj\" }],\n [\"rect\", { width: \"5\", height: \"5\", x: \"16\", y: \"3\", rx: \"1\", key: \"1v8r4q\" }],\n [\"rect\", { width: \"5\", height: \"5\", x: \"3\", y: \"16\", rx: \"1\", key: \"1x03jg\" }],\n [\"path\", { d: \"M21 16h-3a2 2 0 0 0-2 2v3\", key: \"177gqh\" }],\n [\"path\", { d: \"M21 21v.01\", key: \"ents32\" }],\n [\"path\", { d: \"M12 7v3a2 2 0 0 1-2 2H7\", key: \"8crl2c\" }],\n [\"path\", { d: \"M3 12h.01\", key: \"nlz23k\" }],\n [\"path\", { d: \"M12 3h.01\", key: \"n36tog\" }],\n [\"path\", { d: \"M12 16v.01\", key: \"133mhm\" }],\n [\"path\", { d: \"M16 12h1\", key: \"1slzba\" }],\n [\"path\", { d: \"M21 12v.01\", key: \"1lwtk9\" }],\n [\"path\", { d: \"M12 21v-1\", key: \"1880an\" }]\n]);\n\nexport { QrCode as default };\n//# sourceMappingURL=qr-code.js.map\n","/**\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 { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Loader2, QrCode, RefreshCcw, Save, X } 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 useUpdateConfig,\n useStartWechatQr,\n useWechatQrStatus,\n} from '@/hooks/use-settings'\nimport { describeError } from '@/lib/api/errors'\nimport type { AppConfig } from '@/types/api'\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 return {\n messengers,\n telegram: draft.telegram.telegram,\n feishu: draft.feishu.feishu,\n dingtalk: draft.dingtalk.dingtalk,\n discord: draft.discord.discord,\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}\n\nexport default function SettingsMessengersRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const cfgQuery = useConfig()\n const updateCfg = useUpdateConfig()\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\n function patchSlot(slot: Slot, partial: Partial<PlatformDraft>): void {\n setDraft((prev) => ({ ...prev, [slot]: { ...prev[slot], ...partial } }))\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 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 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 {/* 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 {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 <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 >\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\n {cfg.features?.globalIm ? (\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 >\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 <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 >\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\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 >\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\n {cfg.features?.globalIm ? (\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 >\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={() => { void cfgQuery.refetch(); setSynced(false) }}\n />\n </div>\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}\n\nfunction PlatformCard({ label, hint, enabled, onToggle, children }: PlatformCardProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <div className=\"rounded-md border border-border bg-surface p-4\">\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\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-input bg-background px-2 py-1 text-xs\"\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-input 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-input 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":["QrCode","createLucideIcon","buildDraft","cfg","m","buildPatch","draft","messengers","k","SettingsMessengersRoute","t","useTranslation","cfgQuery","useConfig","updateCfg","useUpdateConfig","setDraft","useState","synced","setSynced","useEffect","isDirty","useMemo","qrOpen","setQrOpen","patchSlot","slot","partial","prev","onSave","toast","err","describeError","onDiscard","jsxs","jsx","Button","Loader2","RefreshCcw","Fragment","Badge","X","Save","PlatformCard","v","FieldRow","SelectRow","s","DingTalkAccountsEditor","next","WechatQrDialog","label","hint","enabled","onToggle","children","e","id","value","onChange","type","Label","Input","options","o","open","onOpenChange","onConfirmed","start","useStartWechatQr","token","setToken","qrImage","setQrImage","startError","setStartError","active","r","status","useWechatQrStatus","Dialog","DialogContent","DialogHeader","DialogTitle","DialogDescription","accounts","entries","updateAccount","patch","deleteAccount","renameAccount","oldId","newId","addAccount","candidate","acct"],"mappings":"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","x_google_ignoreList":[0]}
1
+ {"version":3,"file":"messengers-CwWP1qI4.js","sources":["../../node_modules/lucide-react/dist/esm/icons/qr-code.js","../../src/routes/settings/messengers.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 QrCode = createLucideIcon(\"QrCode\", [\n [\"rect\", { width: \"5\", height: \"5\", x: \"3\", y: \"3\", rx: \"1\", key: \"1tu5fj\" }],\n [\"rect\", { width: \"5\", height: \"5\", x: \"16\", y: \"3\", rx: \"1\", key: \"1v8r4q\" }],\n [\"rect\", { width: \"5\", height: \"5\", x: \"3\", y: \"16\", rx: \"1\", key: \"1x03jg\" }],\n [\"path\", { d: \"M21 16h-3a2 2 0 0 0-2 2v3\", key: \"177gqh\" }],\n [\"path\", { d: \"M21 21v.01\", key: \"ents32\" }],\n [\"path\", { d: \"M12 7v3a2 2 0 0 1-2 2H7\", key: \"8crl2c\" }],\n [\"path\", { d: \"M3 12h.01\", key: \"nlz23k\" }],\n [\"path\", { d: \"M12 3h.01\", key: \"n36tog\" }],\n [\"path\", { d: \"M12 16v.01\", key: \"133mhm\" }],\n [\"path\", { d: \"M16 12h1\", key: \"1slzba\" }],\n [\"path\", { d: \"M21 12v.01\", key: \"1lwtk9\" }],\n [\"path\", { d: \"M12 21v-1\", key: \"1880an\" }]\n]);\n\nexport { QrCode as default };\n//# sourceMappingURL=qr-code.js.map\n","/**\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 { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Loader2, QrCode, RefreshCcw, Save, X } 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 useUpdateConfig,\n useStartWechatQr,\n useWechatQrStatus,\n} from '@/hooks/use-settings'\nimport { describeError } from '@/lib/api/errors'\nimport type { AppConfig } from '@/types/api'\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 return {\n messengers,\n telegram: draft.telegram.telegram,\n feishu: draft.feishu.feishu,\n dingtalk: draft.dingtalk.dingtalk,\n discord: draft.discord.discord,\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}\n\nexport default function SettingsMessengersRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const cfgQuery = useConfig()\n const updateCfg = useUpdateConfig()\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\n function patchSlot(slot: Slot, partial: Partial<PlatformDraft>): void {\n setDraft((prev) => ({ ...prev, [slot]: { ...prev[slot], ...partial } }))\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 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 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 {/* 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 {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 <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 >\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\n {cfg.features?.globalIm ? (\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 >\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 <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 >\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\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 >\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\n {cfg.features?.globalIm ? (\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 >\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={() => { void cfgQuery.refetch(); setSynced(false) }}\n />\n </div>\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}\n\nfunction PlatformCard({ label, hint, enabled, onToggle, children }: PlatformCardProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <div className=\"rounded-md border border-border bg-surface p-4\">\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\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-input bg-background px-2 py-1 text-xs\"\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-input 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-input 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":["QrCode","createLucideIcon","buildDraft","cfg","m","buildPatch","draft","messengers","k","SettingsMessengersRoute","t","useTranslation","cfgQuery","useConfig","updateCfg","useUpdateConfig","setDraft","useState","synced","setSynced","useEffect","isDirty","useMemo","qrOpen","setQrOpen","patchSlot","slot","partial","prev","onSave","toast","err","describeError","onDiscard","jsxs","jsx","Button","Loader2","RefreshCcw","Fragment","Badge","X","Save","PlatformCard","v","FieldRow","SelectRow","s","DingTalkAccountsEditor","next","WechatQrDialog","label","hint","enabled","onToggle","children","e","id","value","onChange","type","Label","Input","options","o","open","onOpenChange","onConfirmed","start","useStartWechatQr","token","setToken","qrImage","setQrImage","startError","setStartError","active","r","status","useWechatQrStatus","Dialog","DialogContent","DialogHeader","DialogTitle","DialogDescription","accounts","entries","updateAccount","patch","deleteAccount","renameAccount","oldId","newId","addAccount","candidate","acct"],"mappings":"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","x_google_ignoreList":[0]}
@@ -1,7 +1,7 @@
1
- import{x as e}from"./index-B48azMO-.js";/**
1
+ import{x as e}from"./index-CITyis5g.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-CEqTiog6.js.map
7
+ //# sourceMappingURL=network-CrMEVz4-.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"network-CEqTiog6.js","sources":["../../node_modules/lucide-react/dist/esm/icons/network.js"],"sourcesContent":["/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Network = createLucideIcon(\"Network\", [\n [\"rect\", { x: \"16\", y: \"16\", width: \"6\", height: \"6\", rx: \"1\", key: \"4q2zg0\" }],\n [\"rect\", { x: \"2\", y: \"16\", width: \"6\", height: \"6\", rx: \"1\", key: \"8cvhb9\" }],\n [\"rect\", { x: \"9\", y: \"2\", width: \"6\", height: \"6\", rx: \"1\", key: \"1egb70\" }],\n [\"path\", { d: \"M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3\", key: \"1jsf9p\" }],\n [\"path\", { d: \"M12 12V8\", key: \"2874zd\" }]\n]);\n\nexport { Network as default };\n//# sourceMappingURL=network.js.map\n"],"names":["Network","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAUC,EAAiB,UAAW,CAC1C,CAAC,OAAQ,CAAE,EAAG,KAAM,EAAG,KAAM,MAAO,IAAK,OAAQ,IAAK,GAAI,IAAK,IAAK,QAAQ,CAAE,EAC9E,CAAC,OAAQ,CAAE,EAAG,IAAK,EAAG,KAAM,MAAO,IAAK,OAAQ,IAAK,GAAI,IAAK,IAAK,QAAQ,CAAE,EAC7E,CAAC,OAAQ,CAAE,EAAG,IAAK,EAAG,IAAK,MAAO,IAAK,OAAQ,IAAK,GAAI,IAAK,IAAK,QAAQ,CAAE,EAC5E,CAAC,OAAQ,CAAE,EAAG,4CAA6C,IAAK,QAAQ,CAAE,EAC1E,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAQ,CAAE,CAC3C,CAAC","x_google_ignoreList":[0]}
1
+ {"version":3,"file":"network-CrMEVz4-.js","sources":["../../node_modules/lucide-react/dist/esm/icons/network.js"],"sourcesContent":["/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Network = createLucideIcon(\"Network\", [\n [\"rect\", { x: \"16\", y: \"16\", width: \"6\", height: \"6\", rx: \"1\", key: \"4q2zg0\" }],\n [\"rect\", { x: \"2\", y: \"16\", width: \"6\", height: \"6\", rx: \"1\", key: \"8cvhb9\" }],\n [\"rect\", { x: \"9\", y: \"2\", width: \"6\", height: \"6\", rx: \"1\", key: \"1egb70\" }],\n [\"path\", { d: \"M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3\", key: \"1jsf9p\" }],\n [\"path\", { d: \"M12 12V8\", key: \"2874zd\" }]\n]);\n\nexport { Network as default };\n//# sourceMappingURL=network.js.map\n"],"names":["Network","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAUC,EAAiB,UAAW,CAC1C,CAAC,OAAQ,CAAE,EAAG,KAAM,EAAG,KAAM,MAAO,IAAK,OAAQ,IAAK,GAAI,IAAK,IAAK,QAAQ,CAAE,EAC9E,CAAC,OAAQ,CAAE,EAAG,IAAK,EAAG,KAAM,MAAO,IAAK,OAAQ,IAAK,GAAI,IAAK,IAAK,QAAQ,CAAE,EAC7E,CAAC,OAAQ,CAAE,EAAG,IAAK,EAAG,IAAK,MAAO,IAAK,OAAQ,IAAK,GAAI,IAAK,IAAK,QAAQ,CAAE,EAC5E,CAAC,OAAQ,CAAE,EAAG,4CAA6C,IAAK,QAAQ,CAAE,EAC1E,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAQ,CAAE,CAC3C,CAAC","x_google_ignoreList":[0]}
@@ -1,7 +1,7 @@
1
- import{x as L,aa as E,a9 as P,q as m,ac as A,ab as D,Q as t,c as j,i as M,L as N,S as q,l as F,m as Q,j as z,k as y,I as B,a2 as v,z as K,r as V}from"./index-B48azMO-.js";import{e as w}from"./react-C9F3QeMB.js";import{D as J}from"./data-table-B_BxQrSj.js";import{E as U}from"./empty-state-BKs1qKHx.js";import{S as $}from"./status-badge-_3Ve0Jef.js";import{C as H}from"./confirm-dialog-BEzhDlk7.js";import{u as C}from"./useQuery-BjFqOBV3.js";import{L as Y}from"./loader-circle-DBf4xFjo.js";import{R as G}from"./refresh-ccw-Clj5sQNF.js";import"./table-CZwKizat.js";import"./dialog-BAZNQtMt.js";import"./x-CHe1y-sG.js";/**
1
+ import{x as L,aa as E,a9 as P,q as m,ac as A,ab as D,Q as t,c as j,i as M,L as N,S as q,l as F,m as Q,j as z,k as y,I as B,a2 as v,z as K,r as V}from"./index-CITyis5g.js";import{e as w}from"./react-C9F3QeMB.js";import{D as J}from"./data-table-BKTemkw9.js";import{E as U}from"./empty-state-C87S9Wor.js";import{S as $}from"./status-badge-HSHkhdur.js";import{C as H}from"./confirm-dialog-B53cbWzX.js";import{u as C}from"./useQuery-DFryK9Pn.js";import{L as Y}from"./loader-circle-BFp6Oc8_.js";import{R as G}from"./refresh-ccw-CPSYEbgh.js";import"./table-BBISYTH-.js";import"./dialog-Cevi7KvQ.js";import"./x-D5196-9X.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 W=L("Inbox",[["polyline",{points:"22 12 16 12 14 15 10 15 8 12 2 12",key:"o97t9d"}],["path",{d:"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z",key:"oot6mr"}]]),h={all:["outbox"],list:e=>["outbox","list",e],stats:["outbox","stats"]};function X(e){return C({queryKey:h.list(e),queryFn:()=>m.listOutbox(e),refetchInterval:5e3,refetchIntervalInBackground:!1})}function Z(){return C({queryKey:h.stats,queryFn:()=>m.getOutboxStats(),refetchInterval:1e4,refetchIntervalInBackground:!1})}function ee(){const e=E();return P({mutationFn:a=>m.retryOutbox(a),onSuccess:()=>e.invalidateQueries({queryKey:h.all})})}const te=["pending","delivered","giving_up"];function be(){const{t:e}=A(["tasks","common"]),[a,r]=D(),l=a.get("status")??null,i=a.get("thread")??"",{data:_,isLoading:O,isFetching:f,refetch:k}=X({...l?{status:l}:{},...i?{thread:i}:{},limit:200}),I=_?.rows??[],o=Z().data,c=ee(),[d,p]=w.useState(null);function b(s){const n=new URLSearchParams(a);for(const[g,u]of Object.entries(s))u==null||u===""?n.delete(g):n.set(g,u);r(n,{replace:!0})}async function R(){if(d!=null)try{await c.mutateAsync(d),v.success(e("states.saved",{ns:"common"}))}catch(s){const{message:n}=K(s,e);throw v.error(n),s}}const T=w.useMemo(()=>[{id:"id",header:e("outbox.col.id"),cell:s=>t.jsxs("span",{className:"tabular-nums text-text-dim",children:["#",s.id]}),headClassName:"w-20"},{id:"status",header:e("outbox.col.status"),cell:s=>t.jsx($,{status:s.status,children:e(`outbox.status.${s.status}`,{defaultValue:s.status})}),headClassName:"w-28"},{id:"platform",header:e("outbox.col.platform"),cell:s=>t.jsx("span",{className:"font-medium",children:s.platform}),headClassName:"w-28"},{id:"preview",header:e("outbox.col.preview"),cell:s=>t.jsx("span",{className:"line-clamp-2 text-text",title:s.payload,children:ae(s.payload,s.kind)}),asCardTitle:!0},{id:"thread",header:e("outbox.col.thread"),cell:s=>t.jsx("span",{className:"font-mono text-xs text-text-dim line-clamp-1",title:s.thread_key,children:s.thread_key}),headClassName:"w-44",hideOnMobile:!0},{id:"kind",header:e("outbox.col.kind"),cell:s=>t.jsx("span",{className:"text-text-dim",children:s.kind}),headClassName:"w-20",hideOnMobile:!0},{id:"attempts",header:e("outbox.col.attempts"),cell:s=>t.jsx("span",{className:"tabular-nums",children:s.attempts}),headClassName:"w-20"},{id:"createdAt",header:e("outbox.col.createdAt"),cell:s=>t.jsx("span",{className:"text-text-dim",children:S(s.created_at)}),headClassName:"w-32",hideOnMobile:!0},{id:"lastError",header:e("outbox.col.lastError"),cell:s=>s.last_error?t.jsx("span",{className:"line-clamp-1 text-danger text-xs",title:s.last_error,children:s.last_error}):t.jsx("span",{className:"text-text-muted",children:"—"}),hideOnMobile:!1},{id:"actions",header:"",cell:s=>s.status==="giving_up"?t.jsxs(j,{variant:"outline",size:"sm",onClick:n=>{n.stopPropagation(),p(s.id)},disabled:c.isPending,children:[t.jsx(M,{className:"h-3 w-3"}),e("outbox.action.retry")]}):null,headClassName:"w-28"}],[e,c.isPending]);return t.jsxs("div",{className:"mx-auto flex max-w-7xl flex-col gap-4",children:[t.jsxs("header",{className:"flex flex-col gap-1",children:[t.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[t.jsx("h1",{className:"text-xl font-semibold",children:e("outbox.title")}),t.jsxs(j,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>k(),disabled:f,"aria-label":e("actions.refresh",{ns:"common"}),children:[f?t.jsx(Y,{className:"h-4 w-4 animate-spin"}):t.jsx(G,{className:"h-4 w-4"}),t.jsx("span",{className:"hidden sm:inline",children:e("actions.refresh",{ns:"common"})})]})]}),t.jsx("p",{className:"text-sm text-text-dim",children:e("outbox.subtitle")})]}),o&&t.jsxs("div",{className:"grid grid-cols-2 gap-2 sm:grid-cols-4",children:[t.jsx(x,{label:e("outbox.stats.pending"),value:o.pending,tone:"info"}),t.jsx(x,{label:e("outbox.stats.giving_up"),value:o.giving_up,tone:"danger"}),t.jsx(x,{label:e("outbox.stats.delivered"),value:o.delivered,tone:"success"}),t.jsxs("div",{className:"rounded-md border border-border bg-surface px-3 py-2",children:[t.jsx("div",{className:"text-xs uppercase tracking-wide text-text-dim",children:e("outbox.stats.lastDelivered")}),t.jsx("div",{className:"text-sm font-medium tabular-nums",children:o.lastDeliveredAt?S(o.lastDeliveredAt):"—"})]})]}),t.jsxs("div",{className:"flex flex-wrap items-end gap-2",children:[t.jsxs("div",{className:"flex flex-col gap-1",children:[t.jsx(N,{htmlFor:"status-filter",className:"text-xs text-text-dim",children:e("outbox.filter.status")}),t.jsxs(q,{value:l??"__any__",onValueChange:s=>b({status:s==="__any__"?null:s}),children:[t.jsx(F,{id:"status-filter",className:"w-[160px]",children:t.jsx(Q,{})}),t.jsxs(z,{children:[t.jsx(y,{value:"__any__",children:e("outbox.filter.statusAny")}),te.map(s=>t.jsx(y,{value:s,children:e(`outbox.status.${s}`,{defaultValue:s})},s))]})]})]}),t.jsxs("div",{className:"flex flex-col gap-1",children:[t.jsx(N,{htmlFor:"thread-filter",className:"text-xs text-text-dim",children:e("outbox.filter.thread")}),t.jsx(B,{id:"thread-filter",value:i,onChange:s=>b({thread:s.target.value}),placeholder:"wechat:room:...",className:"w-72 font-mono text-xs"})]})]}),t.jsx(J,{columns:T,rows:I,getRowId:s=>String(s.id),loading:O,emptyState:t.jsx(U,{icon:t.jsx(W,{}),title:e("outbox.empty.title"),description:e("outbox.empty.description")})}),t.jsx(H,{open:d!=null,onOpenChange:s=>{s||p(null)},title:e("outbox.action.confirmRetry"),description:e("outbox.action.confirmRetryDesc"),confirmLabel:e("outbox.action.retry"),onConfirm:R})]})}const se={info:"border-info/30 text-info",success:"border-success/30 text-success",warning:"border-warning/30 text-warning",danger:"border-danger/30 text-danger"};function x({label:e,value:a,tone:r}){return t.jsxs("div",{className:V("rounded-md border bg-surface px-3 py-2",se[r]),children:[t.jsx("div",{className:"text-xs uppercase tracking-wide text-text-dim",children:e}),t.jsx("div",{className:"text-2xl font-semibold tabular-nums",children:a})]})}function ae(e,a){if(!e)return"—";if(a==="text")return e;try{const r=JSON.parse(e),l=r.text??r.message??r.title??r.body??null;return typeof l=="string"&&l.length>0?l:JSON.stringify(r)}catch{return e}}function S(e){if(e==null)return"—";try{const a=new Date(e);return Number.isNaN(a.getTime())?e:a.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return e}}export{be as default};
7
- //# sourceMappingURL=outbox-D4IQcACJ.js.map
7
+ //# sourceMappingURL=outbox-C7FpZzwS.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"outbox-D4IQcACJ.js","sources":["../../node_modules/lucide-react/dist/esm/icons/inbox.js","../../src/hooks/use-outbox.ts","../../src/routes/tasks/outbox.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 Inbox = createLucideIcon(\"Inbox\", [\n [\"polyline\", { points: \"22 12 16 12 14 15 10 15 8 12 2 12\", key: \"o97t9d\" }],\n [\n \"path\",\n {\n d: \"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z\",\n key: \"oot6mr\"\n }\n ]\n]);\n\nexport { Inbox as default };\n//# sourceMappingURL=inbox.js.map\n","/**\n * useOutbox — react-query wrappers for the delivery queue.\n *\n * useOutbox(query) — list rows (status / thread / limit)\n * useOutboxStats() — small summary for KPI cards\n * useRetryOutbox() — retry a giving_up row by id\n *\n * The outbox isn't on the SSE bus. Routes use the react-query\n * polling fallback (5s) plus the existing SSE `job` event, which\n * effectively covers any newly-enqueued row (a job that runs to\n * completion enqueues one or more outbox rows).\n */\n\nimport { useQueryClient, useQuery, useMutation } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type { ListOutboxQuery, ListOutboxResponse, OutboxStats } from '@/types/api'\n\nexport const outboxKeys = {\n all: ['outbox'] as const,\n list: (q: ListOutboxQuery) => ['outbox', 'list', q] as const,\n stats: ['outbox', 'stats'] as const,\n}\n\nexport function useOutbox(query: ListOutboxQuery) {\n return useQuery<ListOutboxResponse>({\n queryKey: outboxKeys.list(query),\n queryFn: () => api.listOutbox(query),\n refetchInterval: 5000,\n refetchIntervalInBackground: false,\n })\n}\n\nexport function useOutboxStats() {\n return useQuery<OutboxStats>({\n queryKey: outboxKeys.stats,\n queryFn: () => api.getOutboxStats(),\n refetchInterval: 10000,\n refetchIntervalInBackground: false,\n })\n}\n\nexport function useInvalidateOutbox() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: outboxKeys.all })\n}\n\nexport function useRetryOutbox() {\n const qc = useQueryClient()\n return useMutation({\n mutationFn: (id: number) => api.retryOutbox(id),\n onSuccess: () => qc.invalidateQueries({ queryKey: outboxKeys.all }),\n })\n}\n","/**\n * /tasks/outbox — IM-platform delivery queue. Read-mostly; the one\n * mutation is \"retry\" on rows stuck in `giving_up`. Per-row action\n * routes through ConfirmDialog so an accidental click doesn't re-\n * fire a possibly-flaky delivery against the user's IM channel.\n */\n\nimport { useMemo, useState } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Inbox, Loader2, RefreshCcw, RotateCcw } from 'lucide-react'\n\nimport { DataTable, type DataTableColumn } from '@/components/common/data-table'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { StatusBadge } from '@/components/common/status-badge'\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport {\n useOutbox,\n useOutboxStats,\n useRetryOutbox,\n} from '@/hooks/use-outbox'\nimport type { OutboxRow, OutboxStatus } from '@/types/api'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\nconst STATUS_OPTIONS: OutboxStatus[] = ['pending', 'delivered', 'giving_up']\n\nexport default function OutboxRoute(): JSX.Element {\n const { t } = useTranslation(['tasks', 'common'])\n const [params, setParams] = useSearchParams()\n const status = (params.get('status') as OutboxStatus | null) ?? null\n const thread = params.get('thread') ?? ''\n\n const { data, isLoading, isFetching, refetch } = useOutbox({\n ...(status ? { status } : {}),\n ...(thread ? { thread } : {}),\n limit: 200,\n })\n const rows = data?.rows ?? []\n const statsQuery = useOutboxStats()\n const stats = statsQuery.data\n\n const retryMut = useRetryOutbox()\n const [confirmRetryId, setConfirmRetryId] = 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 onConfirmRetry(): Promise<void> {\n if (confirmRetryId == null) return\n try {\n await retryMut.mutateAsync(confirmRetryId)\n toast.success(t('states.saved', { ns: 'common' }))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err\n }\n }\n\n const columns: DataTableColumn<OutboxRow>[] = useMemo(\n () => [\n {\n id: 'id',\n header: t('outbox.col.id'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">#{r.id}</span>,\n headClassName: 'w-20',\n },\n {\n id: 'status',\n header: t('outbox.col.status'),\n cell: (r) => (\n <StatusBadge status={r.status}>\n {t(`outbox.status.${r.status}`, { defaultValue: r.status })}\n </StatusBadge>\n ),\n headClassName: 'w-28',\n },\n {\n id: 'platform',\n header: t('outbox.col.platform'),\n cell: (r) => <span className=\"font-medium\">{r.platform}</span>,\n headClassName: 'w-28',\n },\n {\n id: 'preview',\n header: t('outbox.col.preview'),\n cell: (r) => (\n <span\n className=\"line-clamp-2 text-text\"\n title={r.payload}\n >\n {previewPayload(r.payload, r.kind)}\n </span>\n ),\n asCardTitle: true,\n },\n {\n id: 'thread',\n header: t('outbox.col.thread'),\n cell: (r) => (\n <span\n className=\"font-mono text-xs text-text-dim line-clamp-1\"\n title={r.thread_key}\n >\n {r.thread_key}\n </span>\n ),\n headClassName: 'w-44',\n hideOnMobile: true,\n },\n {\n id: 'kind',\n header: t('outbox.col.kind'),\n cell: (r) => <span className=\"text-text-dim\">{r.kind}</span>,\n headClassName: 'w-20',\n hideOnMobile: true,\n },\n {\n id: 'attempts',\n header: t('outbox.col.attempts'),\n cell: (r) => <span className=\"tabular-nums\">{r.attempts}</span>,\n headClassName: 'w-20',\n },\n {\n id: 'createdAt',\n header: t('outbox.col.createdAt'),\n cell: (r) => <span className=\"text-text-dim\">{formatTime(r.created_at)}</span>,\n headClassName: 'w-32',\n hideOnMobile: true,\n },\n {\n id: 'lastError',\n header: t('outbox.col.lastError'),\n cell: (r) =>\n r.last_error ? (\n <span className=\"line-clamp-1 text-danger text-xs\" title={r.last_error}>\n {r.last_error}\n </span>\n ) : (\n <span className=\"text-text-muted\">—</span>\n ),\n hideOnMobile: false,\n },\n {\n id: 'actions',\n header: '',\n cell: (r) =>\n r.status === 'giving_up' ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={(e) => {\n e.stopPropagation()\n setConfirmRetryId(r.id)\n }}\n disabled={retryMut.isPending}\n >\n <RotateCcw className=\"h-3 w-3\" />\n {t('outbox.action.retry')}\n </Button>\n ) : null,\n headClassName: 'w-28',\n },\n ],\n [t, retryMut.isPending],\n )\n\n return (\n <div className=\"mx-auto flex max-w-7xl 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('outbox.title')}</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 {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('outbox.subtitle')}</p>\n </header>\n\n {/* Stats strip */}\n {stats && (\n <div className=\"grid grid-cols-2 gap-2 sm:grid-cols-4\">\n <StatCard label={t('outbox.stats.pending')} value={stats.pending} tone=\"info\" />\n <StatCard label={t('outbox.stats.giving_up')} value={stats.giving_up} tone=\"danger\" />\n <StatCard label={t('outbox.stats.delivered')} value={stats.delivered} tone=\"success\" />\n <div className=\"rounded-md border border-border bg-surface px-3 py-2\">\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">\n {t('outbox.stats.lastDelivered')}\n </div>\n <div className=\"text-sm font-medium tabular-nums\">\n {stats.lastDeliveredAt ? formatTime(stats.lastDeliveredAt) : '—'}\n </div>\n </div>\n </div>\n )}\n\n {/* Filter row */}\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"status-filter\" className=\"text-xs text-text-dim\">\n {t('outbox.filter.status')}\n </Label>\n <Select\n value={status ?? '__any__'}\n onValueChange={(v) => patchParams({ status: v === '__any__' ? null : v })}\n >\n <SelectTrigger id=\"status-filter\" className=\"w-[160px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__any__\">{t('outbox.filter.statusAny')}</SelectItem>\n {STATUS_OPTIONS.map((s) => (\n <SelectItem key={s} value={s}>\n {t(`outbox.status.${s}`, { defaultValue: s })}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"thread-filter\" className=\"text-xs text-text-dim\">\n {t('outbox.filter.thread')}\n </Label>\n <Input\n id=\"thread-filter\"\n value={thread}\n onChange={(e) => patchParams({ thread: e.target.value })}\n placeholder=\"wechat:room:...\"\n className=\"w-72 font-mono text-xs\"\n />\n </div>\n </div>\n\n <DataTable\n columns={columns}\n rows={rows}\n getRowId={(r) => String(r.id)}\n loading={isLoading}\n emptyState={\n <EmptyState\n icon={<Inbox />}\n title={t('outbox.empty.title')}\n description={t('outbox.empty.description')}\n />\n }\n />\n\n <ConfirmDialog\n open={confirmRetryId != null}\n onOpenChange={(open) => {\n if (!open) setConfirmRetryId(null)\n }}\n title={t('outbox.action.confirmRetry')}\n description={t('outbox.action.confirmRetryDesc')}\n confirmLabel={t('outbox.action.retry')}\n onConfirm={onConfirmRetry}\n />\n </div>\n )\n}\n\ninterface StatCardProps {\n label: string\n value: number\n tone: 'info' | 'success' | 'warning' | 'danger'\n}\n\nconst TONE_STYLES: Record<StatCardProps['tone'], string> = {\n info: 'border-info/30 text-info',\n success: 'border-success/30 text-success',\n warning: 'border-warning/30 text-warning',\n danger: 'border-danger/30 text-danger',\n}\n\nfunction StatCard({ label, value, tone }: StatCardProps): JSX.Element {\n return (\n <div\n className={cn(\n 'rounded-md border bg-surface px-3 py-2',\n TONE_STYLES[tone],\n )}\n >\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">{label}</div>\n <div className=\"text-2xl font-semibold tabular-nums\">{value}</div>\n </div>\n )\n}\n\n/** Render a one-line preview of an outbox row's payload.\n *\n * Card payloads are JSON encoded by the agent. We pluck the most\n * likely \"message\" field if we can parse it; otherwise we fall back\n * to the raw string. Text payloads are returned as-is, truncated\n * by the surrounding `line-clamp-2`. */\nfunction previewPayload(payload: string, kind: string): string {\n if (!payload) return '—'\n if (kind === 'text') return payload\n try {\n const parsed = JSON.parse(payload) as Record<string, unknown>\n const text = (parsed.text ?? parsed.message ?? parsed.title ?? parsed.body ?? null) as string | null\n if (typeof text === 'string' && text.length > 0) return text\n // Fallback: serialise the object compactly so the operator still\n // sees something useful.\n return JSON.stringify(parsed)\n } catch {\n return payload\n }\n}\n\nfunction formatTime(iso: string | null): string {\n if (iso == null) return '—'\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":["Inbox","createLucideIcon","outboxKeys","q","useOutbox","query","useQuery","api","useOutboxStats","useRetryOutbox","qc","useQueryClient","useMutation","id","STATUS_OPTIONS","OutboxRoute","t","useTranslation","params","setParams","useSearchParams","status","thread","data","isLoading","isFetching","refetch","rows","stats","retryMut","confirmRetryId","setConfirmRetryId","useState","patchParams","patch","next","k","v","onConfirmRetry","toast","err","message","describeError","columns","useMemo","r","jsxs","StatusBadge","jsx","previewPayload","formatTime","Button","e","RotateCcw","Loader2","RefreshCcw","StatCard","Label","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Input","DataTable","EmptyState","ConfirmDialog","open","TONE_STYLES","label","value","tone","cn","payload","kind","parsed","text","iso","d"],"mappings":"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","x_google_ignoreList":[0]}
1
+ {"version":3,"file":"outbox-C7FpZzwS.js","sources":["../../node_modules/lucide-react/dist/esm/icons/inbox.js","../../src/hooks/use-outbox.ts","../../src/routes/tasks/outbox.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 Inbox = createLucideIcon(\"Inbox\", [\n [\"polyline\", { points: \"22 12 16 12 14 15 10 15 8 12 2 12\", key: \"o97t9d\" }],\n [\n \"path\",\n {\n d: \"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z\",\n key: \"oot6mr\"\n }\n ]\n]);\n\nexport { Inbox as default };\n//# sourceMappingURL=inbox.js.map\n","/**\n * useOutbox — react-query wrappers for the delivery queue.\n *\n * useOutbox(query) — list rows (status / thread / limit)\n * useOutboxStats() — small summary for KPI cards\n * useRetryOutbox() — retry a giving_up row by id\n *\n * The outbox isn't on the SSE bus. Routes use the react-query\n * polling fallback (5s) plus the existing SSE `job` event, which\n * effectively covers any newly-enqueued row (a job that runs to\n * completion enqueues one or more outbox rows).\n */\n\nimport { useQueryClient, useQuery, useMutation } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type { ListOutboxQuery, ListOutboxResponse, OutboxStats } from '@/types/api'\n\nexport const outboxKeys = {\n all: ['outbox'] as const,\n list: (q: ListOutboxQuery) => ['outbox', 'list', q] as const,\n stats: ['outbox', 'stats'] as const,\n}\n\nexport function useOutbox(query: ListOutboxQuery) {\n return useQuery<ListOutboxResponse>({\n queryKey: outboxKeys.list(query),\n queryFn: () => api.listOutbox(query),\n refetchInterval: 5000,\n refetchIntervalInBackground: false,\n })\n}\n\nexport function useOutboxStats() {\n return useQuery<OutboxStats>({\n queryKey: outboxKeys.stats,\n queryFn: () => api.getOutboxStats(),\n refetchInterval: 10000,\n refetchIntervalInBackground: false,\n })\n}\n\nexport function useInvalidateOutbox() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: outboxKeys.all })\n}\n\nexport function useRetryOutbox() {\n const qc = useQueryClient()\n return useMutation({\n mutationFn: (id: number) => api.retryOutbox(id),\n onSuccess: () => qc.invalidateQueries({ queryKey: outboxKeys.all }),\n })\n}\n","/**\n * /tasks/outbox — IM-platform delivery queue. Read-mostly; the one\n * mutation is \"retry\" on rows stuck in `giving_up`. Per-row action\n * routes through ConfirmDialog so an accidental click doesn't re-\n * fire a possibly-flaky delivery against the user's IM channel.\n */\n\nimport { useMemo, useState } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Inbox, Loader2, RefreshCcw, RotateCcw } from 'lucide-react'\n\nimport { DataTable, type DataTableColumn } from '@/components/common/data-table'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { StatusBadge } from '@/components/common/status-badge'\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport {\n useOutbox,\n useOutboxStats,\n useRetryOutbox,\n} from '@/hooks/use-outbox'\nimport type { OutboxRow, OutboxStatus } from '@/types/api'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\nconst STATUS_OPTIONS: OutboxStatus[] = ['pending', 'delivered', 'giving_up']\n\nexport default function OutboxRoute(): JSX.Element {\n const { t } = useTranslation(['tasks', 'common'])\n const [params, setParams] = useSearchParams()\n const status = (params.get('status') as OutboxStatus | null) ?? null\n const thread = params.get('thread') ?? ''\n\n const { data, isLoading, isFetching, refetch } = useOutbox({\n ...(status ? { status } : {}),\n ...(thread ? { thread } : {}),\n limit: 200,\n })\n const rows = data?.rows ?? []\n const statsQuery = useOutboxStats()\n const stats = statsQuery.data\n\n const retryMut = useRetryOutbox()\n const [confirmRetryId, setConfirmRetryId] = 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 onConfirmRetry(): Promise<void> {\n if (confirmRetryId == null) return\n try {\n await retryMut.mutateAsync(confirmRetryId)\n toast.success(t('states.saved', { ns: 'common' }))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err\n }\n }\n\n const columns: DataTableColumn<OutboxRow>[] = useMemo(\n () => [\n {\n id: 'id',\n header: t('outbox.col.id'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">#{r.id}</span>,\n headClassName: 'w-20',\n },\n {\n id: 'status',\n header: t('outbox.col.status'),\n cell: (r) => (\n <StatusBadge status={r.status}>\n {t(`outbox.status.${r.status}`, { defaultValue: r.status })}\n </StatusBadge>\n ),\n headClassName: 'w-28',\n },\n {\n id: 'platform',\n header: t('outbox.col.platform'),\n cell: (r) => <span className=\"font-medium\">{r.platform}</span>,\n headClassName: 'w-28',\n },\n {\n id: 'preview',\n header: t('outbox.col.preview'),\n cell: (r) => (\n <span\n className=\"line-clamp-2 text-text\"\n title={r.payload}\n >\n {previewPayload(r.payload, r.kind)}\n </span>\n ),\n asCardTitle: true,\n },\n {\n id: 'thread',\n header: t('outbox.col.thread'),\n cell: (r) => (\n <span\n className=\"font-mono text-xs text-text-dim line-clamp-1\"\n title={r.thread_key}\n >\n {r.thread_key}\n </span>\n ),\n headClassName: 'w-44',\n hideOnMobile: true,\n },\n {\n id: 'kind',\n header: t('outbox.col.kind'),\n cell: (r) => <span className=\"text-text-dim\">{r.kind}</span>,\n headClassName: 'w-20',\n hideOnMobile: true,\n },\n {\n id: 'attempts',\n header: t('outbox.col.attempts'),\n cell: (r) => <span className=\"tabular-nums\">{r.attempts}</span>,\n headClassName: 'w-20',\n },\n {\n id: 'createdAt',\n header: t('outbox.col.createdAt'),\n cell: (r) => <span className=\"text-text-dim\">{formatTime(r.created_at)}</span>,\n headClassName: 'w-32',\n hideOnMobile: true,\n },\n {\n id: 'lastError',\n header: t('outbox.col.lastError'),\n cell: (r) =>\n r.last_error ? (\n <span className=\"line-clamp-1 text-danger text-xs\" title={r.last_error}>\n {r.last_error}\n </span>\n ) : (\n <span className=\"text-text-muted\">—</span>\n ),\n hideOnMobile: false,\n },\n {\n id: 'actions',\n header: '',\n cell: (r) =>\n r.status === 'giving_up' ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={(e) => {\n e.stopPropagation()\n setConfirmRetryId(r.id)\n }}\n disabled={retryMut.isPending}\n >\n <RotateCcw className=\"h-3 w-3\" />\n {t('outbox.action.retry')}\n </Button>\n ) : null,\n headClassName: 'w-28',\n },\n ],\n [t, retryMut.isPending],\n )\n\n return (\n <div className=\"mx-auto flex max-w-7xl 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('outbox.title')}</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 {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('outbox.subtitle')}</p>\n </header>\n\n {/* Stats strip */}\n {stats && (\n <div className=\"grid grid-cols-2 gap-2 sm:grid-cols-4\">\n <StatCard label={t('outbox.stats.pending')} value={stats.pending} tone=\"info\" />\n <StatCard label={t('outbox.stats.giving_up')} value={stats.giving_up} tone=\"danger\" />\n <StatCard label={t('outbox.stats.delivered')} value={stats.delivered} tone=\"success\" />\n <div className=\"rounded-md border border-border bg-surface px-3 py-2\">\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">\n {t('outbox.stats.lastDelivered')}\n </div>\n <div className=\"text-sm font-medium tabular-nums\">\n {stats.lastDeliveredAt ? formatTime(stats.lastDeliveredAt) : '—'}\n </div>\n </div>\n </div>\n )}\n\n {/* Filter row */}\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"status-filter\" className=\"text-xs text-text-dim\">\n {t('outbox.filter.status')}\n </Label>\n <Select\n value={status ?? '__any__'}\n onValueChange={(v) => patchParams({ status: v === '__any__' ? null : v })}\n >\n <SelectTrigger id=\"status-filter\" className=\"w-[160px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__any__\">{t('outbox.filter.statusAny')}</SelectItem>\n {STATUS_OPTIONS.map((s) => (\n <SelectItem key={s} value={s}>\n {t(`outbox.status.${s}`, { defaultValue: s })}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"thread-filter\" className=\"text-xs text-text-dim\">\n {t('outbox.filter.thread')}\n </Label>\n <Input\n id=\"thread-filter\"\n value={thread}\n onChange={(e) => patchParams({ thread: e.target.value })}\n placeholder=\"wechat:room:...\"\n className=\"w-72 font-mono text-xs\"\n />\n </div>\n </div>\n\n <DataTable\n columns={columns}\n rows={rows}\n getRowId={(r) => String(r.id)}\n loading={isLoading}\n emptyState={\n <EmptyState\n icon={<Inbox />}\n title={t('outbox.empty.title')}\n description={t('outbox.empty.description')}\n />\n }\n />\n\n <ConfirmDialog\n open={confirmRetryId != null}\n onOpenChange={(open) => {\n if (!open) setConfirmRetryId(null)\n }}\n title={t('outbox.action.confirmRetry')}\n description={t('outbox.action.confirmRetryDesc')}\n confirmLabel={t('outbox.action.retry')}\n onConfirm={onConfirmRetry}\n />\n </div>\n )\n}\n\ninterface StatCardProps {\n label: string\n value: number\n tone: 'info' | 'success' | 'warning' | 'danger'\n}\n\nconst TONE_STYLES: Record<StatCardProps['tone'], string> = {\n info: 'border-info/30 text-info',\n success: 'border-success/30 text-success',\n warning: 'border-warning/30 text-warning',\n danger: 'border-danger/30 text-danger',\n}\n\nfunction StatCard({ label, value, tone }: StatCardProps): JSX.Element {\n return (\n <div\n className={cn(\n 'rounded-md border bg-surface px-3 py-2',\n TONE_STYLES[tone],\n )}\n >\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">{label}</div>\n <div className=\"text-2xl font-semibold tabular-nums\">{value}</div>\n </div>\n )\n}\n\n/** Render a one-line preview of an outbox row's payload.\n *\n * Card payloads are JSON encoded by the agent. We pluck the most\n * likely \"message\" field if we can parse it; otherwise we fall back\n * to the raw string. Text payloads are returned as-is, truncated\n * by the surrounding `line-clamp-2`. */\nfunction previewPayload(payload: string, kind: string): string {\n if (!payload) return '—'\n if (kind === 'text') return payload\n try {\n const parsed = JSON.parse(payload) as Record<string, unknown>\n const text = (parsed.text ?? parsed.message ?? parsed.title ?? parsed.body ?? null) as string | null\n if (typeof text === 'string' && text.length > 0) return text\n // Fallback: serialise the object compactly so the operator still\n // sees something useful.\n return JSON.stringify(parsed)\n } catch {\n return payload\n }\n}\n\nfunction formatTime(iso: string | null): string {\n if (iso == null) return '—'\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":["Inbox","createLucideIcon","outboxKeys","q","useOutbox","query","useQuery","api","useOutboxStats","useRetryOutbox","qc","useQueryClient","useMutation","id","STATUS_OPTIONS","OutboxRoute","t","useTranslation","params","setParams","useSearchParams","status","thread","data","isLoading","isFetching","refetch","rows","stats","retryMut","confirmRetryId","setConfirmRetryId","useState","patchParams","patch","next","k","v","onConfirmRetry","toast","err","message","describeError","columns","useMemo","r","jsxs","StatusBadge","jsx","previewPayload","formatTime","Button","e","RotateCcw","Loader2","RefreshCcw","StatCard","Label","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Input","DataTable","EmptyState","ConfirmDialog","open","TONE_STYLES","label","value","tone","cn","payload","kind","parsed","text","iso","d"],"mappings":"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","x_google_ignoreList":[0]}
@@ -1,4 +1,4 @@
1
- import{x as d,ac as f,Q as i,S as b,l as g,m as N,j as k,k as C,c as r,r as y}from"./index-B48azMO-.js";import{C as S}from"./chevron-right-DzyVDoQs.js";/**
1
+ import{x as d,ac as f,Q as i,S as b,l as g,m as N,j as k,k as C,c as r,r as y}from"./index-CITyis5g.js";import{C as S}from"./chevron-right-DEyrYFz4.js";/**
2
2
  * @license lucide-react v0.469.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -14,4 +14,4 @@ import{x as d,ac as f,Q as i,S as b,l as g,m as N,j as k,k as C,c as r,r as y}fr
14
14
  * This source code is licensed under the ISC license.
15
15
  * See the LICENSE file in the root directory of this source tree.
16
16
  */const M=d("ChevronLeft",[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]]);function T({page:a,totalPages:c,totalRows:s,perPage:n,perPageOptions:o,onPageChange:l,onPerPageChange:x,className:p}){const{t:e}=f("common"),m=a>1,h=a<c,u=n!==void 0&&o&&o.length>0&&x,v=n?(a-1)*n+1:null,j=n&&s!==void 0?Math.min(a*n,s):null;return i.jsxs("div",{className:y("flex flex-wrap items-center justify-between gap-3 py-2",p),role:"navigation","aria-label":e("pagination.label"),children:[i.jsxs("div",{className:"flex items-center gap-2 text-sm text-text-dim",children:[u&&i.jsxs("div",{className:"hidden sm:flex items-center gap-2",children:[i.jsx("span",{children:e("pagination.perPage")}),i.jsxs(b,{value:String(n),onValueChange:t=>x?.(Number(t)),children:[i.jsx(g,{className:"h-8 w-[80px]",children:i.jsx(N,{})}),i.jsx(k,{children:o.map(t=>i.jsx(C,{value:String(t),children:t},t))})]})]}),s!==void 0&&v!==null&&j!==null&&i.jsx("span",{"aria-live":"polite",children:e("pagination.range",{from:s===0?0:v,to:j,total:s})})]}),i.jsxs("div",{className:"flex items-center gap-1",children:[i.jsx(r,{variant:"ghost",size:"icon","aria-label":e("pagination.firstPage"),disabled:!m,onClick:()=>l(1),className:"hidden sm:inline-flex",children:i.jsx(z,{})}),i.jsx(r,{variant:"ghost",size:"icon","aria-label":e("actions.previous"),disabled:!m,onClick:()=>l(a-1),children:i.jsx(M,{})}),i.jsx("span",{className:"px-2 text-sm tabular-nums","aria-live":"polite",children:e("pagination.pageOfTotal",{page:a,totalPages:Math.max(1,c)})}),i.jsx(r,{variant:"ghost",size:"icon","aria-label":e("actions.next"),disabled:!h,onClick:()=>l(a+1),children:i.jsx(S,{})}),i.jsx(r,{variant:"ghost",size:"icon","aria-label":e("pagination.lastPage"),disabled:!h,onClick:()=>l(c),className:"hidden sm:inline-flex",children:i.jsx(L,{})})]})]})}T.displayName="Pagination";export{T as P};
17
- //# sourceMappingURL=pagination-R9mql8VB.js.map
17
+ //# sourceMappingURL=pagination-Cgt8W6EX.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pagination-R9mql8VB.js","sources":["../../node_modules/lucide-react/dist/esm/icons/chevron-first.js","../../node_modules/lucide-react/dist/esm/icons/chevron-last.js","../../node_modules/lucide-react/dist/esm/icons/chevron-left.js","../../src/components/common/pagination.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 ChevronFirst = createLucideIcon(\"ChevronFirst\", [\n [\"path\", { d: \"m17 18-6-6 6-6\", key: \"1yerx2\" }],\n [\"path\", { d: \"M7 6v12\", key: \"1p53r6\" }]\n]);\n\nexport { ChevronFirst as default };\n//# sourceMappingURL=chevron-first.js.map\n","/**\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 ChevronLast = createLucideIcon(\"ChevronLast\", [\n [\"path\", { d: \"m7 18 6-6-6-6\", key: \"lwmzdw\" }],\n [\"path\", { d: \"M17 6v12\", key: \"1o0aio\" }]\n]);\n\nexport { ChevronLast as default };\n//# sourceMappingURL=chevron-last.js.map\n","/**\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 ChevronLeft = createLucideIcon(\"ChevronLeft\", [\n [\"path\", { d: \"m15 18-6-6 6-6\", key: \"1wnfg3\" }]\n]);\n\nexport { ChevronLeft as default };\n//# sourceMappingURL=chevron-left.js.map\n","/**\n * Pagination — controlled page navigator. Drives the URL via the\n * `page` / `perPage` callbacks; the caller decides whether to write\n * useSearchParams (recommended), zustand, or just local state.\n *\n * Why controlled: each M2 page wants the page index in the URL so\n * deep-links work (\"here's row 42 — share it\"). Forcing the component\n * to manage its own state would either duplicate the search-params\n * read or trap callers into useEffect to sync. Controlled keeps the\n * data flow obvious.\n *\n * Mobile behavior:\n * - The page-size selector hides below sm (no room; default 20 is\n * fine on phone).\n * - The first / last buttons hide below sm (the page label keeps\n * the user oriented; prev / next is enough).\n * - All buttons have a 44×44 hit target via the `icon` size.\n *\n * Edge cases:\n * - page count of 0 / 1 → component still renders so the table\n * footer doesn't jump on the next page-flip; buttons are disabled.\n * - page > totalPages → clamp on the caller's side (we display the\n * label as-is so the caller sees the bug instead of us masking it).\n */\n\nimport { ChevronFirst, ChevronLast, ChevronLeft, ChevronRight } from 'lucide-react'\nimport { useTranslation } from 'react-i18next'\nimport { Button } from '@/components/ui/button'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { cn } from '@/lib/utils'\n\nexport interface PaginationProps {\n /** 1-based current page. */\n page: number\n /** Total number of pages. Pass `Math.max(1, Math.ceil(total / perPage))`. */\n totalPages: number\n /** Optional row count — when present, renders \"1–20 of 150\" alongside the page label. */\n totalRows?: number\n /** Optional rows-per-page slot. Pass `[10, 20, 50, 100]` to enable. */\n perPage?: number\n perPageOptions?: number[]\n onPageChange: (page: number) => void\n onPerPageChange?: (perPage: number) => void\n className?: string\n}\n\nfunction Pagination({\n page,\n totalPages,\n totalRows,\n perPage,\n perPageOptions,\n onPageChange,\n onPerPageChange,\n className,\n}: PaginationProps): JSX.Element {\n const { t } = useTranslation('common')\n const canPrev = page > 1\n const canNext = page < totalPages\n const showPerPage = perPage !== undefined && perPageOptions && perPageOptions.length > 0 && onPerPageChange\n\n const rangeFrom = perPage ? (page - 1) * perPage + 1 : null\n const rangeTo = perPage && totalRows !== undefined\n ? Math.min(page * perPage, totalRows)\n : null\n\n return (\n <div\n className={cn(\n 'flex flex-wrap items-center justify-between gap-3 py-2',\n className,\n )}\n role=\"navigation\"\n aria-label={t('pagination.label')}\n >\n <div className=\"flex items-center gap-2 text-sm text-text-dim\">\n {showPerPage && (\n <div className=\"hidden sm:flex items-center gap-2\">\n <span>{t('pagination.perPage')}</span>\n <Select\n value={String(perPage)}\n onValueChange={(v) => onPerPageChange?.(Number(v))}\n >\n <SelectTrigger className=\"h-8 w-[80px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {perPageOptions.map((n) => (\n <SelectItem key={n} value={String(n)}>\n {n}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n {totalRows !== undefined && rangeFrom !== null && rangeTo !== null && (\n <span aria-live=\"polite\">\n {t('pagination.range', {\n from: totalRows === 0 ? 0 : rangeFrom,\n to: rangeTo,\n total: totalRows,\n })}\n </span>\n )}\n </div>\n\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('pagination.firstPage')}\n disabled={!canPrev}\n onClick={() => onPageChange(1)}\n className=\"hidden sm:inline-flex\"\n >\n <ChevronFirst />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('actions.previous')}\n disabled={!canPrev}\n onClick={() => onPageChange(page - 1)}\n >\n <ChevronLeft />\n </Button>\n\n <span className=\"px-2 text-sm tabular-nums\" aria-live=\"polite\">\n {t('pagination.pageOfTotal', { page, totalPages: Math.max(1, totalPages) })}\n </span>\n\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('actions.next')}\n disabled={!canNext}\n onClick={() => onPageChange(page + 1)}\n >\n <ChevronRight />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('pagination.lastPage')}\n disabled={!canNext}\n onClick={() => onPageChange(totalPages)}\n className=\"hidden sm:inline-flex\"\n >\n <ChevronLast />\n </Button>\n </div>\n </div>\n )\n}\nPagination.displayName = 'Pagination'\n\nexport { Pagination }\n"],"names":["ChevronFirst","createLucideIcon","ChevronLast","ChevronLeft","Pagination","page","totalPages","totalRows","perPage","perPageOptions","onPageChange","onPerPageChange","className","t","useTranslation","canPrev","canNext","showPerPage","rangeFrom","rangeTo","jsxs","cn","jsx","Select","v","SelectTrigger","SelectValue","SelectContent","n","SelectItem","Button","ChevronRight"],"mappings":"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","x_google_ignoreList":[0,1,2]}
1
+ {"version":3,"file":"pagination-Cgt8W6EX.js","sources":["../../node_modules/lucide-react/dist/esm/icons/chevron-first.js","../../node_modules/lucide-react/dist/esm/icons/chevron-last.js","../../node_modules/lucide-react/dist/esm/icons/chevron-left.js","../../src/components/common/pagination.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 ChevronFirst = createLucideIcon(\"ChevronFirst\", [\n [\"path\", { d: \"m17 18-6-6 6-6\", key: \"1yerx2\" }],\n [\"path\", { d: \"M7 6v12\", key: \"1p53r6\" }]\n]);\n\nexport { ChevronFirst as default };\n//# sourceMappingURL=chevron-first.js.map\n","/**\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 ChevronLast = createLucideIcon(\"ChevronLast\", [\n [\"path\", { d: \"m7 18 6-6-6-6\", key: \"lwmzdw\" }],\n [\"path\", { d: \"M17 6v12\", key: \"1o0aio\" }]\n]);\n\nexport { ChevronLast as default };\n//# sourceMappingURL=chevron-last.js.map\n","/**\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 ChevronLeft = createLucideIcon(\"ChevronLeft\", [\n [\"path\", { d: \"m15 18-6-6 6-6\", key: \"1wnfg3\" }]\n]);\n\nexport { ChevronLeft as default };\n//# sourceMappingURL=chevron-left.js.map\n","/**\n * Pagination — controlled page navigator. Drives the URL via the\n * `page` / `perPage` callbacks; the caller decides whether to write\n * useSearchParams (recommended), zustand, or just local state.\n *\n * Why controlled: each M2 page wants the page index in the URL so\n * deep-links work (\"here's row 42 — share it\"). Forcing the component\n * to manage its own state would either duplicate the search-params\n * read or trap callers into useEffect to sync. Controlled keeps the\n * data flow obvious.\n *\n * Mobile behavior:\n * - The page-size selector hides below sm (no room; default 20 is\n * fine on phone).\n * - The first / last buttons hide below sm (the page label keeps\n * the user oriented; prev / next is enough).\n * - All buttons have a 44×44 hit target via the `icon` size.\n *\n * Edge cases:\n * - page count of 0 / 1 → component still renders so the table\n * footer doesn't jump on the next page-flip; buttons are disabled.\n * - page > totalPages → clamp on the caller's side (we display the\n * label as-is so the caller sees the bug instead of us masking it).\n */\n\nimport { ChevronFirst, ChevronLast, ChevronLeft, ChevronRight } from 'lucide-react'\nimport { useTranslation } from 'react-i18next'\nimport { Button } from '@/components/ui/button'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { cn } from '@/lib/utils'\n\nexport interface PaginationProps {\n /** 1-based current page. */\n page: number\n /** Total number of pages. Pass `Math.max(1, Math.ceil(total / perPage))`. */\n totalPages: number\n /** Optional row count — when present, renders \"1–20 of 150\" alongside the page label. */\n totalRows?: number\n /** Optional rows-per-page slot. Pass `[10, 20, 50, 100]` to enable. */\n perPage?: number\n perPageOptions?: number[]\n onPageChange: (page: number) => void\n onPerPageChange?: (perPage: number) => void\n className?: string\n}\n\nfunction Pagination({\n page,\n totalPages,\n totalRows,\n perPage,\n perPageOptions,\n onPageChange,\n onPerPageChange,\n className,\n}: PaginationProps): JSX.Element {\n const { t } = useTranslation('common')\n const canPrev = page > 1\n const canNext = page < totalPages\n const showPerPage = perPage !== undefined && perPageOptions && perPageOptions.length > 0 && onPerPageChange\n\n const rangeFrom = perPage ? (page - 1) * perPage + 1 : null\n const rangeTo = perPage && totalRows !== undefined\n ? Math.min(page * perPage, totalRows)\n : null\n\n return (\n <div\n className={cn(\n 'flex flex-wrap items-center justify-between gap-3 py-2',\n className,\n )}\n role=\"navigation\"\n aria-label={t('pagination.label')}\n >\n <div className=\"flex items-center gap-2 text-sm text-text-dim\">\n {showPerPage && (\n <div className=\"hidden sm:flex items-center gap-2\">\n <span>{t('pagination.perPage')}</span>\n <Select\n value={String(perPage)}\n onValueChange={(v) => onPerPageChange?.(Number(v))}\n >\n <SelectTrigger className=\"h-8 w-[80px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {perPageOptions.map((n) => (\n <SelectItem key={n} value={String(n)}>\n {n}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n {totalRows !== undefined && rangeFrom !== null && rangeTo !== null && (\n <span aria-live=\"polite\">\n {t('pagination.range', {\n from: totalRows === 0 ? 0 : rangeFrom,\n to: rangeTo,\n total: totalRows,\n })}\n </span>\n )}\n </div>\n\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('pagination.firstPage')}\n disabled={!canPrev}\n onClick={() => onPageChange(1)}\n className=\"hidden sm:inline-flex\"\n >\n <ChevronFirst />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('actions.previous')}\n disabled={!canPrev}\n onClick={() => onPageChange(page - 1)}\n >\n <ChevronLeft />\n </Button>\n\n <span className=\"px-2 text-sm tabular-nums\" aria-live=\"polite\">\n {t('pagination.pageOfTotal', { page, totalPages: Math.max(1, totalPages) })}\n </span>\n\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('actions.next')}\n disabled={!canNext}\n onClick={() => onPageChange(page + 1)}\n >\n <ChevronRight />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('pagination.lastPage')}\n disabled={!canNext}\n onClick={() => onPageChange(totalPages)}\n className=\"hidden sm:inline-flex\"\n >\n <ChevronLast />\n </Button>\n </div>\n </div>\n )\n}\nPagination.displayName = 'Pagination'\n\nexport { Pagination }\n"],"names":["ChevronFirst","createLucideIcon","ChevronLast","ChevronLeft","Pagination","page","totalPages","totalRows","perPage","perPageOptions","onPageChange","onPerPageChange","className","t","useTranslation","canPrev","canNext","showPerPage","rangeFrom","rangeTo","jsxs","cn","jsx","Select","v","SelectTrigger","SelectValue","SelectContent","n","SelectItem","Button","ChevronRight"],"mappings":"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","x_google_ignoreList":[0,1,2]}