@nextclaw/ui 0.15.9 → 0.15.11

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 (360) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/dist/assets/{abnfDiagram-VRR7QNED-BYpK0F5F.js → abnfDiagram-VRR7QNED-M4g_AyR8.js} +1 -1
  3. package/dist/assets/{aiden0z-pptx-renderer.es-D87ywFdC.js → aiden0z-pptx-renderer.es-Bd99vut2.js} +1 -1
  4. package/dist/assets/api-pbx14YAL.js +13 -0
  5. package/dist/assets/app-presenter-provider-Q6u2xBAn.js +106 -0
  6. package/dist/assets/appearance-settings-page-D9wJdf-0.js +1 -0
  7. package/dist/assets/{arc-DFELHWM2.js → arc-IO7WNWOB.js} +1 -1
  8. package/dist/assets/architecture-TIHT7OUA-Cii4JyA2.js +1 -0
  9. package/dist/assets/{architectureDiagram-ZJ3FMSHR-CvRhdovL.js → architectureDiagram-ZJ3FMSHR-Dc-lvdUh.js} +1 -1
  10. package/dist/assets/{blockDiagram-677ZJIJ3-DVYNkbR_.js → blockDiagram-677ZJIJ3-CcsoWpIY.js} +1 -1
  11. package/dist/assets/{book-open-w3160PZf.js → book-open-DZyssdCc.js} +1 -1
  12. package/dist/assets/{c4Diagram-LMCZKHZV-B1w-iwRe.js → c4Diagram-LMCZKHZV-Bsrtg6b2.js} +1 -1
  13. package/dist/assets/card-D7l-gWkY.js +1 -0
  14. package/dist/assets/channel-BSKkTPe8.js +1 -0
  15. package/dist/assets/channels-list-page-B3qW3T-B.js +8 -0
  16. package/dist/assets/chat-page-DUI_Jm6r.js +1 -0
  17. package/dist/assets/chunk-2Q5K7J3B-CDMOR1xZ.js +1 -0
  18. package/dist/assets/{chunk-32BRIVSS-kG3lg0bC.js → chunk-32BRIVSS-Bt08t8oG.js} +1 -1
  19. package/dist/assets/{chunk-52WLFC77-BLeB7iGk.js → chunk-52WLFC77-Ddx68Xzx.js} +1 -1
  20. package/dist/assets/{chunk-5FCAYU7R-BQga1Rr7.js → chunk-5FCAYU7R-B7p9_q55.js} +1 -1
  21. package/dist/assets/{chunk-5HE753X5-DU81hkcF.js → chunk-5HE753X5-D52KvdTm.js} +1 -1
  22. package/dist/assets/{chunk-5JV3BV7I-C2bAx0m7.js → chunk-5JV3BV7I-C329h8nI.js} +1 -1
  23. package/dist/assets/{chunk-5TONJI2A-BExIIgWY.js → chunk-5TONJI2A-BZyUBxWt.js} +1 -1
  24. package/dist/assets/{chunk-5VM5RSS4-C3XB05yh.js → chunk-5VM5RSS4-BUiYXZmu.js} +1 -1
  25. package/dist/assets/{chunk-7BUUIJ7U-JiyRtrGu.js → chunk-7BUUIJ7U-B7o-mn4r.js} +1 -1
  26. package/dist/assets/{chunk-BIQX33UG-BZRV20pI.js → chunk-BIQX33UG-Bey9GoRP.js} +1 -1
  27. package/dist/assets/{chunk-C7G6YPKG-AsyDSQ9j.js → chunk-C7G6YPKG-C6tosszM.js} +1 -1
  28. package/dist/assets/{chunk-CQNSW5MT-iN-fiXVA.js → chunk-CQNSW5MT-BNrdkgGQ.js} +1 -1
  29. package/dist/assets/{chunk-CYSBUYHQ-DhC_TRzI.js → chunk-CYSBUYHQ-DHODFeyB.js} +1 -1
  30. package/dist/assets/{chunk-EMLP6XTP-QFLK8R6d.js → chunk-EMLP6XTP-BcmLjrcq.js} +1 -1
  31. package/dist/assets/{chunk-EX3LRPZG-DzUwhkCz.js → chunk-EX3LRPZG-r-_eEtJI.js} +1 -1
  32. package/dist/assets/{chunk-FWX5IMBZ-DFelpZBy.js → chunk-FWX5IMBZ-DOObDWbf.js} +2 -2
  33. package/dist/assets/{chunk-HOUHSVGY-BMPwFEwN.js → chunk-HOUHSVGY-Bd0FnbWZ.js} +1 -1
  34. package/dist/assets/{chunk-ICXQ74PX-DH8NJMok.js → chunk-ICXQ74PX-ntNwAm4_.js} +1 -1
  35. package/dist/assets/{chunk-JG7HCLWE-D-95AsO4.js → chunk-JG7HCLWE-YtRpblZN.js} +1 -1
  36. package/dist/assets/{chunk-JWPE2WC7-DIaTv8kx.js → chunk-JWPE2WC7-De5-D9ta.js} +1 -1
  37. package/dist/assets/{chunk-MOJQB5TN-BPFLzWgj.js → chunk-MOJQB5TN-CdvKhyp2.js} +1 -1
  38. package/dist/assets/{chunk-MOZMSUNE-DR_fzxG0.js → chunk-MOZMSUNE-DJMMN_lu.js} +1 -1
  39. package/dist/assets/{chunk-OGEWGWER-TIcEoPPH.js → chunk-OGEWGWER-DOFWVw3O.js} +1 -1
  40. package/dist/assets/{chunk-OSBZ3O6U-BALNvSfG.js → chunk-OSBZ3O6U-DZkrIN9r.js} +1 -1
  41. package/dist/assets/{chunk-PUDLZKDR-I-EXhf_k.js → chunk-PUDLZKDR-D1wma2Yf.js} +1 -1
  42. package/dist/assets/{chunk-Q4XR5HBZ-uvIGstBS.js → chunk-Q4XR5HBZ-CjPy94Lz.js} +1 -1
  43. package/dist/assets/{chunk-QBLGF6JB-r-TjLdxa.js → chunk-QBLGF6JB-Hy1bEgS-.js} +1 -1
  44. package/dist/assets/{chunk-R7FJI6CG-N-1LDgvy.js → chunk-R7FJI6CG-CUPIHyh-.js} +1 -1
  45. package/dist/assets/{chunk-RYQCIY6F-jxNASx65.js → chunk-RYQCIY6F-D5Ua4pcv.js} +1 -1
  46. package/dist/assets/{chunk-U6XO7XAA-Cphbuc7q.js → chunk-U6XO7XAA-DaUQcqb7.js} +1 -1
  47. package/dist/assets/{chunk-V7JOEXUC-BLEuBf1s.js → chunk-V7JOEXUC-DX2zLfQe.js} +1 -1
  48. package/dist/assets/chunk-VAUOI2AC-BRvqNW76.js +1 -0
  49. package/dist/assets/{chunk-VR4S4FIN-BAUbR0ke.js → chunk-VR4S4FIN-CFA-WQik.js} +1 -1
  50. package/dist/assets/{chunk-WYO6CB5R-Do6SJrnY.js → chunk-WYO6CB5R-Bk2HeDvJ.js} +2 -2
  51. package/dist/assets/chunk-XXDRQBXY-CwX_mqJ3.js +1 -0
  52. package/dist/assets/{chunk-YOTPTUD7-CQqvMTCr.js → chunk-YOTPTUD7-DUG4FpBN.js} +1 -1
  53. package/dist/assets/{chunk-ZGVPDNZ5-B7kWWaXv.js → chunk-ZGVPDNZ5-70JdIGo0.js} +1 -1
  54. package/dist/assets/{chunk-ZIRB5QZD-DTU0cDNh.js → chunk-ZIRB5QZD-XZdgBt5L.js} +1 -1
  55. package/dist/assets/classDiagram-OUVF2IWQ-RzbGxG77.js +1 -0
  56. package/dist/assets/classDiagram-v2-EOCWNBFH-C_gWB7WT.js +1 -0
  57. package/dist/assets/config-split-page-DFEKStD7.js +1 -0
  58. package/dist/assets/confirm-dialog-7wpxfMCp.js +5 -0
  59. package/dist/assets/{cose-bilkent-JH36ORCC-B9LrtV-q.js → cose-bilkent-JH36ORCC-B-PQoGX-.js} +1 -1
  60. package/dist/assets/cynefin-VYW2F7L2-fSLIS0X3.js +1 -0
  61. package/dist/assets/{cynefinDiagram-TSTJHNR4-BfjvW4su.js → cynefinDiagram-TSTJHNR4-BoLCPEM0.js} +1 -1
  62. package/dist/assets/{dagre-DkiXZKkL.js → dagre-D7Ie4eXr.js} +1 -1
  63. package/dist/assets/{dagre-VKFMJZFB-B1pQKQSY.js → dagre-VKFMJZFB-CKRrwZA-.js} +1 -1
  64. package/dist/assets/desktop-update-config-DP6IbxBO.js +1 -0
  65. package/dist/assets/{diagram-FQU43EPY-cB4EZdaP.js → diagram-FQU43EPY-CASL1J3_.js} +1 -1
  66. package/dist/assets/{diagram-G47NLZAW-CtW8im1B.js → diagram-G47NLZAW-CvLPBIzf.js} +1 -1
  67. package/dist/assets/{diagram-NH7WQ7WH-BDCtrCCm.js → diagram-NH7WQ7WH-Ba6fGdYP.js} +1 -1
  68. package/dist/assets/{diagram-OA4YK3LP-DEMJ42Gt.js → diagram-OA4YK3LP-DkpfgEjM.js} +1 -1
  69. package/dist/assets/{diagram-WEI45ONY-CdCcxSYU.js → diagram-WEI45ONY-BP5UMVsN.js} +1 -1
  70. package/dist/assets/{dist-DEJlYi0E.js → dist-B9UN0HrS.js} +1 -1
  71. package/dist/assets/doc-browser-D7klPMHs.js +1 -0
  72. package/dist/assets/{doc-browser-context-CpvHiuQG.js → doc-browser-context-Bw9m83Jp.js} +1 -1
  73. package/dist/assets/doc-browser-wgEeLkn1.js +1 -0
  74. package/dist/assets/{docx-preview-zis3U0Fa.js → docx-preview-D0tp3a9T.js} +1 -1
  75. package/dist/assets/{ebnfDiagram-CCIWWBDH-DBZETBwE.js → ebnfDiagram-CCIWWBDH-TJKbUcmc.js} +1 -1
  76. package/dist/assets/{erDiagram-Q63AITRT-y2zDXprP.js → erDiagram-Q63AITRT-DzGPKkKH.js} +1 -1
  77. package/dist/assets/eventmodeling-45OFAUF4-XVcQGgha.js +1 -0
  78. package/dist/assets/eye-IVMB0Rrz.js +1 -0
  79. package/dist/assets/flowDiagram-23GEKE2U-BiFSctqz.js +1 -0
  80. package/dist/assets/{form-actions-5OsDRt0g.js → form-actions-DrFAgO58.js} +1 -1
  81. package/dist/assets/{ganttDiagram-NO4QXBWP-D2DP344e.js → ganttDiagram-NO4QXBWP-JhJzsGp2.js} +1 -1
  82. package/dist/assets/gitGraph-TEB2WS4Q-C014uXqS.js +1 -0
  83. package/dist/assets/{gitGraphDiagram-IHSO6WYX-D37uiwA2.js → gitGraphDiagram-IHSO6WYX-DZ1CKMj8.js} +1 -1
  84. package/dist/assets/index-D297NGOb.js +2 -0
  85. package/dist/assets/index-DqZoodZL.css +1 -0
  86. package/dist/assets/info-DKCQHKI2-CQ2qjGhU.js +1 -0
  87. package/dist/assets/{infoDiagram-FWYZ7A6U-CG-WAIRi.js → infoDiagram-FWYZ7A6U-BNXNKfRQ.js} +1 -1
  88. package/dist/assets/{ishikawaDiagram-FXEZZL3T-WeCTnW0f.js → ishikawaDiagram-FXEZZL3T-DoiEfjNw.js} +1 -1
  89. package/dist/assets/{journeyDiagram-5HDEW3XC-DUFBW9Td.js → journeyDiagram-5HDEW3XC-D6oK2HSy.js} +1 -1
  90. package/dist/assets/{kanban-definition-HUTT4EX6-B0lxgMpg.js → kanban-definition-HUTT4EX6-B2UnLOH-.js} +1 -1
  91. package/dist/assets/{line-B78frP_c.js → line-BM7PoxY5.js} +1 -1
  92. package/dist/assets/{linear-C6lVEcb2.js → linear-B3DiqMjk.js} +1 -1
  93. package/dist/assets/loader-circle-DDgFo4Kv.js +1 -0
  94. package/dist/assets/{logo-badge-TdPa95AC.js → logo-badge-DoZOVuPr.js} +1 -1
  95. package/dist/assets/{map-Bdri5UL5.js → map-BAAdHTqR.js} +1 -1
  96. package/dist/assets/mcp-marketplace-page-BtNExfMn.js +1 -0
  97. package/dist/assets/{mcp-marketplace-page-cm3ifaKu.js → mcp-marketplace-page-C151EGP-.js} +2 -2
  98. package/dist/assets/{mermaid-parser.core-Cue18vLo.js → mermaid-parser.core-BeMviefY.js} +2 -2
  99. package/dist/assets/{mermaid.core-CXwWRh5i.js → mermaid.core-D0Q77r9I.js} +3 -3
  100. package/dist/assets/{mindmap-definition-LN4V7U3C-CFxz0P0-.js → mindmap-definition-LN4V7U3C-BQ7r7bR8.js} +1 -1
  101. package/dist/assets/model-config-page-BmfQzc52.js +1 -0
  102. package/dist/assets/navigation-link-CJw6FLOj.js +1 -0
  103. package/dist/assets/{ordinal-Cbd8t4LB.js → ordinal-Bt2N4IkA.js} +1 -1
  104. package/dist/assets/packet-7NZHBO7P-6IFyydij.js +1 -0
  105. package/dist/assets/{pegDiagram-2B236MQR-B_Qt9zyT.js → pegDiagram-2B236MQR-B-C9-LGz.js} +1 -1
  106. package/dist/assets/pie-RZYD4A2V-spXQC_wr.js +1 -0
  107. package/dist/assets/{pieDiagram-ENE6RG2P-CRQdSuwS.js → pieDiagram-ENE6RG2P-CtirZLtn.js} +1 -1
  108. package/dist/assets/plus-CYxLSfLh.js +1 -0
  109. package/dist/assets/{popover-EulxhA0q.js → popover-DitLJE6k.js} +1 -1
  110. package/dist/assets/provider-scoped-model-input-CuAtduIc.js +1 -0
  111. package/dist/assets/providers-config-page-CrmuY4DC.js +1 -0
  112. package/dist/assets/{quadrantDiagram-ABIIQ3AL-D5kPpttq.js → quadrantDiagram-ABIIQ3AL-DiBWAzDU.js} +1 -1
  113. package/dist/assets/radar-I7S5WNFK-DWVA8lvY.js +1 -0
  114. package/dist/assets/railroad-3IZDKUUU-Ce51u8y1.js +1 -0
  115. package/dist/assets/railroad-abnf-AHOZXSZD-D7i7cqI_.js +1 -0
  116. package/dist/assets/railroad-ebnf-EBAXGLYW-BEg2hcPs.js +1 -0
  117. package/dist/assets/railroad-peg-LSFZ7HO6-CxROSzbi.js +1 -0
  118. package/dist/assets/{railroadDiagram-RFXS5EU6-DGh_TGlQ.js → railroadDiagram-RFXS5EU6-CP6b3PBI.js} +1 -1
  119. package/dist/assets/{react-Bb0EYsLS.js → react-CTDaaQ9V.js} +1 -1
  120. package/dist/assets/{refresh-cw-CexL11m1.js → refresh-cw-E5qTlQY6.js} +1 -1
  121. package/dist/assets/remote-YzPpOPmK.js +1 -0
  122. package/dist/assets/{requirementDiagram-TGXJPOKE-EmFph0H_.js → requirementDiagram-TGXJPOKE-D8YV0-Jz.js} +1 -1
  123. package/dist/assets/rotate-cw-BXeiDT6C.js +1 -0
  124. package/dist/assets/runtime-config-page-1fPJJvo5.js +1 -0
  125. package/dist/assets/{sankeyDiagram-HTMAVEWB-BXWB5Ugi.js → sankeyDiagram-HTMAVEWB-C2vA4ojE.js} +1 -1
  126. package/dist/assets/{save-DtccrZld.js → save-CTiZvAd2.js} +1 -1
  127. package/dist/assets/{search-BArc_WOX.js → search-CztGmpnR.js} +1 -1
  128. package/dist/assets/search-config-page-D3jVALZU.js +1 -0
  129. package/dist/assets/secrets-config-page-CxWLQCjZ.js +3 -0
  130. package/dist/assets/security-config-DEyj4WBh.js +1 -0
  131. package/dist/assets/{select-C9FB0jlt.js → select-BPVI2dQ_.js} +1 -1
  132. package/dist/assets/{sequenceDiagram-DBY2YBRQ-ClKnO7v0.js → sequenceDiagram-DBY2YBRQ-B9LBmpUo.js} +1 -1
  133. package/dist/assets/settings-2-Cd7QaBsq.js +1 -0
  134. package/dist/assets/{sizeCapture-X5ZJPWSS-DSo-t5ou.js → sizeCapture-X5ZJPWSS-9UIfya9-.js} +1 -1
  135. package/dist/assets/skeleton-CUpAXGoe.js +1 -0
  136. package/dist/assets/{src-Dad2ZbCt.js → src-DKf77Yzo.js} +1 -1
  137. package/dist/assets/{stateDiagram-2N3HPSRC-BvAalBfz.js → stateDiagram-2N3HPSRC-oTW44vds.js} +1 -1
  138. package/dist/assets/stateDiagram-v2-6OUMAXLB-Bui4RXQK.js +1 -0
  139. package/dist/assets/{swimlanes-5IMT3BWC-DdVqVa1a.js → swimlanes-5IMT3BWC-Cf7lcsay.js} +2 -2
  140. package/dist/assets/swimlanesDiagram-G3AALYLV-DTwUsCBz.js +8 -0
  141. package/dist/assets/{tabs-D_mjyOOf.js → tabs-DrUmYwEQ.js} +1 -1
  142. package/dist/assets/{tag-chip-C011rd9q.js → tag-chip-CmViAZKK.js} +1 -1
  143. package/dist/assets/{timeline-definition-FHXFAJF6-D4ar8IQY.js → timeline-definition-FHXFAJF6-DoCuWKDJ.js} +1 -1
  144. package/dist/assets/{trash-2-bDhfsO1O.js → trash-2-DMRJ63AB.js} +1 -1
  145. package/dist/assets/treeView-QDETBFTQ-D5zsTiuL.js +1 -0
  146. package/dist/assets/treemap-6X3UGDF4-CR3dxqNs.js +1 -0
  147. package/dist/assets/{use-config-BNrlfEck.js → use-config-gpXy2Iyc.js} +1 -1
  148. package/dist/assets/use-confirm-dialog-Du33bHPz.js +1 -0
  149. package/dist/assets/{use-viewport-layout-P0q6Nt_N.js → use-viewport-layout-D80O1d90.js} +1 -1
  150. package/dist/assets/{vennDiagram-L72KCM5P-CDXJ_i3p.js → vennDiagram-L72KCM5P-CpU0pzGe.js} +1 -1
  151. package/dist/assets/wardley-OPB4EBWU-LatRT_Lx.js +1 -0
  152. package/dist/assets/{wardleyDiagram-EHGQE667-D-dSuT_7.js → wardleyDiagram-EHGQE667-CkN6nn6-.js} +1 -1
  153. package/dist/assets/x-CsLMuNFe.js +1 -0
  154. package/dist/assets/{xychartDiagram-FW5EYKEG-C9JCzsZF.js → xychartDiagram-FW5EYKEG-DATpapm2.js} +1 -1
  155. package/dist/index.html +31 -32
  156. package/dist/runtime-icons/opencode.svg +16 -0
  157. package/package.json +10 -9
  158. package/public/runtime-icons/opencode.svg +16 -0
  159. package/src/app/components/layout/__tests__/settings-entry-page.test.tsx +6 -4
  160. package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +24 -12
  161. package/src/app/components/layout/sidebar-items.tsx +11 -2
  162. package/src/app/components/layout/sidebar.tsx +33 -234
  163. package/src/app/configs/app-navigation.config.ts +10 -24
  164. package/src/app/index.tsx +0 -5
  165. package/src/features/channels/components/config/channel-form.tsx +26 -26
  166. package/src/features/channels/components/config/weixin-channel-auth-section.tsx +6 -7
  167. package/src/features/channels/pages/__tests__/channels-list-page.test.tsx +2 -2
  168. package/src/features/channels/pages/channels-list-page.tsx +33 -32
  169. package/src/features/chat/components/conversation/__tests__/chat-conversation-content.test.tsx +68 -7
  170. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +27 -0
  171. package/src/features/chat/components/conversation/__tests__/chat-conversation-panel.test.tsx +0 -8
  172. package/src/features/chat/components/conversation/chat-conversation-content.tsx +65 -21
  173. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +36 -12
  174. package/src/features/chat/components/conversation/chat-conversation-panel.tsx +0 -7
  175. package/src/features/chat/components/layout/__tests__/chat-sidebar-toolbar.test.tsx +0 -1
  176. package/src/features/chat/components/layout/__tests__/chat-sidebar.test.tsx +17 -8
  177. package/src/features/chat/components/layout/chat-page-shell.tsx +2 -2
  178. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +2 -23
  179. package/src/features/chat/components/layout/chat-sidebar.tsx +3 -12
  180. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +155 -93
  181. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +126 -93
  182. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-input-state.test.tsx +8 -0
  183. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +27 -13
  184. package/src/features/chat/features/message/components/__tests__/chat-inline-file-preview.test.tsx +15 -9
  185. package/src/features/chat/features/message/components/__tests__/chat-inline-panel-app-card.test.tsx +127 -49
  186. package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +187 -20
  187. package/src/features/chat/features/message/components/chat-inline-content-surface.tsx +55 -0
  188. package/src/features/chat/features/message/components/chat-inline-file-preview.tsx +49 -71
  189. package/src/features/chat/features/message/components/chat-inline-panel-app-card.tsx +65 -55
  190. package/src/features/chat/features/message/components/chat-message-list.container.tsx +275 -267
  191. package/src/features/chat/features/message/hooks/__tests__/use-chat-message-virtualizer.test.tsx +163 -0
  192. package/src/features/chat/features/message/hooks/use-chat-message-virtualizer.ts +68 -0
  193. package/src/features/chat/features/message/utils/__tests__/chat-message-execution-summary.utils.test.ts +188 -0
  194. package/src/features/chat/features/message/utils/__tests__/chat-message-texts.utils.test.ts +14 -1
  195. package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +33 -0
  196. package/src/features/chat/features/message/utils/chat-inline-panel-app-card.utils.ts +24 -9
  197. package/src/features/chat/features/message/utils/chat-message-execution-summary.utils.ts +178 -0
  198. package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +44 -0
  199. package/src/features/chat/features/message/utils/chat-message-timeline.utils.ts +194 -0
  200. package/src/features/chat/features/message/utils/chat-message.utils.ts +5 -0
  201. package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-session-conversation.test.tsx +151 -13
  202. package/src/features/chat/features/ncp/hooks/use-ncp-session-conversation.ts +44 -70
  203. package/src/features/chat/features/ncp/hooks/use-ncp-session-message-history.ts +197 -0
  204. package/src/features/chat/features/session/components/__tests__/chat-sidebar-session-item.test.tsx +21 -3
  205. package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +7 -7
  206. package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +2 -2
  207. package/src/features/chat/features/session/components/session-context-icon.tsx +1 -1
  208. package/src/features/chat/features/session-type/components/__tests__/chat-session-type-option-item.test.tsx +5 -1
  209. package/src/features/chat/features/session-type/components/chat-session-type-option-item.tsx +1 -1
  210. package/src/features/chat/features/workspace/components/__tests__/workspace-file-content-preview.test.tsx +32 -10
  211. package/src/features/chat/features/workspace/components/workspace-file-content-preview.tsx +5 -15
  212. package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +62 -9
  213. package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +6 -1
  214. package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +1 -25
  215. package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +190 -109
  216. package/src/features/chat/managers/__tests__/chat-thread-workspace.manager.test.ts +9 -10
  217. package/src/features/chat/managers/chat-session-list.manager.ts +68 -27
  218. package/src/features/cron/components/__tests__/cron-config.test.tsx +260 -0
  219. package/src/features/cron/components/cron-config.tsx +392 -388
  220. package/src/features/cron/components/cron-job-detail-dialog.tsx +210 -0
  221. package/src/features/cron/components/cron-job-row.tsx +271 -0
  222. package/src/features/cron/components/cron-task-discovery.tsx +157 -0
  223. package/src/features/cron/hooks/use-cron-jobs.ts +3 -1
  224. package/src/features/marketplace/components/__tests__/marketplace-page.test.tsx +3 -2
  225. package/src/features/marketplace/components/marketplace-external-skill-source-action.tsx +8 -6
  226. package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +26 -40
  227. package/src/features/pwa/components/pwa-install-entry.tsx +45 -58
  228. package/src/features/remote/components/remote-access-page.tsx +128 -208
  229. package/src/features/settings/components/config/provider-auth-section.tsx +32 -17
  230. package/src/features/settings/components/config/provider-form.tsx +6 -6
  231. package/src/features/settings/components/config/provider-models-section.tsx +52 -46
  232. package/src/features/settings/components/config/secrets-config-form.tsx +78 -84
  233. package/src/features/settings/index.ts +0 -1
  234. package/src/features/settings/pages/__tests__/appearance-settings-page.test.tsx +35 -1
  235. package/src/features/settings/pages/__tests__/model-config-page.test.tsx +18 -1
  236. package/src/features/settings/pages/__tests__/search-config-page.test.tsx +8 -0
  237. package/src/features/settings/pages/__tests__/secrets-config-page.test.tsx +18 -17
  238. package/src/features/settings/pages/appearance-settings-page.tsx +87 -64
  239. package/src/features/settings/pages/model-config-page.tsx +75 -70
  240. package/src/features/settings/pages/providers-config-page.tsx +107 -73
  241. package/src/features/settings/pages/search-config-page.tsx +159 -152
  242. package/src/features/settings/pages/secrets-config-page.tsx +6 -1
  243. package/src/features/system-status/components/config/runtime-agent-list-card.tsx +23 -22
  244. package/src/features/system-status/components/config/runtime-binding-list-card.tsx +23 -22
  245. package/src/features/system-status/components/config/runtime-config-editor.tsx +17 -7
  246. package/src/features/system-status/components/config/runtime-config-overview.tsx +0 -3
  247. package/src/features/system-status/components/config/runtime-entry-list-card.tsx +24 -23
  248. package/src/features/system-status/components/config/runtime-settings-card.tsx +59 -52
  249. package/src/features/system-status/components/desktop-update-config.tsx +117 -112
  250. package/src/features/system-status/components/runtime-control-card.tsx +62 -59
  251. package/src/features/system-status/components/runtime-presence-card.tsx +79 -98
  252. package/src/features/system-status/components/runtime-security-card.tsx +74 -62
  253. package/src/features/system-status/components/security-config.tsx +3 -4
  254. package/src/features/system-status/pages/runtime-config-page.tsx +6 -1
  255. package/src/platforms/desktop/components/desktop-app-shell.tsx +1 -1
  256. package/src/platforms/mobile/components/mobile-settings-shell.tsx +2 -2
  257. package/src/shared/components/__tests__/config-split-page.test.tsx +15 -3
  258. package/src/shared/components/__tests__/settings-page.test.tsx +31 -0
  259. package/src/shared/components/actions/__tests__/navigation-link.test.tsx +47 -0
  260. package/src/shared/components/actions/navigation-link.tsx +116 -0
  261. package/src/shared/components/common/__tests__/brand-header.test.tsx +5 -5
  262. package/src/shared/components/common/__tests__/searchable-model-input.test.tsx +24 -0
  263. package/src/shared/components/common/brand-header.tsx +12 -10
  264. package/src/shared/components/common/searchable-model-input.tsx +9 -10
  265. package/src/shared/components/config-split-page.tsx +70 -65
  266. package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +6 -7
  267. package/src/shared/components/settings/setting-row.tsx +61 -30
  268. package/src/shared/components/settings/settings-page.tsx +34 -0
  269. package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +23 -2
  270. package/src/shared/components/ui/actions/icon-action-button.tsx +9 -2
  271. package/src/shared/components/ui/overlays/sheet.tsx +142 -0
  272. package/src/shared/lib/api/ncp-session.types.ts +8 -2
  273. package/src/shared/lib/api/types.ts +22 -1
  274. package/src/shared/lib/api/utils/config.utils.ts +2 -1
  275. package/src/shared/lib/api/utils/ncp-session.utils.ts +25 -11
  276. package/src/shared/lib/i18n/locales/en-US/chat.json +32 -1
  277. package/src/shared/lib/i18n/locales/en-US/core.json +3 -3
  278. package/src/shared/lib/i18n/locales/en-US/cron.json +87 -17
  279. package/src/shared/lib/i18n/locales/zh-CN/chat.json +34 -3
  280. package/src/shared/lib/i18n/locales/zh-CN/core.json +6 -6
  281. package/src/shared/lib/i18n/locales/zh-CN/cron.json +80 -10
  282. package/src/shared/lib/transport/__tests__/remote.transport.test.ts +16 -4
  283. package/dist/assets/api-D0U10BcF.js +0 -13
  284. package/dist/assets/app-presenter-provider-Dffdm_Ek.js +0 -106
  285. package/dist/assets/appearance-settings-page-sfusZc2d.js +0 -1
  286. package/dist/assets/architecture-TIHT7OUA-ClwVFq-K.js +0 -1
  287. package/dist/assets/channel-BEHOSFc5.js +0 -1
  288. package/dist/assets/channels-list-page-Dkfe87Zq.js +0 -8
  289. package/dist/assets/chat-page-CeapbQnG.js +0 -1
  290. package/dist/assets/chunk-2Q5K7J3B-DrIhesSX.js +0 -1
  291. package/dist/assets/chunk-VAUOI2AC-Dpcz6BhT.js +0 -1
  292. package/dist/assets/chunk-XXDRQBXY-C2QjjwYX.js +0 -1
  293. package/dist/assets/classDiagram-OUVF2IWQ-DESMaY3_.js +0 -1
  294. package/dist/assets/classDiagram-v2-EOCWNBFH-DwOlByYH.js +0 -1
  295. package/dist/assets/config-split-page-CnQI8cKT.js +0 -1
  296. package/dist/assets/confirm-dialog-RZUWA_j9.js +0 -5
  297. package/dist/assets/cynefin-VYW2F7L2-CzjeeOq9.js +0 -1
  298. package/dist/assets/desktop-update-config-CbSYQMYz.js +0 -1
  299. package/dist/assets/doc-browser-DwXHr-mm.js +0 -1
  300. package/dist/assets/doc-browser-jVTq8iY_2.js +0 -1
  301. package/dist/assets/download-BP7ZxrwI.js +0 -1
  302. package/dist/assets/eventmodeling-45OFAUF4-C38BqG8w.js +0 -1
  303. package/dist/assets/external-link-DvHCEe3h.js +0 -1
  304. package/dist/assets/eye-C--6dxv_.js +0 -1
  305. package/dist/assets/flowDiagram-23GEKE2U-BoKk8RRq.js +0 -1
  306. package/dist/assets/folder-BfeO1zCY.js +0 -1
  307. package/dist/assets/gitGraph-TEB2WS4Q-IsQHHJuS.js +0 -1
  308. package/dist/assets/index-BlKbckX4.css +0 -1
  309. package/dist/assets/index-DoZR11Nh.js +0 -2
  310. package/dist/assets/info-DKCQHKI2-ofy2qlHI.js +0 -1
  311. package/dist/assets/loader-circle-BWdgwVnn.js +0 -1
  312. package/dist/assets/mcp-marketplace-page-XnRWiC8c.js +0 -1
  313. package/dist/assets/model-config-page-CXnqSbSI.js +0 -1
  314. package/dist/assets/packet-7NZHBO7P-Rfopfa1o.js +0 -1
  315. package/dist/assets/pie-RZYD4A2V-CJR1xKEv.js +0 -1
  316. package/dist/assets/plus-BeApS21t.js +0 -1
  317. package/dist/assets/provider-scoped-model-input-ll_Btc9h.js +0 -1
  318. package/dist/assets/providers-config-page-Bcuhqkdl.js +0 -1
  319. package/dist/assets/radar-I7S5WNFK-CDg8Z-1r.js +0 -1
  320. package/dist/assets/railroad-3IZDKUUU-BHnNmjxO.js +0 -1
  321. package/dist/assets/railroad-abnf-AHOZXSZD-DGtNcusW.js +0 -1
  322. package/dist/assets/railroad-ebnf-EBAXGLYW-BRFtsQmm.js +0 -1
  323. package/dist/assets/railroad-peg-LSFZ7HO6-Bj5IypCA.js +0 -1
  324. package/dist/assets/remote-CqKpuOP9.js +0 -1
  325. package/dist/assets/rotate-cw-DHXoiqFB.js +0 -1
  326. package/dist/assets/runtime-config-page-D-Aqxizs.js +0 -1
  327. package/dist/assets/search-config-page-XTKf5rc0.js +0 -1
  328. package/dist/assets/secrets-config-page-Cx-qptcj.js +0 -3
  329. package/dist/assets/security-config-DWGFM2u9.js +0 -1
  330. package/dist/assets/setting-row-DFvioO2a.js +0 -1
  331. package/dist/assets/settings-2-RMWqf-ey.js +0 -1
  332. package/dist/assets/skeleton-DQ5WhuDG.js +0 -1
  333. package/dist/assets/stateDiagram-v2-6OUMAXLB-CfMU38yc.js +0 -1
  334. package/dist/assets/swimlanesDiagram-G3AALYLV-D9Zb9X57.js +0 -8
  335. package/dist/assets/treeView-QDETBFTQ-Uy7M0WvH.js +0 -1
  336. package/dist/assets/treemap-6X3UGDF4-BJfGV7KX.js +0 -1
  337. package/dist/assets/use-confirm-dialog-CTNA1PC0.js +0 -1
  338. package/dist/assets/wardley-OPB4EBWU-q263iF3K.js +0 -1
  339. package/dist/assets/x-qvh05iyu.js +0 -1
  340. package/src/features/chat/components/conversation/chat-conversation-skeleton.tsx +0 -86
  341. package/src/features/settings/pages/__tests__/language-settings-page.test.tsx +0 -36
  342. package/src/features/settings/pages/language-settings-page.tsx +0 -56
  343. package/src/shared/components/actions/action-link.tsx +0 -49
  344. /package/dist/assets/{array-BqYdCIE6.js → array-CAkJT3no.js} +0 -0
  345. /package/dist/assets/{chunk-KEIR6QF5-A3jEqwzn.js → chunk-KEIR6QF5-BgdDoWEH.js} +0 -0
  346. /package/dist/assets/{chunk-Y2CYZVJY-BGrd8tLy.js → chunk-Y2CYZVJY-pTllD0P3.js} +0 -0
  347. /package/dist/assets/{config-hints-LxG80Uj5.js → config-hints-S3g-UVZb.js} +0 -0
  348. /package/dist/assets/{cytoscape.esm-CRW8q92n.js → cytoscape.esm-DmURt-5G.js} +0 -0
  349. /package/dist/assets/{defaultLocale-Cdv9x6q7.js → defaultLocale-BKy_KP3O.js} +0 -0
  350. /package/dist/assets/{dist-dw-gAfM_.js → dist-IgNNB7K9.js} +0 -0
  351. /package/dist/assets/{graphlib-BcNFQr5y.js → graphlib-xw_TBHyH.js} +0 -0
  352. /package/dist/assets/{host-capabilities-CFbAfrrA.js → host-capabilities-B-TtABsP.js} +0 -0
  353. /package/dist/assets/{init-D8TjIqfm.js → init-C9xlLIAu.js} +0 -0
  354. /package/dist/assets/{jszip.min-CP5uPNQa.js → jszip.min-Das2IAnb.js} +0 -0
  355. /package/dist/assets/{katex-wEmrEFTg.js → katex-DSy1eD2d.js} +0 -0
  356. /package/dist/assets/{middleware-CAXxl-af.js → middleware-Df-a4x-q.js} +0 -0
  357. /package/dist/assets/{path-DzBnMI1r.js → path-DB0USYHi.js} +0 -0
  358. /package/dist/assets/{provider-models-BoUhFo9R.js → provider-models-CXUgDxGR.js} +0 -0
  359. /package/dist/assets/{rough.esm-wJ1d3nQl.js → rough.esm-B1B52ZQS.js} +0 -0
  360. /package/dist/assets/{xlsx-DUqJhg5u.js → xlsx-DfjC_iml.js} +0 -0
@@ -1,39 +1,49 @@
1
- import { useState } from "react";
2
- import { ExternalLink, KeyRound, Search as SearchIcon } from "lucide-react";
3
- import { PageHeader, PageLayout } from "@/app/components/layout/page-layout";
4
- import { Button } from "@/shared/components/ui/button";
5
- import { FormActions } from "@/shared/components/ui/actions/form-actions";
6
- import { Input } from "@/shared/components/ui/input";
7
- import { Label } from "@/shared/components/ui/label";
8
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/shared/components/ui/select";
9
- import { useConfig, useConfigMeta, useUpdateSearch } from "@/shared/hooks/use-config";
10
- import { t } from "@/shared/lib/i18n";
11
- import type { SearchConfigUpdate, SearchProviderName, TavilySearchDepthValue } from "@/shared/lib/api";
12
- import { ConfigSelectionCard, ConfigSplitDetailPane, ConfigSplitEmptyPane, ConfigSplitPage, ConfigSplitPaneBody, ConfigSplitPaneFooter, ConfigSplitPaneHeader, ConfigSplitSidebar } from "@/shared/components/config-split-page";
13
- import { useViewportLayout } from "@/app/hooks/use-viewport-layout";
1
+ import { useState } from 'react';
2
+ import { KeyRound, Search as SearchIcon } from 'lucide-react';
3
+ import { SettingsPage } from '@/shared/components/settings/settings-page';
4
+ import { NavigationLink } from '@/shared/components/actions/navigation-link';
5
+ import { Button } from '@/shared/components/ui/button';
6
+ import { FormActions } from '@/shared/components/ui/actions/form-actions';
7
+ import { Input } from '@/shared/components/ui/input';
8
+ import { Label } from '@/shared/components/ui/label';
9
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/shared/components/ui/select';
10
+ import { useConfig, useConfigMeta, useUpdateSearch } from '@/shared/hooks/use-config';
11
+ import { t } from '@/shared/lib/i18n';
12
+ import type { SearchConfigUpdate, SearchProviderName, TavilySearchDepthValue } from '@/shared/lib/api';
13
+ import {
14
+ ConfigSelectionCard,
15
+ ConfigSplitDetailPane,
16
+ ConfigSplitEmptyPane,
17
+ ConfigSplitPage,
18
+ ConfigSplitPaneBody,
19
+ ConfigSplitPaneFooter,
20
+ ConfigSplitPaneHeader,
21
+ ConfigSplitSidebar
22
+ } from '@/shared/components/config-split-page';
23
+ import { useViewportLayout } from '@/app/hooks/use-viewport-layout';
14
24
 
15
25
  const FRESHNESS_OPTIONS = [
16
- { value: "noLimit", label: "searchFreshnessNoLimit" },
17
- { value: "oneDay", label: "searchFreshnessOneDay" },
18
- { value: "oneWeek", label: "searchFreshnessOneWeek" },
19
- { value: "oneMonth", label: "searchFreshnessOneMonth" },
20
- { value: "oneYear", label: "searchFreshnessOneYear" },
26
+ { value: 'noLimit', label: 'searchFreshnessNoLimit' },
27
+ { value: 'oneDay', label: 'searchFreshnessOneDay' },
28
+ { value: 'oneWeek', label: 'searchFreshnessOneWeek' },
29
+ { value: 'oneMonth', label: 'searchFreshnessOneMonth' },
30
+ { value: 'oneYear', label: 'searchFreshnessOneYear' }
21
31
  ] as const;
22
32
 
23
33
  const SEARCH_DEPTH_OPTIONS = [
24
- { value: "basic", label: "searchDepthBasic" },
25
- { value: "advanced", label: "searchDepthAdvanced" },
34
+ { value: 'basic', label: 'searchDepthBasic' },
35
+ { value: 'advanced', label: 'searchDepthAdvanced' }
26
36
  ] as const;
27
37
 
28
38
  const ENABLED_OPTIONS = [
29
- { value: "true", label: "enabled" },
30
- { value: "false", label: "disabled" },
39
+ { value: 'true', label: 'enabled' },
40
+ { value: 'false', label: 'disabled' }
31
41
  ] as const;
32
42
 
33
43
  const SEARCH_PROVIDER_DESCRIPTION_KEYS: Record<SearchProviderName, string> = {
34
- bocha: "searchProviderBochaDescription",
35
- tavily: "searchProviderTavilyDescription",
36
- brave: "searchProviderBraveDescription",
44
+ bocha: 'searchProviderBochaDescription',
45
+ tavily: 'searchProviderTavilyDescription',
46
+ brave: 'searchProviderBraveDescription'
37
47
  };
38
48
 
39
49
  type SearchDraft = {
@@ -41,7 +51,12 @@ type SearchDraft = {
41
51
  enabledProviders: SearchProviderName[];
42
52
  maxResults: string;
43
53
  providers: {
44
- bocha: { apiKey: string; baseUrl: string; summary: boolean; freshness: string };
54
+ bocha: {
55
+ apiKey: string;
56
+ baseUrl: string;
57
+ summary: boolean;
58
+ freshness: string;
59
+ };
45
60
  tavily: {
46
61
  apiKey: string;
47
62
  baseUrl: string;
@@ -52,11 +67,11 @@ type SearchDraft = {
52
67
  };
53
68
  };
54
69
 
55
- type SearchView = NonNullable<ReturnType<typeof useConfig>["data"]>["search"];
56
- type SearchProviderMeta = NonNullable<ReturnType<typeof useConfigMeta>["data"]>["search"][number];
70
+ type SearchView = NonNullable<ReturnType<typeof useConfig>['data']>['search'];
71
+ type SearchProviderMeta = NonNullable<ReturnType<typeof useConfigMeta>['data']>['search'][number];
57
72
  type UpdateProviderDraft = <T extends SearchProviderName>(
58
73
  provider: T,
59
- patch: Partial<SearchDraft["providers"][T]>,
74
+ patch: Partial<SearchDraft['providers'][T]>
60
75
  ) => void;
61
76
 
62
77
  function buildSearchDraft(search: SearchView): SearchDraft {
@@ -66,19 +81,19 @@ function buildSearchDraft(search: SearchView): SearchDraft {
66
81
  maxResults: String(search.defaults.maxResults),
67
82
  providers: {
68
83
  bocha: {
69
- apiKey: "",
84
+ apiKey: '',
70
85
  baseUrl: search.providers.bocha.baseUrl,
71
86
  summary: Boolean(search.providers.bocha.summary),
72
- freshness: search.providers.bocha.freshness ?? "noLimit",
87
+ freshness: search.providers.bocha.freshness ?? 'noLimit'
73
88
  },
74
89
  tavily: {
75
- apiKey: "",
90
+ apiKey: '',
76
91
  baseUrl: search.providers.tavily.baseUrl,
77
- searchDepth: search.providers.tavily.searchDepth ?? "basic",
78
- includeAnswer: Boolean(search.providers.tavily.includeAnswer),
92
+ searchDepth: search.providers.tavily.searchDepth ?? 'basic',
93
+ includeAnswer: Boolean(search.providers.tavily.includeAnswer)
79
94
  },
80
- brave: { apiKey: "", baseUrl: search.providers.brave.baseUrl },
81
- },
95
+ brave: { apiKey: '', baseUrl: search.providers.brave.baseUrl }
96
+ }
82
97
  };
83
98
  }
84
99
 
@@ -92,19 +107,19 @@ function buildSearchPayload(draft: SearchDraft): SearchConfigUpdate {
92
107
  apiKey: draft.providers.bocha.apiKey || undefined,
93
108
  baseUrl: draft.providers.bocha.baseUrl,
94
109
  summary: draft.providers.bocha.summary,
95
- freshness: draft.providers.bocha.freshness,
110
+ freshness: draft.providers.bocha.freshness
96
111
  },
97
112
  tavily: {
98
113
  apiKey: draft.providers.tavily.apiKey || undefined,
99
114
  baseUrl: draft.providers.tavily.baseUrl,
100
115
  searchDepth: draft.providers.tavily.searchDepth,
101
- includeAnswer: draft.providers.tavily.includeAnswer,
116
+ includeAnswer: draft.providers.tavily.includeAnswer
102
117
  },
103
118
  brave: {
104
119
  apiKey: draft.providers.brave.apiKey || undefined,
105
- baseUrl: draft.providers.brave.baseUrl,
106
- },
107
- },
120
+ baseUrl: draft.providers.brave.baseUrl
121
+ }
122
+ }
108
123
  };
109
124
  }
110
125
 
@@ -114,11 +129,11 @@ function SearchTextField(props: {
114
129
  onChange: (value: string) => void;
115
130
  placeholder?: string;
116
131
  type?: string;
117
- inputMode?: "numeric";
132
+ inputMode?: 'numeric';
118
133
  }) {
119
- const { label, value, onChange, placeholder, type = "text", inputMode } = props;
134
+ const { label, value, onChange, placeholder, type = 'text', inputMode } = props;
120
135
  return (
121
- <div className="space-y-2">
136
+ <div className='space-y-2'>
122
137
  <Label>{label}</Label>
123
138
  <Input
124
139
  type={type}
@@ -126,7 +141,7 @@ function SearchTextField(props: {
126
141
  onChange={(event) => onChange(event.target.value)}
127
142
  placeholder={placeholder}
128
143
  inputMode={inputMode}
129
- className="rounded-xl"
144
+ className='rounded-xl'
130
145
  />
131
146
  </div>
132
147
  );
@@ -140,10 +155,10 @@ function SearchSelectField(props: {
140
155
  }) {
141
156
  const { label, value, options, onChange } = props;
142
157
  return (
143
- <div className="space-y-2">
158
+ <div className='space-y-2'>
144
159
  <Label>{label}</Label>
145
160
  <Select value={value} onValueChange={onChange}>
146
- <SelectTrigger className="rounded-xl">
161
+ <SelectTrigger className='rounded-xl'>
147
162
  <SelectValue />
148
163
  </SelectTrigger>
149
164
  <SelectContent>
@@ -158,15 +173,12 @@ function SearchSelectField(props: {
158
173
  );
159
174
  }
160
175
 
161
- function SearchDocsButton({ docsUrl }: { docsUrl?: string }) {
176
+ function SearchDocsLink({ docsUrl }: { docsUrl?: string }) {
162
177
  if (!docsUrl) return null;
163
178
  return (
164
- <a href={docsUrl} target="_blank" rel="noreferrer">
165
- <Button type="button" variant="outline" className="rounded-xl">
166
- <ExternalLink className="mr-2 h-4 w-4" />
167
- {t("searchProviderOpenDocs")}
168
- </Button>
169
- </a>
179
+ <NavigationLink href={docsUrl} external>
180
+ {t('searchProviderOpenDocs')}
181
+ </NavigationLink>
170
182
  );
171
183
  }
172
184
 
@@ -179,76 +191,76 @@ function SearchProviderFields(props: {
179
191
  }) {
180
192
  const { draft, provider, search, selectedDocsUrl, updateProviderDraft } = props;
181
193
 
182
- if (provider === "bocha") {
194
+ if (provider === 'bocha') {
183
195
  const { bocha } = draft.providers;
184
196
  return (
185
197
  <>
186
198
  <SearchTextField
187
- label={t("apiKey")}
199
+ label={t('apiKey')}
188
200
  value={bocha.apiKey}
189
- onChange={(apiKey) => updateProviderDraft("bocha", { apiKey })}
190
- placeholder={search.providers.bocha.apiKeyMasked || t("enterApiKey")}
191
- type="password"
201
+ onChange={(apiKey) => updateProviderDraft('bocha', { apiKey })}
202
+ placeholder={search.providers.bocha.apiKeyMasked || t('enterApiKey')}
203
+ type='password'
192
204
  />
193
205
  <SearchTextField
194
- label={t("searchProviderBaseUrl")}
206
+ label={t('searchProviderBaseUrl')}
195
207
  value={bocha.baseUrl}
196
- onChange={(baseUrl) => updateProviderDraft("bocha", { baseUrl })}
208
+ onChange={(baseUrl) => updateProviderDraft('bocha', { baseUrl })}
197
209
  />
198
- <div className="grid gap-4 md:grid-cols-2">
210
+ <div className='grid gap-4 md:grid-cols-2'>
199
211
  <SearchSelectField
200
- label={t("searchProviderSummary")}
201
- value={bocha.summary ? "true" : "false"}
212
+ label={t('searchProviderSummary')}
213
+ value={bocha.summary ? 'true' : 'false'}
202
214
  options={ENABLED_OPTIONS}
203
- onChange={(value) => updateProviderDraft("bocha", { summary: value === "true" })}
215
+ onChange={(value) => updateProviderDraft('bocha', { summary: value === 'true' })}
204
216
  />
205
217
  <SearchSelectField
206
- label={t("searchProviderFreshness")}
218
+ label={t('searchProviderFreshness')}
207
219
  value={bocha.freshness}
208
220
  options={FRESHNESS_OPTIONS}
209
- onChange={(freshness) => updateProviderDraft("bocha", { freshness })}
221
+ onChange={(freshness) => updateProviderDraft('bocha', { freshness })}
210
222
  />
211
223
  </div>
212
- <SearchDocsButton docsUrl={selectedDocsUrl ?? "https://open.bocha.cn"} />
224
+ <SearchDocsLink docsUrl={selectedDocsUrl ?? 'https://open.bocha.cn'} />
213
225
  </>
214
226
  );
215
227
  }
216
228
 
217
- if (provider === "tavily") {
229
+ if (provider === 'tavily') {
218
230
  const { tavily } = draft.providers;
219
231
  return (
220
232
  <>
221
233
  <SearchTextField
222
- label={t("apiKey")}
234
+ label={t('apiKey')}
223
235
  value={tavily.apiKey}
224
- onChange={(apiKey) => updateProviderDraft("tavily", { apiKey })}
225
- placeholder={search.providers.tavily.apiKeyMasked || t("enterApiKey")}
226
- type="password"
236
+ onChange={(apiKey) => updateProviderDraft('tavily', { apiKey })}
237
+ placeholder={search.providers.tavily.apiKeyMasked || t('enterApiKey')}
238
+ type='password'
227
239
  />
228
240
  <SearchTextField
229
- label={t("searchProviderBaseUrl")}
241
+ label={t('searchProviderBaseUrl')}
230
242
  value={tavily.baseUrl}
231
- onChange={(baseUrl) => updateProviderDraft("tavily", { baseUrl })}
243
+ onChange={(baseUrl) => updateProviderDraft('tavily', { baseUrl })}
232
244
  />
233
- <div className="grid gap-4 md:grid-cols-2">
245
+ <div className='grid gap-4 md:grid-cols-2'>
234
246
  <SearchSelectField
235
- label={t("searchProviderSearchDepth")}
247
+ label={t('searchProviderSearchDepth')}
236
248
  value={tavily.searchDepth}
237
249
  options={SEARCH_DEPTH_OPTIONS}
238
250
  onChange={(searchDepth) =>
239
- updateProviderDraft("tavily", { searchDepth: searchDepth as TavilySearchDepthValue })
251
+ updateProviderDraft('tavily', {
252
+ searchDepth: searchDepth as TavilySearchDepthValue
253
+ })
240
254
  }
241
255
  />
242
256
  <SearchSelectField
243
- label={t("searchProviderIncludeAnswer")}
244
- value={tavily.includeAnswer ? "true" : "false"}
257
+ label={t('searchProviderIncludeAnswer')}
258
+ value={tavily.includeAnswer ? 'true' : 'false'}
245
259
  options={ENABLED_OPTIONS}
246
- onChange={(value) =>
247
- updateProviderDraft("tavily", { includeAnswer: value === "true" })
248
- }
260
+ onChange={(value) => updateProviderDraft('tavily', { includeAnswer: value === 'true' })}
249
261
  />
250
262
  </div>
251
- <SearchDocsButton docsUrl={selectedDocsUrl} />
263
+ <SearchDocsLink docsUrl={selectedDocsUrl} />
252
264
  </>
253
265
  );
254
266
  }
@@ -257,16 +269,16 @@ function SearchProviderFields(props: {
257
269
  return (
258
270
  <>
259
271
  <SearchTextField
260
- label={t("apiKey")}
272
+ label={t('apiKey')}
261
273
  value={brave.apiKey}
262
- onChange={(apiKey) => updateProviderDraft("brave", { apiKey })}
263
- placeholder={search.providers.brave.apiKeyMasked || t("enterApiKey")}
264
- type="password"
274
+ onChange={(apiKey) => updateProviderDraft('brave', { apiKey })}
275
+ placeholder={search.providers.brave.apiKeyMasked || t('enterApiKey')}
276
+ type='password'
265
277
  />
266
278
  <SearchTextField
267
- label={t("searchProviderBaseUrl")}
279
+ label={t('searchProviderBaseUrl')}
268
280
  value={brave.baseUrl}
269
- onChange={(baseUrl) => updateProviderDraft("brave", { baseUrl })}
281
+ onChange={(baseUrl) => updateProviderDraft('brave', { baseUrl })}
270
282
  />
271
283
  </>
272
284
  );
@@ -282,12 +294,10 @@ function SearchProviderSidebar(props: {
282
294
  const { draft, providers, search, selectedProvider, onSelect } = props;
283
295
  return (
284
296
  <ConfigSplitSidebar>
285
- <ConfigSplitPaneHeader className="px-4 py-4">
286
- <p className="text-xs font-semibold uppercase tracking-[0.16em] text-gray-500">
287
- {t("searchChannels")}
288
- </p>
297
+ <ConfigSplitPaneHeader className='px-4 py-4'>
298
+ <p className='text-xs font-semibold uppercase tracking-[0.16em] text-muted-foreground'>{t('searchChannels')}</p>
289
299
  </ConfigSplitPaneHeader>
290
- <ConfigSplitPaneBody className="space-y-2 p-3">
300
+ <ConfigSplitPaneBody className='space-y-2 p-3'>
291
301
  {providers.map((provider) => {
292
302
  const providerView = search.providers[provider.name];
293
303
  const isEnabled = draft.enabledProviders.includes(provider.name);
@@ -296,26 +306,22 @@ function SearchProviderSidebar(props: {
296
306
  key={provider.name}
297
307
  onClick={() => onSelect(provider.name)}
298
308
  active={selectedProvider === provider.name}
299
- className="p-3"
309
+ className='p-3'
300
310
  >
301
- <div className="flex items-start justify-between gap-3">
302
- <div className="min-w-0">
303
- <p className="truncate text-sm font-semibold text-gray-900">
304
- {provider.displayName}
305
- </p>
306
- <p className="line-clamp-2 text-[11px] text-gray-500">
311
+ <div className='flex items-start justify-between gap-3'>
312
+ <div className='min-w-0'>
313
+ <p className='truncate text-sm font-semibold text-foreground'>{provider.displayName}</p>
314
+ <p className='line-clamp-2 text-[11px] text-muted-foreground'>
307
315
  {t(SEARCH_PROVIDER_DESCRIPTION_KEYS[provider.name])}
308
316
  </p>
309
317
  </div>
310
- <div className="flex flex-col items-end gap-1">
311
- <span className="rounded-full bg-gray-100 px-2 py-0.5 text-[11px] font-medium text-gray-600">
312
- {providerView.apiKeySet
313
- ? t("searchStatusConfigured")
314
- : t("searchStatusNeedsSetup")}
318
+ <div className='flex flex-col items-end gap-1'>
319
+ <span className='rounded-full bg-muted px-2 py-0.5 text-[11px] font-medium text-muted-foreground'>
320
+ {providerView.apiKeySet ? t('searchStatusConfigured') : t('searchStatusNeedsSetup')}
315
321
  </span>
316
322
  {isEnabled ? (
317
- <span className="rounded-full bg-emerald-50 px-2 py-0.5 text-[11px] font-medium text-emerald-700">
318
- {t("searchProviderActivated")}
323
+ <span className='rounded-full bg-emerald-50 px-2 py-0.5 text-[11px] font-medium text-emerald-700'>
324
+ {t('searchProviderActivated')}
319
325
  </span>
320
326
  ) : null}
321
327
  </div>
@@ -337,9 +343,7 @@ function SearchConfigForm(props: {
337
343
  }) {
338
344
  const { initialDraft, providers, search, onSubmit, isPending } = props;
339
345
  const { isMobile } = useViewportLayout();
340
- const [selectedProvider, setSelectedProvider] = useState<SearchProviderName | null>(
341
- isMobile ? null : search.provider,
342
- );
346
+ const [selectedProvider, setSelectedProvider] = useState<SearchProviderName | null>(null);
343
347
  const [draft, setDraft] = useState(initialDraft);
344
348
  const resolvedSelectedProvider =
345
349
  selectedProvider && providers.some((provider) => provider.name === selectedProvider)
@@ -347,14 +351,9 @@ function SearchConfigForm(props: {
347
351
  : isMobile
348
352
  ? null
349
353
  : search.provider;
350
- const selectedMeta =
351
- providers.find((provider) => provider.name === resolvedSelectedProvider) ?? null;
352
- const selectedView = resolvedSelectedProvider
353
- ? search.providers[resolvedSelectedProvider]
354
- : null;
355
- const selectedEnabled = resolvedSelectedProvider
356
- ? draft.enabledProviders.includes(resolvedSelectedProvider)
357
- : false;
354
+ const selectedMeta = providers.find((provider) => provider.name === resolvedSelectedProvider) ?? null;
355
+ const selectedView = resolvedSelectedProvider ? search.providers[resolvedSelectedProvider] : null;
356
+ const selectedEnabled = resolvedSelectedProvider ? draft.enabledProviders.includes(resolvedSelectedProvider) : false;
358
357
  const selectedDocsUrl = selectedView?.docsUrl ?? selectedMeta?.docsUrl;
359
358
 
360
359
  const updateProviderDraft: UpdateProviderDraft = (provider, patch) => {
@@ -362,8 +361,8 @@ function SearchConfigForm(props: {
362
361
  ...prev,
363
362
  providers: {
364
363
  ...prev.providers,
365
- [provider]: { ...prev.providers[provider], ...patch },
366
- },
364
+ [provider]: { ...prev.providers[provider], ...patch }
365
+ }
367
366
  }));
368
367
  };
369
368
 
@@ -380,10 +379,10 @@ function SearchConfigForm(props: {
380
379
 
381
380
  return (
382
381
  <ConfigSplitPage
383
- className="xl:min-h-0"
384
- mobileView={isMobile ? (resolvedSelectedProvider ? "detail" : "list") : undefined}
382
+ className='md:min-h-0'
383
+ compactView={selectedProvider ? 'detail' : 'list'}
385
384
  onMobileBack={() => setSelectedProvider(null)}
386
- mobileListLabel={t("searchPageTitle")}
385
+ mobileListLabel={t('searchPageTitle')}
387
386
  >
388
387
  <SearchProviderSidebar
389
388
  draft={draft}
@@ -394,7 +393,7 @@ function SearchConfigForm(props: {
394
393
  />
395
394
  {!selectedMeta ? (
396
395
  <ConfigSplitEmptyPane>
397
- <p className="text-sm text-gray-500">{t("searchNoProviderSelected")}</p>
396
+ <p className='text-sm text-muted-foreground'>{t('searchNoProviderSelected')}</p>
398
397
  </ConfigSplitEmptyPane>
399
398
  ) : (
400
399
  <ConfigSplitDetailPane>
@@ -403,48 +402,53 @@ function SearchConfigForm(props: {
403
402
  event.preventDefault();
404
403
  onSubmit(draft);
405
404
  }}
406
- className="flex min-h-0 flex-1 flex-col"
405
+ className='flex min-h-0 flex-1 flex-col'
407
406
  >
408
- <ConfigSplitPaneHeader className="px-6 py-5">
409
- <div className="flex items-start justify-between gap-4">
410
- <div className="flex items-center gap-3">
411
- <div className="flex h-10 w-10 items-center justify-center rounded-xl bg-primary text-white">
412
- <SearchIcon className="h-5 w-5" />
407
+ <ConfigSplitPaneHeader className='px-5 py-4'>
408
+ <div className='flex items-start justify-between gap-4'>
409
+ <div className='flex items-center gap-3'>
410
+ <div className='flex h-10 w-10 items-center justify-center rounded-xl bg-primary text-primary-foreground'>
411
+ <SearchIcon className='h-5 w-5' />
413
412
  </div>
414
413
  <div>
415
- <h3 className="text-lg font-semibold text-gray-900">{selectedMeta.displayName}</h3>
416
- <p className="text-sm text-gray-500">{selectedMeta.description}</p>
414
+ <h3 className='text-lg font-semibold text-foreground'>{selectedMeta.displayName}</h3>
415
+ <p className='text-sm text-muted-foreground'>
416
+ {t(SEARCH_PROVIDER_DESCRIPTION_KEYS[selectedMeta.name])}
417
+ </p>
417
418
  </div>
418
419
  </div>
419
420
  <Button
420
- type="button"
421
- variant={selectedEnabled ? "secondary" : "outline"}
422
- className="rounded-xl"
421
+ type='button'
422
+ variant={selectedEnabled ? 'secondary' : 'outline'}
423
+ className='rounded-xl'
423
424
  onClick={handleToggleEnabled}
424
425
  >
425
- {selectedEnabled ? t("searchProviderDeactivate") : t("searchProviderActivate")}
426
+ {selectedEnabled ? t('searchProviderDeactivate') : t('searchProviderActivate')}
426
427
  </Button>
427
428
  </div>
428
429
  </ConfigSplitPaneHeader>
429
430
 
430
- <ConfigSplitPaneBody className="space-y-6 px-6 py-5">
431
- <div className="grid gap-4 md:grid-cols-2">
431
+ <ConfigSplitPaneBody className='space-y-5 px-5 py-4'>
432
+ <div className='grid gap-4 md:grid-cols-2'>
432
433
  <SearchSelectField
433
- label={t("searchActiveProvider")}
434
+ label={t('searchActiveProvider')}
434
435
  value={draft.activeProvider}
435
436
  options={providers.map((provider) => ({
436
437
  value: provider.name,
437
- label: provider.displayName,
438
+ label: provider.displayName
438
439
  }))}
439
440
  onChange={(activeProvider) =>
440
- setDraft({ ...draft, activeProvider: activeProvider as SearchProviderName })
441
+ setDraft({
442
+ ...draft,
443
+ activeProvider: activeProvider as SearchProviderName
444
+ })
441
445
  }
442
446
  />
443
447
  <SearchTextField
444
- label={t("searchDefaultMaxResults")}
448
+ label={t('searchDefaultMaxResults')}
445
449
  value={draft.maxResults}
446
450
  onChange={(maxResults) => setDraft({ ...draft, maxResults })}
447
- inputMode="numeric"
451
+ inputMode='numeric'
448
452
  />
449
453
  </div>
450
454
 
@@ -459,9 +463,9 @@ function SearchConfigForm(props: {
459
463
 
460
464
  <ConfigSplitPaneFooter>
461
465
  <FormActions>
462
- <Button type="submit" size="sm" disabled={isPending}>
463
- <KeyRound className="mr-1.5 h-3.5 w-3.5" />
464
- {isPending ? t("saving") : t("saveChanges")}
466
+ <Button type='submit' size='sm' disabled={isPending}>
467
+ <KeyRound className='mr-1.5 h-3.5 w-3.5' />
468
+ {isPending ? t('saving') : t('saveChanges')}
465
469
  </Button>
466
470
  </FormActions>
467
471
  </ConfigSplitPaneFooter>
@@ -480,12 +484,15 @@ export function SearchConfigPage() {
480
484
  const search = config?.search;
481
485
 
482
486
  if (!search || providers.length === 0) {
483
- return <div className="p-8">{t("loading")}</div>;
487
+ return (
488
+ <SettingsPage title={t('searchPageTitle')} description={t('searchPageDescription')} layout='split'>
489
+ <div className='text-sm text-muted-foreground'>{t('loading')}</div>
490
+ </SettingsPage>
491
+ );
484
492
  }
485
493
 
486
494
  return (
487
- <PageLayout className="pb-0 xl:flex xl:h-full xl:min-h-0 xl:flex-col">
488
- <PageHeader title={t("searchPageTitle")} description={t("searchPageDescription")} />
495
+ <SettingsPage title={t('searchPageTitle')} description={t('searchPageDescription')} layout='split'>
489
496
  <SearchConfigForm
490
497
  key={JSON.stringify(search)}
491
498
  initialDraft={buildSearchDraft(search)}
@@ -494,6 +501,6 @@ export function SearchConfigPage() {
494
501
  onSubmit={(draft) => updateSearch.mutate({ data: buildSearchPayload(draft) })}
495
502
  isPending={updateSearch.isPending}
496
503
  />
497
- </PageLayout>
504
+ </SettingsPage>
498
505
  );
499
506
  }
@@ -2,13 +2,18 @@ import { useConfig, useUpdateSecrets } from '@/shared/hooks/use-config';
2
2
  import { t } from '@/shared/lib/i18n';
3
3
  import { SecretsConfigForm } from '@/features/settings/components/config/secrets-config-form';
4
4
  import { buildSecretsFormState, buildSecretsSubmitPayload } from '@/features/settings/utils/secrets-config-form.utils';
5
+ import { SettingsPage } from '@/shared/components/settings/settings-page';
5
6
 
6
7
  export function SecretsConfigPage() {
7
8
  const { data: config, isLoading } = useConfig();
8
9
  const updateSecrets = useUpdateSecrets();
9
10
 
10
11
  if (isLoading) {
11
- return <div className="p-8 text-gray-400">{t('loading')}</div>;
12
+ return (
13
+ <SettingsPage title={t('secretsPageTitle')} description={t('secretsPageDescription')}>
14
+ <div className='text-sm text-muted-foreground'>{t('loading')}</div>
15
+ </SettingsPage>
16
+ );
12
17
  }
13
18
 
14
19
  return (