@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,14 +1,14 @@
1
1
  import type { UpdateSnapshot } from '@nextclaw/shared';
2
2
  import { useQuery } from '@tanstack/react-query';
3
3
  import { runtimeUpdateManager, useRuntimeUpdateStore } from '@/features/system-status';
4
+ import { NavigationLink } from '@/shared/components/actions/navigation-link';
4
5
  import { Button } from '@/shared/components/ui/button';
5
6
  import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/shared/components/ui/card';
6
- import { Label } from '@/shared/components/ui/label';
7
+ import { SettingRow, SettingsGroup, SettingsSection } from '@/shared/components/settings/setting-row';
8
+ import { SettingsPage } from '@/shared/components/settings/settings-page';
7
9
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/shared/components/ui/select';
8
- import { PageHeader, PageLayout } from '@/app/components/layout/page-layout';
9
10
  import { formatDateTime, getLanguage, t } from '@/shared/lib/i18n';
10
11
  import { cn } from '@/shared/lib/utils';
11
- import { hostCapabilityManager } from '@/shared/lib/host-capabilities';
12
12
  import {
13
13
  fetchReleaseNotesData,
14
14
  readReleaseNotesText,
@@ -16,7 +16,7 @@ import {
16
16
  type ReleaseNotesLocale,
17
17
  type ReleaseNotesSection
18
18
  } from '@/features/system-status/utils/update-release-notes.utils';
19
- import { Download, ExternalLink, RefreshCw, RotateCw } from 'lucide-react';
19
+ import { Download, RefreshCw, RotateCw } from 'lucide-react';
20
20
 
21
21
  const STATUS_LABEL_KEYS: Record<string, string> = {
22
22
  checking: 'desktopUpdatesStatusChecking',
@@ -40,7 +40,12 @@ function StatusBadge({ snapshot }: { snapshot: UpdateSnapshot }) {
40
40
  }
41
41
 
42
42
  function OverviewStat({ label, value }: { label: string; value: string }) {
43
- return <div className="rounded-xl border border-gray-200 bg-gray-50/60 p-4"><p className="text-xs font-medium uppercase tracking-[0.08em] text-gray-500">{label}</p><p className="mt-2 text-base font-semibold text-gray-900">{value}</p></div>;
43
+ return (
44
+ <div className='rounded-lg bg-background/70 p-3'>
45
+ <p className='text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground'>{label}</p>
46
+ <p className='mt-1 text-sm font-semibold text-foreground'>{value}</p>
47
+ </div>
48
+ );
44
49
  }
45
50
 
46
51
  function DownloadProgress({ snapshot }: { snapshot: UpdateSnapshot }) {
@@ -53,13 +58,13 @@ function DownloadProgress({ snapshot }: { snapshot: UpdateSnapshot }) {
53
58
  : t('desktopUpdatesDownloadProgressPercent').replace('{percent}', String(percent));
54
59
  const byteLabel = formatDownloadBytes(snapshot.progress?.downloadedBytes ?? 0, snapshot.progress?.totalBytes ?? null);
55
60
  return (
56
- <div className="rounded-2xl border border-amber-200 bg-amber-50/70 p-4">
57
- <div className="flex items-center justify-between gap-4">
58
- <p className="text-sm font-semibold text-amber-800">{progressLabel}</p>
59
- <p className="text-xs font-medium text-amber-700">{byteLabel}</p>
61
+ <div className='rounded-2xl border border-amber-200 bg-amber-50/70 p-4'>
62
+ <div className='flex items-center justify-between gap-4'>
63
+ <p className='text-sm font-semibold text-amber-800'>{progressLabel}</p>
64
+ <p className='text-xs font-medium text-amber-700'>{byteLabel}</p>
60
65
  </div>
61
- <div className="mt-3 h-2 overflow-hidden rounded-full bg-amber-100">
62
- <div className="h-full rounded-full bg-amber-500 transition-[width]" style={{ width: `${percent ?? 0}%` }} />
66
+ <div className='mt-3 h-2 overflow-hidden rounded-full bg-amber-100'>
67
+ <div className='h-full rounded-full bg-amber-500 transition-[width]' style={{ width: `${percent ?? 0}%` }} />
63
68
  </div>
64
69
  </div>
65
70
  );
@@ -140,37 +145,36 @@ function ReleaseNotesPreview({ snapshot }: { snapshot: UpdateSnapshot }) {
140
145
  return (
141
146
  <Card>
142
147
  <CardHeader>
143
- <div className="flex flex-wrap items-start justify-between gap-3">
144
- <div className="space-y-1">
148
+ <div className='flex flex-wrap items-start justify-between gap-3'>
149
+ <div className='space-y-1'>
145
150
  <CardTitle>{title}</CardTitle>
146
151
  <CardDescription>{summary}</CardDescription>
147
152
  </div>
148
- <Button variant="ghost" onClick={() => void hostCapabilityManager.openExternalUrl(snapshot.releaseNotesUrl ?? '')}>
149
- <ExternalLink className="mr-2 h-4 w-4" />
153
+ <NavigationLink href={snapshot.releaseNotesUrl} external>
150
154
  {t('desktopUpdatesReleaseNotes')}
151
- </Button>
155
+ </NavigationLink>
152
156
  </div>
153
157
  </CardHeader>
154
- <CardContent className="space-y-4">
158
+ <CardContent className='space-y-4'>
155
159
  {releaseNotesQuery.isLoading ? (
156
- <p className="text-sm text-gray-500">{t('desktopUpdatesReleaseNotesPreviewLoading')}</p>
160
+ <p className='text-sm text-gray-500'>{t('desktopUpdatesReleaseNotesPreviewLoading')}</p>
157
161
  ) : null}
158
162
  {!dataUrl || releaseNotesQuery.isError ? (
159
- <p className="text-sm text-gray-500">{t('desktopUpdatesReleaseNotesPreviewUnavailable')}</p>
163
+ <p className='text-sm text-gray-500'>{t('desktopUpdatesReleaseNotesPreviewUnavailable')}</p>
160
164
  ) : null}
161
165
  {payload ? (
162
- <div className="grid gap-4 md:grid-cols-2">
166
+ <div className='grid gap-4 md:grid-cols-2'>
163
167
  {payload.sections.map((section) => (
164
- <div key={section.kind} className="rounded-xl border border-gray-200 bg-gray-50/60 p-4">
165
- <p className="text-sm font-semibold text-gray-900">{getReleaseNotesSectionTitle(section, locale)}</p>
166
- <ul className="mt-3 space-y-3">
168
+ <div key={section.kind} className='rounded-xl border border-gray-200 bg-gray-50/60 p-4'>
169
+ <p className='text-sm font-semibold text-gray-900'>{getReleaseNotesSectionTitle(section, locale)}</p>
170
+ <ul className='mt-3 space-y-3'>
167
171
  {section.items.map((item, index) => {
168
172
  const itemTitle = readReleaseNotesText(item.title, locale);
169
173
  const itemBody = readReleaseNotesText(item.body, locale);
170
174
  return (
171
- <li key={`${itemTitle ?? section.kind}-${index}`} className="space-y-1">
172
- {itemTitle ? <p className="text-sm font-medium text-gray-800">{itemTitle}</p> : null}
173
- {itemBody ? <p className="text-sm leading-5 text-gray-600">{itemBody}</p> : null}
175
+ <li key={`${itemTitle ?? section.kind}-${index}`} className='space-y-1'>
176
+ {itemTitle ? <p className='text-sm font-medium text-gray-800'>{itemTitle}</p> : null}
177
+ {itemBody ? <p className='text-sm leading-5 text-gray-600'>{itemBody}</p> : null}
174
178
  </li>
175
179
  );
176
180
  })}
@@ -186,23 +190,27 @@ function ReleaseNotesPreview({ snapshot }: { snapshot: UpdateSnapshot }) {
186
190
 
187
191
  function RuntimeUpdateUnavailableState() {
188
192
  return (
189
- <PageLayout className="space-y-6">
190
- <PageHeader title={t('runtimeUpdatesPageTitle')} description={t('runtimeUpdatesPageDescription')} />
191
- <Card>
192
- <CardHeader>
193
- <CardTitle>{t('runtimeUpdatesUnavailableTitle')}</CardTitle>
194
- <CardDescription>{t('runtimeUpdatesUnavailableDescription')}</CardDescription>
195
- </CardHeader>
196
- <CardContent><p className="text-sm text-gray-500">{t('runtimeUpdatesUnavailableHint')}</p></CardContent>
197
- </Card>
198
- </PageLayout>
193
+ <SettingsPage title={t('runtimeUpdatesPageTitle')} description={t('runtimeUpdatesPageDescription')}>
194
+ <SettingsSection
195
+ title={t('runtimeUpdatesUnavailableTitle')}
196
+ description={t('runtimeUpdatesUnavailableDescription')}
197
+ >
198
+ <SettingsGroup>
199
+ <p className='p-4 text-sm text-muted-foreground'>{t('runtimeUpdatesUnavailableHint')}</p>
200
+ </SettingsGroup>
201
+ </SettingsSection>
202
+ </SettingsPage>
199
203
  );
200
204
  }
201
205
 
202
206
  export function DesktopUpdateConfig() {
203
207
  const { supported, initialized, busyAction, snapshot } = useRuntimeUpdateStore();
204
208
  if (!initialized) {
205
- return <div className="p-8 text-gray-400">{t('loading')}</div>;
209
+ return (
210
+ <SettingsPage title={t('runtimeUpdatesPageTitle')} description={t('runtimeUpdatesPageDescription')}>
211
+ <div className='text-sm text-muted-foreground'>{t('loading')}</div>
212
+ </SettingsPage>
213
+ );
206
214
  }
207
215
  if (!supported || !snapshot) {
208
216
  return <RuntimeUpdateUnavailableState />;
@@ -221,90 +229,87 @@ export function DesktopUpdateConfig() {
221
229
  [t('desktopUpdatesCurrentChannel'), getChannelLabel(snapshot.channel)],
222
230
  ] as const;
223
231
  return (
224
- <PageLayout className="space-y-6">
225
- <PageHeader
226
- title={t('runtimeUpdatesPageTitle')}
227
- description={t('runtimeUpdatesPageDescription')}
228
- actions={<Button variant="outline" onClick={() => void runtimeUpdateManager.checkForUpdates()} disabled={isChecking || isDownloading || isApplying}><RefreshCw className={cn('mr-2 h-4 w-4', isChecking && 'animate-spin')} />{t('desktopUpdatesCheckNow')}</Button>}
229
- />
230
- <Card>
231
- <CardHeader>
232
- <CardTitle>{t('desktopUpdatesOverviewTitle')}</CardTitle>
233
- <CardDescription>{t('desktopUpdatesOverviewDescription')}</CardDescription>
234
- </CardHeader>
235
- <CardContent className="space-y-5">
236
- <div className="flex flex-wrap items-center gap-3"><span className="text-sm font-medium text-gray-700">{t('desktopUpdatesStatusLabel')}</span><StatusBadge snapshot={snapshot} /></div>
237
- <div className="grid gap-4 md:grid-cols-2 xl:grid-cols-5">{overviewStats.map(([label, value]) => <OverviewStat key={label} label={label} value={value} />)}</div>
238
- {snapshot.channel === 'beta' ? (
239
- <div className="rounded-2xl border border-amber-200 bg-amber-50/70 p-4">
240
- <p className="text-sm font-semibold text-amber-800">{t('desktopUpdatesBetaBadgeTitle')}</p>
241
- <p className="mt-1 text-sm text-amber-700">{t('desktopUpdatesBetaBadgeDescription')}</p>
242
- </div>
243
- ) : null}
244
- {snapshot.downloadedVersion ? (
245
- <div className="rounded-2xl border border-emerald-200 bg-emerald-50/70 p-4">
246
- <p className="text-sm font-semibold text-emerald-800">{t('desktopUpdatesDownloadedBannerTitle')}</p>
247
- <p className="mt-1 text-sm text-emerald-700">{t('runtimeUpdatesDownloadedBannerDescription').replace('{version}', snapshot.downloadedVersion)}</p>
248
- </div>
249
- ) : null}
250
- <DownloadProgress snapshot={snapshot} />
251
- {snapshot.status === 'blocked' ? (
252
- <div className="rounded-2xl border border-red-200 bg-red-50/70 p-4">
253
- <p className="text-sm font-semibold text-red-800">{t('desktopUpdatesBlockedTitle')}</p>
254
- <p className="mt-1 text-sm text-red-700">{snapshot.errorMessage ?? t('desktopUpdatesBlockedDescription')}</p>
255
- {snapshot.recoveryCommand ? <code className="mt-3 block rounded-lg bg-white/70 px-3 py-2 text-xs text-red-800">{snapshot.recoveryCommand}</code> : null}
232
+ <SettingsPage
233
+ title={t('runtimeUpdatesPageTitle')}
234
+ description={t('runtimeUpdatesPageDescription')}
235
+ actions={<Button variant='outline' onClick={() => void runtimeUpdateManager.checkForUpdates()} disabled={isChecking || isDownloading || isApplying}><RefreshCw className={cn('mr-2 h-4 w-4', isChecking && 'animate-spin')} />{t('desktopUpdatesCheckNow')}</Button>}
236
+ >
237
+ <SettingsSection title={t('desktopUpdatesOverviewTitle')} description={t('desktopUpdatesOverviewDescription')}>
238
+ <SettingsGroup>
239
+ <div className='space-y-4 p-4'>
240
+ <div className='flex flex-wrap items-center gap-3'>
241
+ <span className='text-sm font-medium text-foreground'>{t('desktopUpdatesStatusLabel')}</span>
242
+ <StatusBadge snapshot={snapshot} />
256
243
  </div>
257
- ) : null}
258
- {snapshot.errorMessage && snapshot.status !== 'blocked' ? <div className="rounded-2xl border border-red-200 bg-red-50/70 p-4 text-sm text-red-700">{snapshot.errorMessage}</div> : null}
259
- </CardContent>
260
- </Card>
261
- <ReleaseNotesPreview snapshot={snapshot} />
262
- <Card>
263
- <CardHeader>
264
- <CardTitle>{t('desktopUpdatesChannelSettingsTitle')}</CardTitle>
265
- <CardDescription>{t('desktopUpdatesChannelSettingsDescription')}</CardDescription>
266
- </CardHeader>
267
- <CardContent className="space-y-5">
268
- <div className="rounded-xl border border-gray-200 p-4">
269
- <div className="space-y-3">
270
- <div className="space-y-1">
271
- <Label>{t('desktopUpdatesReleaseChannel')}</Label>
272
- <p className="text-sm text-gray-500">{t('desktopUpdatesReleaseChannelHelp')}</p>
244
+ <div className='grid gap-4 md:grid-cols-2 xl:grid-cols-5'>{overviewStats.map(([label, value]) => <OverviewStat key={label} label={label} value={value} />)}</div>
245
+ {snapshot.channel === 'beta' ? (
246
+ <div className='rounded-2xl border border-amber-200 bg-amber-50/70 p-4'>
247
+ <p className='text-sm font-semibold text-amber-800'>{t('desktopUpdatesBetaBadgeTitle')}</p>
248
+ <p className='mt-1 text-sm text-amber-700'>{t('desktopUpdatesBetaBadgeDescription')}</p>
249
+ </div>
250
+ ) : null}
251
+ {snapshot.downloadedVersion ? (
252
+ <div className='rounded-2xl border border-emerald-200 bg-emerald-50/70 p-4'>
253
+ <p className='text-sm font-semibold text-emerald-800'>{t('desktopUpdatesDownloadedBannerTitle')}</p>
254
+ <p className='mt-1 text-sm text-emerald-700'>{t('runtimeUpdatesDownloadedBannerDescription').replace('{version}', snapshot.downloadedVersion)}</p>
255
+ </div>
256
+ ) : null}
257
+ <DownloadProgress snapshot={snapshot} />
258
+ {snapshot.status === 'blocked' ? (
259
+ <div className='rounded-2xl border border-red-200 bg-red-50/70 p-4'>
260
+ <p className='text-sm font-semibold text-red-800'>{t('desktopUpdatesBlockedTitle')}</p>
261
+ <p className='mt-1 text-sm text-red-700'>{snapshot.errorMessage ?? t('desktopUpdatesBlockedDescription')}</p>
262
+ {snapshot.recoveryCommand ? <code className='mt-3 block rounded-lg bg-white/70 px-3 py-2 text-xs text-red-800'>{snapshot.recoveryCommand}</code> : null}
273
263
  </div>
264
+ ) : null}
265
+ {snapshot.errorMessage && snapshot.status !== 'blocked' ? <div className='rounded-2xl border border-red-200 bg-red-50/70 p-4 text-sm text-red-700'>{snapshot.errorMessage}</div> : null}
266
+ </div>
267
+ </SettingsGroup>
268
+ </SettingsSection>
269
+ <ReleaseNotesPreview snapshot={snapshot} />
270
+ <SettingsSection
271
+ title={t('desktopUpdatesChannelSettingsTitle')}
272
+ description={t('desktopUpdatesChannelSettingsDescription')}
273
+ >
274
+ <SettingsGroup>
275
+ <SettingRow
276
+ title={t('desktopUpdatesReleaseChannel')}
277
+ description={t('desktopUpdatesReleaseChannelHelp')}
278
+ layout='stacked'
279
+ >
280
+ <div className='space-y-2'>
274
281
  <Select value={snapshot.channel} disabled={isSwitchingChannel || isChecking || isDownloading || isApplying} onValueChange={(value) => void runtimeUpdateManager.updateChannel(value as UpdateSnapshot['channel'])}>
275
- <SelectTrigger className="w-full max-w-sm">
282
+ <SelectTrigger className='w-full max-w-sm'>
276
283
  <SelectValue placeholder={t('desktopUpdatesReleaseChannel')} />
277
284
  </SelectTrigger>
278
285
  <SelectContent>
279
- <SelectItem value="stable">{t('desktopUpdatesChannelStable')}</SelectItem>
280
- <SelectItem value="beta">{t('desktopUpdatesChannelBeta')}</SelectItem>
286
+ <SelectItem value='stable'>{t('desktopUpdatesChannelStable')}</SelectItem>
287
+ <SelectItem value='beta'>{t('desktopUpdatesChannelBeta')}</SelectItem>
281
288
  </SelectContent>
282
289
  </Select>
283
- <p className="text-sm text-gray-500">{t('desktopUpdatesReleaseChannelDowngradeHint')}</p>
290
+ <p className='text-xs text-muted-foreground'>{t('desktopUpdatesReleaseChannelDowngradeHint')}</p>
284
291
  </div>
292
+ </SettingRow>
293
+ </SettingsGroup>
294
+ </SettingsSection>
295
+ <SettingsSection title={t('desktopUpdatesActionsTitle')} description={t('runtimeUpdatesActionsDescription')}>
296
+ <SettingsGroup>
297
+ <div className='flex flex-wrap items-center gap-3 p-4'>
298
+ <Button variant='outline' onClick={() => void runtimeUpdateManager.checkForUpdates()} disabled={isChecking || isDownloading || isApplying}>
299
+ <RefreshCw className={cn('mr-2 h-4 w-4', isChecking && 'animate-spin')} />
300
+ {t('desktopUpdatesCheckNow')}
301
+ </Button>
302
+ <Button onClick={() => void runtimeUpdateManager.downloadUpdate()} disabled={!canDownload}>
303
+ <Download className={cn('mr-2 h-4 w-4', isDownloading && 'animate-bounce')} />
304
+ {t('desktopUpdatesDownloadNow')}
305
+ </Button>
306
+ <Button variant='secondary' onClick={() => void runtimeUpdateManager.applyDownloadedUpdate()} disabled={!canApply}>
307
+ <RotateCw className={cn('mr-2 h-4 w-4', isApplying && 'animate-spin')} />
308
+ {t('runtimeUpdatesApplyNow')}
309
+ </Button>
285
310
  </div>
286
- </CardContent>
287
- </Card>
288
- <Card>
289
- <CardHeader>
290
- <CardTitle>{t('desktopUpdatesActionsTitle')}</CardTitle>
291
- <CardDescription>{t('runtimeUpdatesActionsDescription')}</CardDescription>
292
- </CardHeader>
293
- <CardContent className="flex flex-wrap items-center gap-3">
294
- <Button variant="outline" onClick={() => void runtimeUpdateManager.checkForUpdates()} disabled={isChecking || isDownloading || isApplying}>
295
- <RefreshCw className={cn('mr-2 h-4 w-4', isChecking && 'animate-spin')} />
296
- {t('desktopUpdatesCheckNow')}
297
- </Button>
298
- <Button onClick={() => void runtimeUpdateManager.downloadUpdate()} disabled={!canDownload}>
299
- <Download className={cn('mr-2 h-4 w-4', isDownloading && 'animate-bounce')} />
300
- {t('desktopUpdatesDownloadNow')}
301
- </Button>
302
- <Button variant="secondary" onClick={() => void runtimeUpdateManager.applyDownloadedUpdate()} disabled={!canApply}>
303
- <RotateCw className={cn('mr-2 h-4 w-4', isApplying && 'animate-spin')} />
304
- {t('runtimeUpdatesApplyNow')}
305
- </Button>
306
- </CardContent>
307
- </Card>
308
- </PageLayout>
311
+ </SettingsGroup>
312
+ </SettingsSection>
313
+ </SettingsPage>
309
314
  );
310
315
  }
@@ -6,7 +6,7 @@ import type {
6
6
  RuntimeServiceState
7
7
  } from '@/shared/lib/api';
8
8
  import { Button } from '@/shared/components/ui/button';
9
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/shared/components/ui/card';
9
+ import { SettingsGroup, SettingsSection } from '@/shared/components/settings/setting-row';
10
10
  import { useRuntimeControlPanelView, systemStatusManager } from '@/features/system-status';
11
11
  import { localizeRuntimeControlMessage } from '@/features/system-status/utils/system-status.utils';
12
12
  import { t } from '@/shared/lib/i18n';
@@ -111,15 +111,15 @@ function resolveVisibleActions(controlView: RuntimeControlView | undefined): Vis
111
111
  function RuntimeActionIcon(props: { icon: VisibleRuntimeAction['icon']; busy: boolean }) {
112
112
  const { busy, icon } = props;
113
113
  if (busy) {
114
- return <Loader2 className="mr-2 h-4 w-4 animate-spin" />;
114
+ return <Loader2 className='mr-2 h-4 w-4 animate-spin' />;
115
115
  }
116
116
  if (icon === 'play') {
117
- return <Play className="mr-2 h-4 w-4" />;
117
+ return <Play className='mr-2 h-4 w-4' />;
118
118
  }
119
119
  if (icon === 'square') {
120
- return <Square className="mr-2 h-4 w-4" />;
120
+ return <Square className='mr-2 h-4 w-4' />;
121
121
  }
122
- return <RotateCw className="mr-2 h-4 w-4" />;
122
+ return <RotateCw className='mr-2 h-4 w-4' />;
123
123
  }
124
124
 
125
125
  export function RuntimeControlCard() {
@@ -163,7 +163,10 @@ export function RuntimeControlCard() {
163
163
 
164
164
  const handleRestartApp = async () => {
165
165
  if (!controlView?.canRestartApp.available) {
166
- toast.error(localizeRuntimeControlMessage(controlView?.canRestartApp.reasonIfUnavailable) ?? t('runtimeRestartAppUnavailable'));
166
+ toast.error(
167
+ localizeRuntimeControlMessage(controlView?.canRestartApp.reasonIfUnavailable) ??
168
+ t('runtimeRestartAppUnavailable')
169
+ );
167
170
  return;
168
171
  }
169
172
  if (!window.confirm(t('runtimeControlRestartAppConfirm'))) {
@@ -180,39 +183,37 @@ export function RuntimeControlCard() {
180
183
  };
181
184
 
182
185
  return (
183
- <Card>
184
- <CardHeader>
185
- <CardTitle>{t('runtimeControlTitle')}</CardTitle>
186
- <CardDescription>{t('runtimeControlDescription')}</CardDescription>
187
- </CardHeader>
188
- <CardContent className="space-y-4">
189
- <div className="space-y-3 rounded-xl border border-gray-200 bg-gray-50 p-4">
190
- <div className="flex flex-col gap-1 md:flex-row md:items-center md:justify-between">
191
- <div className="text-sm font-medium text-gray-900">{resolveServiceStateLabel(displayedServiceState)}</div>
192
- <div className="text-xs text-gray-500">
186
+ <SettingsSection title={t('runtimeControlTitle')} description={t('runtimeControlDescription')}>
187
+ <SettingsGroup>
188
+ <div className='space-y-3 p-4'>
189
+ <div className='flex flex-col gap-1 md:flex-row md:items-center md:justify-between'>
190
+ <div className='text-sm font-medium text-foreground'>{resolveServiceStateLabel(displayedServiceState)}</div>
191
+ <div className='text-xs text-muted-foreground'>
193
192
  {controlView ? resolveEnvironmentLabel(controlView) : t('runtimeControlLoading')}
194
193
  </div>
195
194
  </div>
196
- <p className="text-sm text-gray-600">{displayedMessage}</p>
197
- <div className="text-xs text-gray-500">{resolveLifecycleLabel(displayedLifecycle)}</div>
198
- {controlView?.managementHint ? <p className="text-xs text-gray-500">{localizeRuntimeControlMessage(controlView.managementHint)}</p> : null}
199
- {errorMessage && !busy ? <p className="text-sm text-amber-700">{errorMessage}</p> : null}
195
+ <p className='text-sm text-muted-foreground'>{displayedMessage}</p>
196
+ <div className='text-xs text-muted-foreground'>{resolveLifecycleLabel(displayedLifecycle)}</div>
197
+ {controlView?.managementHint ? (
198
+ <p className='text-xs text-muted-foreground'>{localizeRuntimeControlMessage(controlView.managementHint)}</p>
199
+ ) : null}
200
+ {errorMessage && !busy ? <p className='text-sm text-amber-700'>{errorMessage}</p> : null}
200
201
  </div>
201
202
 
202
203
  {pendingRestart ? (
203
- <div className="space-y-3 rounded-xl border border-amber-200 bg-amber-50 p-4">
204
- <div className="text-sm font-medium text-amber-900">{t('runtimeControlPendingRestartTitle')}</div>
205
- <p className="text-sm text-amber-800">{t('runtimeControlPendingRestartDescription')}</p>
204
+ <div className='space-y-3 bg-amber-50/75 p-4 dark:bg-amber-950/20'>
205
+ <div className='text-sm font-medium text-amber-900'>{t('runtimeControlPendingRestartTitle')}</div>
206
+ <p className='text-sm text-amber-800'>{t('runtimeControlPendingRestartDescription')}</p>
206
207
  {pendingRestart.changedPaths.length > 0 ? (
207
- <div className="space-y-2">
208
- <div className="text-xs font-medium uppercase tracking-[0.08em] text-amber-700">
208
+ <div className='space-y-2'>
209
+ <div className='text-xs font-medium uppercase tracking-[0.08em] text-amber-700'>
209
210
  {t('runtimeControlPendingRestartPaths')}
210
211
  </div>
211
- <div className="flex flex-wrap gap-2">
212
+ <div className='flex flex-wrap gap-2'>
212
213
  {pendingRestart.changedPaths.map((path) => (
213
214
  <span
214
215
  key={path}
215
- className="rounded-full border border-amber-200 bg-white px-2.5 py-1 text-xs text-amber-800"
216
+ className='rounded-full bg-background/80 px-2.5 py-1 text-xs text-amber-800 dark:text-amber-300'
216
217
  >
217
218
  {path}
218
219
  </span>
@@ -223,39 +224,41 @@ export function RuntimeControlCard() {
223
224
  </div>
224
225
  ) : null}
225
226
 
226
- <div className="flex flex-col gap-3 md:flex-row md:flex-wrap">
227
- {visibleActions.map((item) => {
228
- const handleClick = () => {
229
- if (item.action === 'restart-app') {
230
- void handleRestartApp();
231
- return;
232
- }
233
- void handleServiceAction(item.action);
234
- };
227
+ <div className='space-y-3 p-4'>
228
+ <div className='flex flex-col gap-3 md:flex-row md:flex-wrap'>
229
+ {visibleActions.map((item) => {
230
+ const handleClick = () => {
231
+ if (item.action === 'restart-app') {
232
+ void handleRestartApp();
233
+ return;
234
+ }
235
+ void handleServiceAction(item.action);
236
+ };
235
237
 
236
- return (
237
- <Button
238
- key={item.action}
239
- type="button"
240
- variant={item.variant ?? 'default'}
241
- onClick={handleClick}
242
- disabled={!item.capability.available || busy}
243
- >
244
- <RuntimeActionIcon icon={item.icon} busy={busyAction === item.action} />
245
- {item.label}
246
- </Button>
247
- );
248
- })}
249
- </div>
238
+ return (
239
+ <Button
240
+ key={item.action}
241
+ type='button'
242
+ variant={item.variant ?? 'default'}
243
+ onClick={handleClick}
244
+ disabled={!item.capability.available || busy}
245
+ >
246
+ <RuntimeActionIcon icon={item.icon} busy={busyAction === item.action} />
247
+ {item.label}
248
+ </Button>
249
+ );
250
+ })}
251
+ </div>
250
252
 
251
- {visibleActions
252
- .filter((item) => !item.capability.available && item.capability.reasonIfUnavailable)
253
- .map((item) => (
254
- <p key={`${item.action}-reason`} className="text-xs text-gray-500">
255
- {localizeRuntimeControlMessage(item.capability.reasonIfUnavailable)}
256
- </p>
257
- ))}
258
- </CardContent>
259
- </Card>
253
+ {visibleActions
254
+ .filter((item) => !item.capability.available && item.capability.reasonIfUnavailable)
255
+ .map((item) => (
256
+ <p key={`${item.action}-reason`} className='text-xs text-muted-foreground'>
257
+ {localizeRuntimeControlMessage(item.capability.reasonIfUnavailable)}
258
+ </p>
259
+ ))}
260
+ </div>
261
+ </SettingsGroup>
262
+ </SettingsSection>
260
263
  );
261
264
  }