@nextclaw/ui 0.26.5 → 0.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (433) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/dist/.vite/manifest.json +1342 -1227
  3. package/dist/assets/{abnfDiagram-VRR7QNED-Dcw10Yt1.js → abnfDiagram-VRR7QNED-BT0_ycaq.js} +1 -1
  4. package/dist/assets/account-panel-BVNV8XqM.js +1 -0
  5. package/dist/assets/agents-CfpN8PQc.js +1 -0
  6. package/dist/assets/agents-E4nu-17c.js +1 -0
  7. package/dist/assets/{aiden0z-pptx-renderer.es--oNqetPA.js → aiden0z-pptx-renderer.es-ClCaf_Wh.js} +1 -1
  8. package/dist/assets/api-CI6_8Qt1.js +20 -0
  9. package/dist/assets/app-presenter-provider-2DwHRRle.js +28 -0
  10. package/dist/assets/app-presenter-provider-D3BuuOyZ.css +1 -0
  11. package/dist/assets/appearance-settings-page-Cn9w3F-K.js +1 -0
  12. package/dist/assets/apps-YFlJirpx.js +1 -0
  13. package/dist/assets/{arc-DBRedCax.js → arc-cmSdpq1Z.js} +1 -1
  14. package/dist/assets/architecture-TIHT7OUA-BImoGh10.js +1 -0
  15. package/dist/assets/{architectureDiagram-ZJ3FMSHR-Dufhtuv-.js → architectureDiagram-ZJ3FMSHR-aYglVeoS.js} +1 -1
  16. package/dist/assets/{blockDiagram-677ZJIJ3-BUk0vtJ7.js → blockDiagram-677ZJIJ3-Di_PBl5q.js} +1 -1
  17. package/dist/assets/{book-open-Bcnn2_uV.js → book-open-i_BjUBqL.js} +1 -1
  18. package/dist/assets/{c4Diagram-LMCZKHZV-CxDcVE9p.js → c4Diagram-LMCZKHZV-CfuxybOL.js} +1 -1
  19. package/dist/assets/{card-Cqs73hGI.js → card-DokH7OBp.js} +1 -1
  20. package/dist/assets/channel-BDQry0ob.js +1 -0
  21. package/dist/assets/channels-list-page-B7G9lHUm.js +8 -0
  22. package/dist/assets/chunk-2Q5K7J3B-DkgSFfIy.js +1 -0
  23. package/dist/assets/{chunk-32BRIVSS-DSF3KElA.js → chunk-32BRIVSS-CCGc4qg4.js} +1 -1
  24. package/dist/assets/{chunk-52WLFC77-Costxzr3.js → chunk-52WLFC77-aJoxU2Ow.js} +1 -1
  25. package/dist/assets/{chunk-5FCAYU7R-rhqzGGZo.js → chunk-5FCAYU7R-CGwtZSax.js} +1 -1
  26. package/dist/assets/{chunk-5HE753X5-BsEsmIao.js → chunk-5HE753X5-DqaMSMeS.js} +1 -1
  27. package/dist/assets/{chunk-5JV3BV7I-Dqw_DCoN.js → chunk-5JV3BV7I-DnabINcd.js} +1 -1
  28. package/dist/assets/{chunk-5TONJI2A-Cft82fp8.js → chunk-5TONJI2A-BhpKv1k2.js} +1 -1
  29. package/dist/assets/{chunk-5VM5RSS4-DqNHn9Dl.js → chunk-5VM5RSS4-DvkRPit_.js} +1 -1
  30. package/dist/assets/{chunk-7BUUIJ7U-A5SBEMYY.js → chunk-7BUUIJ7U-CgDQOLnC.js} +1 -1
  31. package/dist/assets/{chunk-BIQX33UG-1Ng3mTrH.js → chunk-BIQX33UG-9FEv5b7T.js} +1 -1
  32. package/dist/assets/{chunk-C7G6YPKG-DRJEy8ZI.js → chunk-C7G6YPKG-CNGFAFYL.js} +1 -1
  33. package/dist/assets/{chunk-CQNSW5MT-Bydv_J3J.js → chunk-CQNSW5MT-DovTZx0M.js} +1 -1
  34. package/dist/assets/{chunk-CYSBUYHQ-HkMIg12u.js → chunk-CYSBUYHQ-DpLEgYa1.js} +1 -1
  35. package/dist/assets/{chunk-EMLP6XTP-C5ndDvm3.js → chunk-EMLP6XTP-D4NuN01W.js} +1 -1
  36. package/dist/assets/{chunk-EX3LRPZG-DzeloZRo.js → chunk-EX3LRPZG-D8Jf4kc2.js} +1 -1
  37. package/dist/assets/{chunk-FWX5IMBZ-n_2_CLTQ.js → chunk-FWX5IMBZ-BdHymAs0.js} +2 -2
  38. package/dist/assets/{chunk-HOUHSVGY-kx_slvu3.js → chunk-HOUHSVGY-Dd_Ycn9Z.js} +1 -1
  39. package/dist/assets/{chunk-ICXQ74PX-sQLMURqL.js → chunk-ICXQ74PX-BRPUu3ff.js} +1 -1
  40. package/dist/assets/{chunk-JG7HCLWE-CMUn5Elc.js → chunk-JG7HCLWE-DnCasQja.js} +1 -1
  41. package/dist/assets/{chunk-JWPE2WC7-Cra3s-Uk.js → chunk-JWPE2WC7-C3CkbEj1.js} +1 -1
  42. package/dist/assets/{chunk-MOJQB5TN-umcrg5Bi.js → chunk-MOJQB5TN-Pi--K4-1.js} +1 -1
  43. package/dist/assets/{chunk-MOZMSUNE-BnljD1ig.js → chunk-MOZMSUNE-3VTspvlh.js} +1 -1
  44. package/dist/assets/{chunk-OGEWGWER-BXx5pQjU.js → chunk-OGEWGWER-BetLLyJt.js} +1 -1
  45. package/dist/assets/{chunk-OSBZ3O6U-D-1qfdWu.js → chunk-OSBZ3O6U-D1VcupAj.js} +1 -1
  46. package/dist/assets/{chunk-PUDLZKDR-DLzX78LC.js → chunk-PUDLZKDR-Cy4G8SjV.js} +1 -1
  47. package/dist/assets/{chunk-Q4XR5HBZ-DTK-rtW6.js → chunk-Q4XR5HBZ-UYxXzi7_.js} +1 -1
  48. package/dist/assets/{chunk-QBLGF6JB-CsFeIGfr.js → chunk-QBLGF6JB-CHiGeRY1.js} +1 -1
  49. package/dist/assets/{chunk-R7FJI6CG-4xNYUeng.js → chunk-R7FJI6CG-C5kVJus8.js} +1 -1
  50. package/dist/assets/{chunk-RYQCIY6F-DJiHiTE5.js → chunk-RYQCIY6F-C6cuuEBn.js} +1 -1
  51. package/dist/assets/{chunk-U6XO7XAA-BVYkauHz.js → chunk-U6XO7XAA-CM0EK7Y0.js} +1 -1
  52. package/dist/assets/{chunk-V7JOEXUC-BsazE8cS.js → chunk-V7JOEXUC-DWJZIsME.js} +1 -1
  53. package/dist/assets/chunk-VAUOI2AC-CsTIB8qD.js +1 -0
  54. package/dist/assets/{chunk-VR4S4FIN-7RoZQffO.js → chunk-VR4S4FIN-CY5KYeEi.js} +1 -1
  55. package/dist/assets/{chunk-WYO6CB5R-DEuS6N1R.js → chunk-WYO6CB5R-B30N3ZP8.js} +3 -3
  56. package/dist/assets/chunk-XXDRQBXY-DK6dz0Q3.js +1 -0
  57. package/dist/assets/{chunk-YOTPTUD7-9KBrosZL.js → chunk-YOTPTUD7-CBu82JpO.js} +1 -1
  58. package/dist/assets/{chunk-ZGVPDNZ5-IYgN9f5A.js → chunk-ZGVPDNZ5-BN5NX5qA.js} +1 -1
  59. package/dist/assets/{chunk-ZIRB5QZD-BUo0-zcp.js → chunk-ZIRB5QZD-DcDXK29L.js} +1 -1
  60. package/dist/assets/{circle-dashed-EY1ScSMe.js → circle-dashed-Cx8CIEbg.js} +1 -1
  61. package/dist/assets/classDiagram-OUVF2IWQ-BYygHCrp.js +1 -0
  62. package/dist/assets/classDiagram-v2-EOCWNBFH-BgQ0XKYz.js +1 -0
  63. package/dist/assets/{client-CH7w6yRV.js → client-CUJUci3r.js} +1 -1
  64. package/dist/assets/config-split-page-hY1xug28.js +1 -0
  65. package/dist/assets/confirm-dialog-B-ejV666.js +1 -0
  66. package/dist/assets/{app-presenter-provider-jNGlmBLe.css → context-menu-DEcVZfaU.css} +1 -1
  67. package/dist/assets/context-menu-dGVv8klA.js +211 -0
  68. package/dist/assets/{cose-bilkent-JH36ORCC-DhqbC1fR.js → cose-bilkent-JH36ORCC-CmeJVoTw.js} +1 -1
  69. package/dist/assets/{createLucideIcon-Cfo2ySi5.js → createLucideIcon-reFMl-W-.js} +1 -1
  70. package/dist/assets/cron-CH5c55CR.js +1 -0
  71. package/dist/assets/cynefin-VYW2F7L2-DKbotNWS.js +1 -0
  72. package/dist/assets/{cynefinDiagram-TSTJHNR4-C-TBRi5V.js → cynefinDiagram-TSTJHNR4-DGOUMgPP.js} +1 -1
  73. package/dist/assets/{dagre-CrgsRasE.js → dagre-CMxSkbJJ.js} +1 -1
  74. package/dist/assets/{dagre-VKFMJZFB-BmafJymp.js → dagre-VKFMJZFB-3YUBEXwo.js} +1 -1
  75. package/dist/assets/{desktop-capabilities-page-BDYITStl.js → desktop-capabilities-page-CYJTQ3nC.js} +1 -1
  76. package/dist/assets/desktop-update-config-guKAozXO.js +1 -0
  77. package/dist/assets/{diagram-FQU43EPY-BoOMwa6D.js → diagram-FQU43EPY-Br1g--ww.js} +1 -1
  78. package/dist/assets/{diagram-G47NLZAW-Le7N6Uym.js → diagram-G47NLZAW-D1wJCBgr.js} +1 -1
  79. package/dist/assets/{diagram-NH7WQ7WH-Fbpj3-MO.js → diagram-NH7WQ7WH-Cgg2auLH.js} +1 -1
  80. package/dist/assets/{diagram-OA4YK3LP-D3QuGGuu.js → diagram-OA4YK3LP-R-wHiWqh.js} +1 -1
  81. package/dist/assets/{diagram-WEI45ONY-Cxu1uiN6.js → diagram-WEI45ONY-CsNnKV0P.js} +1 -1
  82. package/dist/assets/dialog-DLOwdjT1.js +1 -0
  83. package/dist/assets/dist-ZaFFmAGl.js +41 -0
  84. package/dist/assets/doc-browser-ClDUWo9V.js +1 -0
  85. package/dist/assets/doc-browser-context-CTmOmuqa.js +1 -0
  86. package/dist/assets/{docx-preview-CkU2psnd.js → docx-preview-kPn_EtAr.js} +1 -1
  87. package/dist/assets/{download-BoaKzDJk.js → download-DovI3Yvf.js} +1 -1
  88. package/dist/assets/{ebnfDiagram-CCIWWBDH-CCAjuQM6.js → ebnfDiagram-CCIWWBDH-DCyhIPdi.js} +1 -1
  89. package/dist/assets/{erDiagram-Q63AITRT-BuzUAq-d.js → erDiagram-Q63AITRT-D0ZJYAUf.js} +1 -1
  90. package/dist/assets/eventmodeling-45OFAUF4-SIhbIFIw.js +1 -0
  91. package/dist/assets/extensions-BZ3qrM8M.js +1 -0
  92. package/dist/assets/external-link-DUD3AbsF.js +1 -0
  93. package/dist/assets/flowDiagram-23GEKE2U-DdAjkU7I.js +1 -0
  94. package/dist/assets/{form-actions-D9JWSFQu.js → form-actions-B8VniHts.js} +1 -1
  95. package/dist/assets/{ganttDiagram-NO4QXBWP-cJmWVY8F.js → ganttDiagram-NO4QXBWP-CiXDcXZD.js} +1 -1
  96. package/dist/assets/gitGraph-TEB2WS4Q-DnMNpESZ.js +1 -0
  97. package/dist/assets/{gitGraphDiagram-IHSO6WYX-F58o-vtP.js → gitGraphDiagram-IHSO6WYX-BSiIV48S.js} +1 -1
  98. package/dist/assets/{i18n-Bm3Ov7Fy.js → i18n-IGQbjBqS.js} +2 -2
  99. package/dist/assets/inbox-BjBZIbgx.js +1 -0
  100. package/dist/assets/inbox-ClAG7SI_.js +1 -0
  101. package/dist/assets/info-DKCQHKI2-BSm-69p_.js +1 -0
  102. package/dist/assets/{infoDiagram-FWYZ7A6U-Gt59b83C.js → infoDiagram-FWYZ7A6U-CCIgBCVq.js} +1 -1
  103. package/dist/assets/{ishikawaDiagram-FXEZZL3T-1u4IAj1I.js → ishikawaDiagram-FXEZZL3T-nQ_baN5u.js} +1 -1
  104. package/dist/assets/{journeyDiagram-5HDEW3XC-CCQsfV-5.js → journeyDiagram-5HDEW3XC-ABueIPzj.js} +1 -1
  105. package/dist/assets/{kanban-definition-HUTT4EX6-vlB6O_Zn.js → kanban-definition-HUTT4EX6-8FKS3fmQ.js} +1 -1
  106. package/dist/assets/katex-DPgHtix3.js +1 -0
  107. package/dist/assets/keyboard-shortcuts-settings-page-BqfbbKir.js +1 -0
  108. package/dist/assets/{line-D_bHubTL.js → line-Biw8iEUz.js} +1 -1
  109. package/dist/assets/{linear-ChlwuS5y.js → linear-D7CWUHTF.js} +1 -1
  110. package/dist/assets/login-page-BxSMwUsc.js +1 -0
  111. package/dist/assets/{login-page-C-DvcG3L.js → login-page-DYaozpzz.js} +1 -1
  112. package/dist/assets/main-CWYF9QU_.js +2 -0
  113. package/dist/assets/main-D_zmSVS1.css +1 -0
  114. package/dist/assets/main-i18n-catalog.config-itg3Gvzp.js +1 -0
  115. package/dist/assets/{map-oGHTsIu8.js → map-CDu47gTf.js} +1 -1
  116. package/dist/assets/marketplace-CnQ5USfr.js +1 -0
  117. package/dist/assets/mcp-marketplace-page-Dor6H9IC.js +1 -0
  118. package/dist/assets/{mermaid-parser.core-CuRe1ZG4.js → mermaid-parser.core-Cc9wjl82.js} +2 -2
  119. package/dist/assets/{mermaid.core-u4YCFKRf.js → mermaid.core-GWlaVWz1.js} +3 -3
  120. package/dist/assets/{mindmap-definition-LN4V7U3C-DeJAQYTu.js → mindmap-definition-LN4V7U3C-oqnKsz-R.js} +1 -1
  121. package/dist/assets/model-config-page-Cduyz2Hy.js +1 -0
  122. package/dist/assets/{navigation-link-CjxNC8aT.js → navigation-link-D-JSWFxj.js} +2 -2
  123. package/dist/assets/{ordinal-C6JFfkKN.js → ordinal-DImbxqBz.js} +1 -1
  124. package/dist/assets/packet-7NZHBO7P-1YQvC6mT.js +1 -0
  125. package/dist/assets/panel-app-BBTg0tVp.js +1 -0
  126. package/dist/assets/panel-app-i18n-catalog.config-BfLHr1tc.js +1 -0
  127. package/dist/assets/panel-apps-C-izvtu9.js +1 -0
  128. package/dist/assets/panelStandalone-XRlWxbRS.css +1 -0
  129. package/dist/assets/panelStandalone-oHxbXvYt.js +2 -0
  130. package/dist/assets/{pegDiagram-2B236MQR-nVMkxShH.js → pegDiagram-2B236MQR-DYAB8CEz.js} +1 -1
  131. package/dist/assets/pie-RZYD4A2V-BGoNOSwu.js +1 -0
  132. package/dist/assets/{pieDiagram-ENE6RG2P-8aUH44QZ.js → pieDiagram-ENE6RG2P-DGsH0Kk5.js} +1 -1
  133. package/dist/assets/plus-DUdl68Eo.js +1 -0
  134. package/dist/assets/privacy-settings-page-DG9E8N-F.js +1 -0
  135. package/dist/assets/projects-CzBaTOTL.js +1 -0
  136. package/dist/assets/provider-models-COzjYl29.js +1 -0
  137. package/dist/assets/provider-scoped-model-input-Cvy74uj8.js +1 -0
  138. package/dist/assets/providers-config-page-7rCwVnhh.js +1 -0
  139. package/dist/assets/puzzle-C5Wfpjk_.js +1 -0
  140. package/dist/assets/pwa-CAg_9zFs.js +1 -0
  141. package/dist/assets/{quadrantDiagram-ABIIQ3AL-EY8hpFv8.js → quadrantDiagram-ABIIQ3AL-BegGcT3l.js} +1 -1
  142. package/dist/assets/radar-I7S5WNFK-uPku9RRq.js +1 -0
  143. package/dist/assets/railroad-3IZDKUUU-DHnmbuIo.js +1 -0
  144. package/dist/assets/railroad-abnf-AHOZXSZD-DiZs--Iw.js +1 -0
  145. package/dist/assets/railroad-ebnf-EBAXGLYW-Nr53gnNE.js +1 -0
  146. package/dist/assets/railroad-peg-LSFZ7HO6-Cm_PuwJS.js +1 -0
  147. package/dist/assets/{railroadDiagram-RFXS5EU6-CNhcIeji.js → railroadDiagram-RFXS5EU6-B3yJ2yxE.js} +1 -1
  148. package/dist/assets/{refresh-cw-BlXDrVP0.js → refresh-cw-OhwaPDn1.js} +1 -1
  149. package/dist/assets/remote-DvCdHjzA.js +1 -0
  150. package/dist/assets/{requirementDiagram-TGXJPOKE-D8Dcs-Rt.js → requirementDiagram-TGXJPOKE-DtEyoEXG.js} +1 -1
  151. package/dist/assets/{rotate-cw-ei6rPD6z.js → rotate-cw-aBponvp7.js} +1 -1
  152. package/dist/assets/runtime-config-page-BF1wxvzR.js +1 -0
  153. package/dist/assets/{sankeyDiagram-HTMAVEWB-HTrb6aa-.js → sankeyDiagram-HTMAVEWB-h9AYS2UB.js} +1 -1
  154. package/dist/assets/{save-DdF-bXgC.js → save-394QCMXn.js} +1 -1
  155. package/dist/assets/search-BG2qAlNZ.js +1 -0
  156. package/dist/assets/search-config-page-D4LeiB9y.js +1 -0
  157. package/dist/assets/secrets-config-page-BzGcr5Vw.js +3 -0
  158. package/dist/assets/security-config-vD_V0BQF.js +1 -0
  159. package/dist/assets/select-xUXYV0Gr.js +1 -0
  160. package/dist/assets/{sequenceDiagram-DBY2YBRQ-6f_4X16Y.js → sequenceDiagram-DBY2YBRQ-D-uxCkob.js} +1 -1
  161. package/dist/assets/service-apps-panel-D3wwPRzV.js +1 -0
  162. package/dist/assets/{settings-2-CrNhfInU.js → settings-2-CWOGRRaA.js} +1 -1
  163. package/dist/assets/{sizeCapture-X5ZJPWSS-Ck9rsuwL.js → sizeCapture-X5ZJPWSS-DBzZytQo.js} +1 -1
  164. package/dist/assets/{src-C8AUg09O.js → src-zrGbZsfc.js} +1 -1
  165. package/dist/assets/{stateDiagram-2N3HPSRC-Cm33MLHu.js → stateDiagram-2N3HPSRC-DyDy7AHq.js} +1 -1
  166. package/dist/assets/stateDiagram-v2-6OUMAXLB-CtkpO6aA.js +1 -0
  167. package/dist/assets/{status-dot-C3SRFEta.js → status-dot-CYifnSnt.js} +1 -1
  168. package/dist/assets/{swimlanes-5IMT3BWC-B107vmvM.js → swimlanes-5IMT3BWC-BzOduS38.js} +2 -2
  169. package/dist/assets/swimlanesDiagram-G3AALYLV-BSdi6mvi.js +8 -0
  170. package/dist/assets/tag-chip-CjM6lyeh.js +1 -0
  171. package/dist/assets/theme-provider-BToFZGZG.js +1 -0
  172. package/dist/assets/{timeline-definition-FHXFAJF6-CJEoAj33.js → timeline-definition-FHXFAJF6-CmgnEF2t.js} +1 -1
  173. package/dist/assets/trash-2-DvJ6duOW.js +1 -0
  174. package/dist/assets/treeView-QDETBFTQ-DBoqypPR.js +1 -0
  175. package/dist/assets/treemap-6X3UGDF4-BMeL3P0q.js +1 -0
  176. package/dist/assets/use-config-COusaY5p.js +1 -0
  177. package/dist/assets/{use-desktop-capabilities-BYDjFlpt.js → use-desktop-capabilities-B-u6ojjW.js} +1 -1
  178. package/dist/assets/use-viewport-layout-IKKGpjzF.js +1 -0
  179. package/dist/assets/{vennDiagram-L72KCM5P-DzsUHk5I.js → vennDiagram-L72KCM5P-DwS7D2kg.js} +1 -1
  180. package/dist/assets/wardley-OPB4EBWU-Dqxe7zN6.js +1 -0
  181. package/dist/assets/{wardleyDiagram-EHGQE667-1NfFs5ua.js → wardleyDiagram-EHGQE667-B4X8OOL4.js} +1 -1
  182. package/dist/assets/x-E9VB4HQx.js +1 -0
  183. package/dist/assets/{xychartDiagram-FW5EYKEG-Ci8AI3Qo.js → xychartDiagram-FW5EYKEG-BjRQ_0nx.js} +1 -1
  184. package/dist/index.html +44 -106
  185. package/dist/panel-standalone.html +19 -13
  186. package/index.html +15 -66
  187. package/package.json +5 -5
  188. package/src/app/styles/design-system.css +85 -1
  189. package/src/app/styles/island-theme.css +8 -6
  190. package/src/features/agents/components/__tests__/agents-page.test.tsx +8 -5
  191. package/src/features/agents/components/agent-details-dialog.tsx +24 -18
  192. package/src/features/agents/components/agents-page.tsx +27 -38
  193. package/src/features/app-data/components/app-retained-data-section.tsx +4 -4
  194. package/src/features/apps/components/__tests__/app-marketplace-catalog.test.tsx +2 -2
  195. package/src/features/apps/components/__tests__/app-packages-panel.test.tsx +94 -23
  196. package/src/features/apps/components/__tests__/apps-panel.test.tsx +5 -3
  197. package/src/features/apps/components/app-document-access-section.tsx +17 -14
  198. package/src/features/apps/components/app-marketplace-catalog.tsx +69 -42
  199. package/src/features/apps/components/app-marketplace-cover.tsx +5 -2
  200. package/src/features/apps/components/app-marketplace-detail.tsx +20 -8
  201. package/src/features/apps/components/app-marketplace-operation.tsx +8 -3
  202. package/src/features/apps/components/app-marketplace-panel.tsx +168 -0
  203. package/src/features/apps/components/app-package-card.tsx +224 -147
  204. package/src/features/apps/components/app-package-details-dialog.tsx +103 -0
  205. package/src/features/apps/components/app-packages-panel.tsx +162 -147
  206. package/src/features/apps/components/apps-panel.tsx +43 -12
  207. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +1 -1
  208. package/src/features/chat/components/conversation/chat-conversation-header.tsx +1 -1
  209. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +2 -2
  210. package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +9 -7
  211. package/src/features/chat/components/providers/chat-runtime.provider.tsx +1 -1
  212. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +0 -1
  213. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +13 -2
  214. package/src/features/chat/features/conversation/components/floating-session-conversation.tsx +2 -3
  215. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +9 -1
  216. package/src/features/chat/features/conversation/components/session-conversation-input-top-slot.tsx +44 -0
  217. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +4 -38
  218. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-controller.test.tsx +86 -10
  219. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-input-state.test.tsx +44 -1
  220. package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +85 -73
  221. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-query.ts +5 -15
  222. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +53 -13
  223. package/src/features/chat/features/conversation/hooks/use-session-submission-recovery.ts +83 -0
  224. package/src/features/chat/features/conversation/types/session-conversation-input.types.ts +38 -0
  225. package/src/features/chat/features/input/utils/__tests__/ncp-chat-input-availability.utils.test.ts +1 -29
  226. package/src/features/chat/features/input/utils/ncp-chat-input-availability.utils.ts +1 -8
  227. package/src/features/chat/features/message/components/__tests__/chat-message-list-skill-preview.container.test.tsx +14 -1
  228. package/src/features/chat/features/message/hooks/use-chat-inline-token-actions.ts +7 -2
  229. package/src/features/chat/features/message/utils/chat-message-execution-summary.utils.ts +3 -0
  230. package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +1 -0
  231. package/src/features/chat/features/message/utils/chat-message-trigger-details.utils.ts +3 -0
  232. package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +1 -1
  233. package/src/features/chat/features/session/components/session-header/chat-session-metadata-dialog.tsx +1 -1
  234. package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +2 -2
  235. package/src/features/chat/features/session/utils/__tests__/chat-session-route.utils.test.ts +26 -0
  236. package/src/features/chat/features/session/utils/chat-session-preference-governance.utils.ts +14 -8
  237. package/src/features/chat/features/session/utils/chat-session-route.utils.ts +9 -12
  238. package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +31 -6
  239. package/src/features/chat/features/welcome/components/chat-conversation-welcome.tsx +13 -1
  240. package/src/features/chat/features/welcome/components/chat-welcome-agent-picker.tsx +1 -1
  241. package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +1 -1
  242. package/src/features/chat/features/welcome/components/chat-welcome-prompt-suggestions.tsx +56 -13
  243. package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +3 -3
  244. package/src/features/chat/features/welcome/components/chat-welcome.tsx +14 -4
  245. package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-continuation.utils.test.ts +40 -0
  246. package/src/features/chat/features/welcome/utils/chat-welcome-continuation.utils.ts +21 -0
  247. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.selection.test.tsx +14 -2
  248. package/src/features/chat/features/workspace/components/__tests__/session-cron-job-content.test.tsx +5 -1
  249. package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +1 -1
  250. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +3 -7
  251. package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +6 -5
  252. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +27 -27
  253. package/src/features/chat/features/workspace/components/overview/chat-session-continuous-attention.tsx +11 -11
  254. package/src/features/chat/features/workspace/components/overview/chat-session-token-usage.tsx +15 -15
  255. package/src/features/chat/features/workspace/components/project-files/workspace-directory-tree.tsx +2 -2
  256. package/src/features/chat/features/workspace/components/project-files/workspace-new-folder-tree-item.tsx +1 -1
  257. package/src/features/chat/features/workspace/components/project-files/workspace-project-files-toolbar.tsx +2 -2
  258. package/src/features/chat/features/workspace/components/session-cron-job-content.tsx +13 -26
  259. package/src/features/chat/index.ts +1 -0
  260. package/src/features/chat/pages/__tests__/ncp-chat-page.test.ts +37 -47
  261. package/src/features/chat/pages/ncp-chat-page.tsx +3 -3
  262. package/src/features/chat/stores/__tests__/chat-composer-draft.store.test.ts +67 -1
  263. package/src/features/chat/stores/chat-composer-draft.store.ts +230 -29
  264. package/src/features/cron/components/__tests__/cron-config.test.tsx +8 -2
  265. package/src/features/cron/components/cron-config.tsx +6 -17
  266. package/src/features/cron/components/cron-job-detail-dialog.tsx +10 -9
  267. package/src/features/cron/components/cron-job-resource.tsx +51 -0
  268. package/src/features/cron/components/cron-job-row.tsx +5 -4
  269. package/src/features/cron/index.ts +1 -0
  270. package/src/features/desktop-capabilities/components/desktop-authorization-dialog.tsx +5 -5
  271. package/src/features/inbox/components/inbox-reader-dialog.test.tsx +46 -6
  272. package/src/features/inbox/components/inbox-reader-dialog.tsx +38 -29
  273. package/src/features/inbox/managers/inbox.manager.test.ts +28 -0
  274. package/src/features/inbox/managers/inbox.manager.ts +18 -4
  275. package/src/features/inbox/pages/inbox-page.test.ts +4 -2
  276. package/src/features/inbox/pages/inbox-page.tsx +14 -10
  277. package/src/features/marketplace/components/__tests__/marketplace-page-detail.test.tsx +1 -0
  278. package/src/features/marketplace/components/__tests__/marketplace-page.test.tsx +1 -0
  279. package/src/features/marketplace/components/mcp/__tests__/mcp-marketplace-page.test.tsx +2 -0
  280. package/src/features/marketplace/components/mcp/mcp-marketplace-card.tsx +2 -2
  281. package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +23 -1
  282. package/src/features/marketplace/hooks/use-marketplace-item-detail.ts +11 -0
  283. package/src/features/panel-apps/components/panel-app-list-item.tsx +4 -3
  284. package/src/features/panel-apps/components/panel-app-service-action-authorization-dialog.tsx +2 -2
  285. package/src/features/panel-apps/index.ts +1 -0
  286. package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +5 -24
  287. package/src/features/projects/components/work/project-work-item-drawer.tsx +7 -10
  288. package/src/features/projects/components/work/project-work-items.tsx +1 -1
  289. package/src/features/projects/pages/project-home-page.tsx +18 -23
  290. package/src/features/projects/pages/projects-page.test.tsx +4 -1
  291. package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +3 -3
  292. package/src/features/pwa/managers/pwa-shell-theme.manager.ts +8 -3
  293. package/src/features/right-panel-resources/components/__tests__/page-resource-icon.test.tsx +13 -2
  294. package/src/features/right-panel-resources/components/__tests__/system-object-resource.test.tsx +74 -6
  295. package/src/features/right-panel-resources/components/native-object-resource.tsx +134 -0
  296. package/src/features/right-panel-resources/components/page-resource-icon.tsx +16 -8
  297. package/src/features/right-panel-resources/components/system-object-resource.tsx +66 -1
  298. package/src/features/right-panel-resources/components/workspace-file-resource.tsx +9 -0
  299. package/src/features/right-panel-resources/configs/right-panel-resource-routes.config.ts +11 -21
  300. package/src/features/right-panel-resources/index.ts +3 -0
  301. package/src/features/right-panel-resources/managers/__tests__/page-resource.manager.test.ts +14 -4
  302. package/src/features/right-panel-resources/managers/page-resource.manager.ts +38 -21
  303. package/src/features/right-panel-resources/utils/__tests__/right-panel-resource-route-resolver.utils.test.ts +17 -0
  304. package/src/features/right-panel-resources/utils/right-panel-resource-uri.utils.ts +3 -2
  305. package/src/features/service-apps/components/service-action-row.tsx +4 -3
  306. package/src/features/service-apps/components/service-app-delete-dialog.tsx +2 -2
  307. package/src/features/service-apps/components/service-app-list-item.tsx +5 -4
  308. package/src/features/service-apps/components/service-apps-panel.tsx +5 -2
  309. package/src/features/settings/components/config/provider-model-suggestions-panel.tsx +1 -1
  310. package/src/features/settings/pages/providers-config-page.tsx +3 -2
  311. package/src/index.css +42 -8
  312. package/src/shared/components/doc-browser/__tests__/doc-browser-context.test.tsx +16 -0
  313. package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +2 -2
  314. package/src/shared/components/doc-browser/__tests__/resource-link-interceptor.test.tsx +29 -1
  315. package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +2 -2
  316. package/src/shared/components/doc-browser/stores/doc-browser.store.ts +13 -7
  317. package/src/shared/components/doc-browser/utils/doc-browser-url.utils.ts +2 -1
  318. package/src/shared/components/path-picker/server-path-picker-dialog.tsx +5 -3
  319. package/src/shared/components/ui/__tests__/dialog.test.tsx +37 -1
  320. package/src/shared/components/ui/actions/action-feedback.ts +1 -8
  321. package/src/shared/components/ui/actions/icon-action-button.tsx +1 -1
  322. package/src/shared/components/ui/confirm-dialog.tsx +1 -2
  323. package/src/shared/components/ui/context-menu/context-menu-items.tsx +2 -2
  324. package/src/shared/components/ui/dialog.tsx +29 -7
  325. package/src/shared/components/ui/popover.tsx +14 -3
  326. package/src/shared/components/ui/skeleton.tsx +16 -2
  327. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +2 -2
  328. package/src/shared/components/ui/tooltip.tsx +2 -1
  329. package/src/shared/components/workbench/__tests__/workbench-surface.test.tsx +21 -0
  330. package/src/shared/components/workbench/workbench-surface-toolbar.tsx +4 -0
  331. package/src/shared/components/workbench/workbench-surface.tsx +4 -1
  332. package/src/shared/lib/i18n/locales/en-US/chat.json +21 -7
  333. package/src/shared/lib/i18n/locales/en-US/core.json +5 -1
  334. package/src/shared/lib/i18n/locales/en-US/doc-browser.json +10 -5
  335. package/src/shared/lib/i18n/locales/en-US/inbox.json +1 -0
  336. package/src/shared/lib/i18n/locales/zh-CN/chat.json +21 -7
  337. package/src/shared/lib/i18n/locales/zh-CN/core.json +5 -1
  338. package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +11 -6
  339. package/src/shared/lib/i18n/locales/zh-CN/inbox.json +1 -0
  340. package/src/shared/lib/theme/index.test.ts +28 -1
  341. package/src/shared/lib/theme/index.ts +14 -3
  342. package/src/shared/lib/transport/__tests__/local-transport.service.test.ts +24 -0
  343. package/src/shared/lib/transport/local-transport.service.ts +8 -6
  344. package/dist/assets/account-panel-BAH7FW6z.js +0 -1
  345. package/dist/assets/api-DjiZvIa0.js +0 -20
  346. package/dist/assets/app-presenter-provider-CCRFsFYr.js +0 -232
  347. package/dist/assets/appearance-settings-page-CdP86QJ7.js +0 -1
  348. package/dist/assets/architecture-TIHT7OUA-CvnC-LeA.js +0 -1
  349. package/dist/assets/channel-CpMstUPF.js +0 -1
  350. package/dist/assets/channels-list-page-5qGagKuE.js +0 -8
  351. package/dist/assets/chunk-2Q5K7J3B-Djp3VF0s.js +0 -1
  352. package/dist/assets/chunk-VAUOI2AC-BrbiIC1Q.js +0 -1
  353. package/dist/assets/chunk-XXDRQBXY-Cx9N40wF.js +0 -1
  354. package/dist/assets/classDiagram-OUVF2IWQ-DFN1v3PQ.js +0 -1
  355. package/dist/assets/classDiagram-v2-EOCWNBFH-DRvglADa.js +0 -1
  356. package/dist/assets/config-split-page-CuEGQL8Z.js +0 -1
  357. package/dist/assets/confirm-dialog-CxfecBzO.js +0 -1
  358. package/dist/assets/context-menu-BsCj2fRs.js +0 -1
  359. package/dist/assets/cynefin-VYW2F7L2-DXUGnpJH.js +0 -1
  360. package/dist/assets/desktop-update-config-e-zhkJuS.js +0 -1
  361. package/dist/assets/dialog-QjQoKbIV.js +0 -5
  362. package/dist/assets/doc-browser-CLEdkH9z.js +0 -1
  363. package/dist/assets/doc-browser-context-DwgG6wrz.js +0 -1
  364. package/dist/assets/es2015-Bp6cuSGh.js +0 -41
  365. package/dist/assets/eventmodeling-45OFAUF4-ZBfVS3ZC.js +0 -1
  366. package/dist/assets/extensions-CgShSIkd.js +0 -1
  367. package/dist/assets/eye-kisejBFH.js +0 -1
  368. package/dist/assets/flowDiagram-23GEKE2U-CqdsKk6x.js +0 -1
  369. package/dist/assets/gitGraph-TEB2WS4Q-fHYFd9Es.js +0 -1
  370. package/dist/assets/info-DKCQHKI2-CSaOL_bb.js +0 -1
  371. package/dist/assets/katex-B4FQSo9k.js +0 -1
  372. package/dist/assets/keyboard-shortcuts-settings-page-DZ8A1iLg.js +0 -1
  373. package/dist/assets/loader-circle-Bd1fTm-x.js +0 -1
  374. package/dist/assets/login-page-D99JjH9F.js +0 -1
  375. package/dist/assets/main-Bt5r6b21.js +0 -2
  376. package/dist/assets/main-DXd_aKJV.css +0 -1
  377. package/dist/assets/main-i18n-catalog.config-D0Ll36J_.js +0 -1
  378. package/dist/assets/mcp-marketplace-page-DUoGfSmY.js +0 -1
  379. package/dist/assets/model-config-page-9NNf-mzK.js +0 -1
  380. package/dist/assets/packet-7NZHBO7P-D-YFTczs.js +0 -1
  381. package/dist/assets/panel-app-BYfQu_TS.js +0 -1
  382. package/dist/assets/panel-app-i18n-catalog.config-Ddf2Kv8A.js +0 -1
  383. package/dist/assets/panelStandalone-BRg7B1EI.css +0 -1
  384. package/dist/assets/panelStandalone-BaUzY8Wy.js +0 -2
  385. package/dist/assets/pie-RZYD4A2V-VEnYu9s5.js +0 -1
  386. package/dist/assets/privacy-settings-page-CVMBFuak.js +0 -1
  387. package/dist/assets/projects-BEsU3box.js +0 -1
  388. package/dist/assets/provider-models-Dm-pmWAA.js +0 -1
  389. package/dist/assets/provider-scoped-model-input-CzrXg4cX.js +0 -1
  390. package/dist/assets/providers-config-page-839uUADZ.js +0 -1
  391. package/dist/assets/puzzle-BGvD2DPZ.js +0 -1
  392. package/dist/assets/pwa-DNNK_8E9.js +0 -1
  393. package/dist/assets/radar-I7S5WNFK-BFNIekC1.js +0 -1
  394. package/dist/assets/railroad-3IZDKUUU-lVqJ3Hak.js +0 -1
  395. package/dist/assets/railroad-abnf-AHOZXSZD-DYaefdFC.js +0 -1
  396. package/dist/assets/railroad-ebnf-EBAXGLYW-CTAk6lVq.js +0 -1
  397. package/dist/assets/railroad-peg-LSFZ7HO6-Cob294tg.js +0 -1
  398. package/dist/assets/remote-B5qIuUbT.js +0 -1
  399. package/dist/assets/runtime-config-page-Bf-4JYxQ.js +0 -1
  400. package/dist/assets/search-config-page-C0qA3j-T.js +0 -1
  401. package/dist/assets/secrets-config-page-DxfZWpnk.js +0 -3
  402. package/dist/assets/security-config-CItfIQZ4.js +0 -1
  403. package/dist/assets/select-CWyjnar7.js +0 -1
  404. package/dist/assets/service-apps-panel-D3SOkRVv.js +0 -1
  405. package/dist/assets/stateDiagram-v2-6OUMAXLB-BrNv-raG.js +0 -1
  406. package/dist/assets/swimlanesDiagram-G3AALYLV-ntcxaPXp.js +0 -8
  407. package/dist/assets/tag-chip-BIuavK2K.js +0 -1
  408. package/dist/assets/theme-provider-CWUz4yO9.js +0 -1
  409. package/dist/assets/trash-2-hAbJh9VZ.js +0 -1
  410. package/dist/assets/treeView-QDETBFTQ-DbFmr-gw.js +0 -1
  411. package/dist/assets/treemap-6X3UGDF4-C8aY96pi.js +0 -1
  412. package/dist/assets/use-config-evzage09.js +0 -1
  413. package/dist/assets/use-viewport-layout-D_9XWGDV.js +0 -1
  414. package/dist/assets/wardley-OPB4EBWU-D8d6DbbJ.js +0 -1
  415. package/dist/assets/x-ChPbNv39.js +0 -1
  416. package/src/features/apps/components/app-marketplace-dialog.tsx +0 -168
  417. /package/dist/assets/{array-BV9OtnO8.js → array-DsNX3jRj.js} +0 -0
  418. /package/dist/assets/{chunk-KEIR6QF5-Cx-8EJ4_.js → chunk-KEIR6QF5-BOAXXeyv.js} +0 -0
  419. /package/dist/assets/{chunk-Y2CYZVJY-Dy1ufvjf.js → chunk-Y2CYZVJY-CHjSjwoV.js} +0 -0
  420. /package/dist/assets/{config-hints-DbmiyTKg.js → config-hints-CaB3I7KP.js} +0 -0
  421. /package/dist/assets/{cytoscape.esm-CSCjuT4Z.js → cytoscape.esm-j4J9a91l.js} +0 -0
  422. /package/dist/assets/{defaultLocale-DWTiNsbT.js → defaultLocale-Bmxjp-V_.js} +0 -0
  423. /package/dist/assets/{dist-BVCSkfWY.js → dist-DwLj1Wg5.js} +0 -0
  424. /package/dist/assets/{graphlib-B1yb1Wl8.js → graphlib-CC0HTn1v.js} +0 -0
  425. /package/dist/assets/{host-capabilities-DuIFVsvM.js → host-capabilities-B107nwS3.js} +0 -0
  426. /package/dist/assets/{init-BF6GH5oe.js → init-Biz9Rus1.js} +0 -0
  427. /package/dist/assets/{jszip.min-D12teKzP.js → jszip.min-DQvBVV_R.js} +0 -0
  428. /package/dist/assets/{katex-CsAM73R9.js → katex-BzT-4KBu.js} +0 -0
  429. /package/dist/assets/{navigation-history-CzErJuPG.js → navigation-history-CCnxsAKR.js} +0 -0
  430. /package/dist/assets/{path-C56XkznJ.js → path-4azsBPZv.js} +0 -0
  431. /package/dist/assets/{preload-helper-ca-nBW7U.js → preload-helper-DWTEM3RW.js} +0 -0
  432. /package/dist/assets/{rough.esm-CGfeEbtE.js → rough.esm-w1lBArN6.js} +0 -0
  433. /package/dist/assets/{xlsx-sds5nUpL.js → xlsx--SB9KlFl.js} +0 -0
@@ -1,5 +1,6 @@
1
+ import { useRef, type RefObject } from 'react';
1
2
  import type { AppPackageHostTarget, AppPackageOperationView, AppPackageView } from '@nextclaw/client-sdk';
2
- import { ChevronRight, Search, Sparkles } from 'lucide-react';
3
+ import { ChevronRight, Search, Sparkles, PackagePlus, X } from 'lucide-react';
3
4
  import { AppArtwork } from '@/features/apps/components/app-artwork';
4
5
  import { AppMarketplaceCover } from '@/features/apps/components/app-marketplace-cover';
5
6
  import {
@@ -17,13 +18,10 @@ import {
17
18
  resolveAppMarketplaceInstallability,
18
19
  } from '@/features/apps/utils/app-marketplace-platform.utils';
19
20
  import { pickLocalizedText } from '@/features/marketplace';
20
- import {
21
- DialogDescription,
22
- DialogHeader,
23
- DialogTitle,
24
- } from '@/shared/components/ui/dialog';
21
+ import { Button } from '@/shared/components/ui/button';
22
+ import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
25
23
  import { Input } from '@/shared/components/ui/input';
26
- import { Skeleton } from '@/shared/components/ui/skeleton';
24
+ import { SkeletonContent } from '@/shared/components/ui/skeleton';
27
25
  import { getLanguage, t } from '@/shared/lib/i18n';
28
26
  import { cn } from '@/shared/lib/utils';
29
27
 
@@ -31,10 +29,13 @@ export type MarketplaceFilter = 'all' | 'featured' | 'personal' | 'local';
31
29
 
32
30
  export function AppMarketplaceCatalog({
33
31
  error,
32
+ onCustomInstall,
33
+ sourceButtonRef,
34
34
  filter,
35
35
  hostTarget,
36
36
  installedById,
37
37
  isError,
38
+ onRetry,
38
39
  isFetchingNextPage,
39
40
  isLoading,
40
41
  isStarting,
@@ -46,16 +47,20 @@ export function AppMarketplaceCatalog({
46
47
  onSearchChange,
47
48
  onSelect,
48
49
  onUpdate,
50
+ onManagePackage,
49
51
  operations,
50
52
  hasNextPage,
51
53
  search,
52
54
  startingSource,
53
55
  }: {
54
56
  error: Error | null;
57
+ onCustomInstall?: () => void;
58
+ sourceButtonRef?: RefObject<HTMLButtonElement>;
55
59
  filter: MarketplaceFilter;
56
60
  hostTarget?: AppPackageHostTarget;
57
61
  installedById: Map<string, AppPackageView>;
58
62
  isError: boolean;
63
+ onRetry?: () => void;
59
64
  isFetchingNextPage: boolean;
60
65
  isLoading: boolean;
61
66
  isStarting: boolean;
@@ -67,20 +72,24 @@ export function AppMarketplaceCatalog({
67
72
  onSearchChange: (value: string) => void;
68
73
  onSelect: (slug: string) => void;
69
74
  onUpdate: (appId: string) => void;
75
+ onManagePackage?: (appId: string) => void;
70
76
  operations: AppPackageOperationView[];
71
77
  hasNextPage: boolean;
72
78
  search: string;
73
79
  startingSource?: string;
74
80
  }) {
81
+ const scrollArea = useRef<HTMLDivElement>(null);
75
82
  return (
76
83
  <>
77
84
  <MarketplaceCatalogHeader
85
+ onCustomInstall={onCustomInstall}
86
+ sourceButtonRef={sourceButtonRef}
78
87
  filter={filter}
79
- onFilterChange={onFilterChange}
80
- onSearchChange={onSearchChange}
88
+ onFilterChange={(value) => { if (scrollArea.current) scrollArea.current.scrollTop = 0; onFilterChange(value); }}
89
+ onSearchChange={(value) => { if (scrollArea.current) scrollArea.current.scrollTop = 0; onSearchChange(value); }}
81
90
  search={search}
82
91
  />
83
- <div className="custom-scrollbar min-h-0 flex-1 overflow-y-auto bg-background px-4 py-4 sm:px-6 sm:py-5">
92
+ <div ref={scrollArea} className="custom-scrollbar min-h-0 flex-1 overflow-y-auto bg-background px-4 py-5 [@container(min-width:40rem)]:px-6">
84
93
  {error ? (
85
94
  <div role="alert" className="mb-2 rounded-xl bg-destructive/8 px-3 py-2.5 text-xs leading-5 text-destructive ring-1 ring-destructive/15">
86
95
  {error.message || t('appPackagesActionFailed')}
@@ -90,6 +99,7 @@ export function AppMarketplaceCatalog({
90
99
  installedById={installedById}
91
100
  hostTarget={hostTarget}
92
101
  isError={isError}
102
+ onRetry={onRetry}
93
103
  isFetchingNextPage={isFetchingNextPage}
94
104
  isLoading={isLoading}
95
105
  isStarting={isStarting}
@@ -99,6 +109,7 @@ export function AppMarketplaceCatalog({
99
109
  onLoadMore={onLoadMore}
100
110
  onSelect={onSelect}
101
111
  onUpdate={onUpdate}
112
+ onManagePackage={onManagePackage}
102
113
  operations={operations}
103
114
  hasNextPage={hasNextPage}
104
115
  startingSource={startingSource}
@@ -109,11 +120,15 @@ export function AppMarketplaceCatalog({
109
120
  }
110
121
 
111
122
  function MarketplaceCatalogHeader({
123
+ onCustomInstall,
124
+ sourceButtonRef,
112
125
  filter,
113
126
  onFilterChange,
114
127
  onSearchChange,
115
128
  search,
116
129
  }: {
130
+ onCustomInstall?: () => void;
131
+ sourceButtonRef?: RefObject<HTMLButtonElement>;
117
132
  filter: MarketplaceFilter;
118
133
  onFilterChange: (value: MarketplaceFilter) => void;
119
134
  onSearchChange: (value: string) => void;
@@ -126,34 +141,35 @@ function MarketplaceCatalogHeader({
126
141
  { value: 'local', label: t('appPackagesFilterLocal') },
127
142
  ];
128
143
  return (
129
- <div className="shrink-0 border-b border-border/60 bg-card px-5 pb-3.5 pt-[max(1.25rem,env(safe-area-inset-top))] sm:px-6 sm:pt-5">
130
- <DialogHeader className="pr-8">
131
- <DialogTitle className="text-xl">{t('appPackagesMarketplaceTitle')}</DialogTitle>
132
- <DialogDescription className="max-w-xl leading-5">
133
- {t('appPackagesMarketplaceDescription')}
134
- </DialogDescription>
135
- </DialogHeader>
144
+ <div className="shrink-0 border-b border-border/60 bg-card px-4 pb-4 pt-5 [@container(min-width:40rem)]:px-6">
145
+ <div className="mx-auto max-w-[872px]">
146
+ <div className="flex items-center justify-between gap-3">
147
+ <h1 className="text-xl font-semibold tracking-tight">{t('appPackagesMarketplaceTitle')}</h1>
148
+ {onCustomInstall ? <IconActionButton ref={sourceButtonRef} icon={<PackagePlus className="h-4 w-4" />} label={t('appPackagesCustomSource')} onClick={onCustomInstall} /> : null}
149
+ </div>
150
+ <p className="mt-1.5 text-sm leading-5 text-muted-foreground">{t('appPackagesMarketplaceDescription')}</p>
136
151
  <div className="relative mt-4">
137
152
  <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
138
153
  <Input
139
- autoFocus
140
- className="h-10 rounded-xl border-transparent bg-muted/65 pl-9 shadow-none focus-visible:ring-1"
154
+ className="h-10 rounded-xl border-0 bg-muted/65 pl-9 pr-10 ![box-shadow:none]"
141
155
  value={search}
142
156
  onChange={(event) => onSearchChange(event.target.value)}
143
157
  placeholder={t('appPackagesMarketplaceSearch')}
144
158
  aria-label={t('appPackagesMarketplaceSearch')}
145
159
  />
160
+ {search ? <div className="absolute right-1 top-1/2 -translate-y-1/2"><IconActionButton icon={<X className="h-3.5 w-3.5" />} label={t('appPackagesClearSearch')} onClick={() => onSearchChange('')} /></div> : null}
146
161
  </div>
147
- <div className="mt-3 flex gap-1 overflow-x-auto" aria-label={t('appPackagesFilterLabel')}>
162
+ <div className="custom-scrollbar mt-3 flex gap-1 overflow-x-auto" aria-label={t('appPackagesFilterLabel')}>
148
163
  {filters.map((entry) => (
149
164
  <button
150
165
  key={entry.value}
151
166
  type="button"
167
+ aria-pressed={filter === entry.value}
152
168
  onClick={() => onFilterChange(entry.value)}
153
169
  className={cn(
154
170
  'shrink-0 rounded-full px-3 py-1.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border',
155
171
  filter === entry.value
156
- ? 'bg-foreground text-background'
172
+ ? 'bg-[var(--interaction-selection)] text-foreground'
157
173
  : 'text-muted-foreground hover:bg-[var(--interaction-hover)] hover:text-foreground',
158
174
  )}
159
175
  >
@@ -161,6 +177,7 @@ function MarketplaceCatalogHeader({
161
177
  </button>
162
178
  ))}
163
179
  </div>
180
+ </div>
164
181
  </div>
165
182
  );
166
183
  }
@@ -169,6 +186,7 @@ function MarketplaceCatalogContent({
169
186
  installedById,
170
187
  hostTarget,
171
188
  isError,
189
+ onRetry,
172
190
  isFetchingNextPage,
173
191
  isLoading,
174
192
  isStarting,
@@ -178,6 +196,7 @@ function MarketplaceCatalogContent({
178
196
  onLoadMore,
179
197
  onSelect,
180
198
  onUpdate,
199
+ onManagePackage,
181
200
  operations,
182
201
  hasNextPage,
183
202
  startingSource,
@@ -185,6 +204,7 @@ function MarketplaceCatalogContent({
185
204
  installedById: Map<string, AppPackageView>;
186
205
  hostTarget?: AppPackageHostTarget;
187
206
  isError: boolean;
207
+ onRetry?: () => void;
188
208
  isFetchingNextPage: boolean;
189
209
  isLoading: boolean;
190
210
  isStarting: boolean;
@@ -194,16 +214,17 @@ function MarketplaceCatalogContent({
194
214
  onLoadMore: () => void;
195
215
  onSelect: (slug: string) => void;
196
216
  onUpdate: (appId: string) => void;
217
+ onManagePackage?: (appId: string) => void;
197
218
  operations: AppPackageOperationView[];
198
219
  hasNextPage: boolean;
199
220
  startingSource?: string;
200
221
  }) {
201
222
  if (isLoading) {
202
223
  return (
203
- <div className="grid gap-3 sm:grid-cols-2 min-[820px]:grid-cols-3" aria-label={t('appPackagesMarketplaceLoading')}>
204
- <Skeleton className="aspect-[16/9] w-full rounded-2xl" />
205
- <Skeleton className="aspect-[16/9] w-full rounded-2xl" />
206
- <Skeleton className="hidden aspect-[16/9] w-full rounded-2xl min-[820px]:block" />
224
+ <div className="mx-auto grid max-w-[872px] gap-4 [@container(min-width:36rem)]:grid-cols-2 [@container(min-width:52rem)]:grid-cols-3" role="status" aria-label={t('appPackagesMarketplaceLoading')}>
225
+ <SkeletonContent />
226
+ <SkeletonContent />
227
+ <SkeletonContent className="hidden [@container(min-width:52rem)]:flex" />
207
228
  </div>
208
229
  );
209
230
  }
@@ -211,6 +232,7 @@ function MarketplaceCatalogContent({
211
232
  return (
212
233
  <div role="alert" className="rounded-xl border border-destructive/20 bg-destructive/5 px-4 py-5 text-sm text-destructive">
213
234
  {t('appPackagesMarketplaceFailed')}
235
+ {onRetry ? <Button className="mt-3 block" variant="outline" size="sm" onClick={onRetry}>{t('appPackagesRefresh')}</Button> : null}
214
236
  </div>
215
237
  );
216
238
  }
@@ -226,8 +248,8 @@ function MarketplaceCatalogContent({
226
248
  );
227
249
  }
228
250
  return (
229
- <div>
230
- <div className="grid gap-3 sm:grid-cols-2 min-[820px]:grid-cols-3">
251
+ <div className="mx-auto w-full max-w-[872px]">
252
+ <div className="grid gap-1 [@container(min-width:36rem)]:gap-4 [@container(min-width:36rem)]:grid-cols-2 [@container(min-width:52rem)]:grid-cols-3">
231
253
  {items.map((item) => (
232
254
  <MarketplaceCatalogCard
233
255
  key={item.id}
@@ -239,6 +261,7 @@ function MarketplaceCatalogContent({
239
261
  onInstall={onInstall}
240
262
  onSelect={onSelect}
241
263
  onUpdate={onUpdate}
264
+ onManagePackage={onManagePackage}
242
265
  operation={findLatestAppPackageOperation(operations, item.appId, item.install.spec)}
243
266
  />
244
267
  ))}
@@ -268,6 +291,7 @@ function MarketplaceCatalogCard({
268
291
  onInstall,
269
292
  onSelect,
270
293
  onUpdate,
294
+ onManagePackage,
271
295
  operation,
272
296
  }: {
273
297
  installedPackage?: AppPackageView;
@@ -278,6 +302,7 @@ function MarketplaceCatalogCard({
278
302
  onInstall: (source: string, registryUrl: string) => void;
279
303
  onSelect: (slug: string) => void;
280
304
  onUpdate: (appId: string) => void;
305
+ onManagePackage?: (appId: string) => void;
281
306
  operation?: AppPackageOperationView;
282
307
  }) {
283
308
  const displayName = installedPackage
@@ -298,16 +323,17 @@ function MarketplaceCatalogCard({
298
323
  );
299
324
  const blockAction = Boolean(compatibility && (!installedPackage || canUpdate));
300
325
  return (
301
- <article className="group relative overflow-hidden rounded-2xl border border-border/60 bg-card shadow-sm transition duration-200 hover:-translate-y-0.5 hover:border-border hover:shadow-lg">
326
+ <article className="group relative overflow-hidden rounded-lg bg-card transition-colors duration-150 hover:bg-[var(--interaction-hover)] [@container(min-width:36rem)]:rounded-2xl [@container(min-width:36rem)]:border [@container(min-width:36rem)]:border-border/60 [@container(min-width:36rem)]:shadow-sm">
302
327
  <button
303
328
  type="button"
304
329
  onClick={() => onSelect(item.slug)}
305
- className="block w-full text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
330
+ aria-label={displayName}
331
+ className="hidden w-full text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring [@container(min-width:36rem)]:block"
306
332
  >
307
- <AppMarketplaceCover accentColor={item.accentColor} coverPreview={item.coverPreview} coverUrl={item.coverUrl} name={displayName} className="aspect-[16/9] rounded-none ring-0" />
333
+ <AppMarketplaceCover icon={item.iconUrl ?? installedPackage?.icon} accentColor={item.accentColor} coverPreview={item.coverPreview} coverUrl={item.coverUrl} name={displayName} className="aspect-[16/9] rounded-none ring-0" />
308
334
  </button>
309
- <div className="p-3.5">
310
- <div className="flex items-start gap-3">
335
+ <div className="grid grid-cols-[minmax(0,1fr)_auto] items-end gap-2 px-2 py-3 [@container(min-width:36rem)]:block [@container(min-width:36rem)]:p-3.5">
336
+ <div className="flex min-w-0 items-start gap-2.5">
311
337
  <AppArtwork icon={item.iconUrl ?? installedPackage?.icon} name={displayName} className="h-11 w-11 rounded-[13px]" />
312
338
  <button
313
339
  type="button"
@@ -319,24 +345,25 @@ function MarketplaceCatalogCard({
319
345
  {item.featured ? <Sparkles className="h-3.5 w-3.5 shrink-0 text-amber-500" aria-label={t('appPackagesMarketplaceFeatured')} /> : null}
320
346
  </span>
321
347
  <MarketplaceCompatibilityBadge presentation={compatibility} />
322
- <span className="mt-1 line-clamp-2 block min-h-10 text-xs leading-5 text-muted-foreground">{summary}</span>
323
- <span className="mt-2 flex items-center gap-1.5 text-[11px] text-muted-foreground/75">
324
- <span>{item.publisher.name}</span>
325
- <span aria-hidden="true">·</span>
326
- <span>v{item.latestVersion}</span>
327
- <span aria-hidden="true">·</span>
328
- <span>{supportedPlatforms}</span>
348
+ <span className="mt-1 block truncate text-xs leading-5 text-muted-foreground [@container(min-width:36rem)]:line-clamp-2 [@container(min-width:36rem)]:min-h-10 [@container(min-width:36rem)]:whitespace-normal">{summary}</span>
349
+ <span className="mt-1 flex items-center gap-1.5 overflow-hidden text-[11px] text-muted-foreground [@container(min-width:36rem)]:mt-2 [@container(min-width:36rem)]:flex-wrap">
350
+ <span className="truncate">{item.publisher.name}</span>
351
+ <span aria-hidden="true" className="hidden [@container(min-width:36rem)]:inline">·</span>
352
+ <span className="hidden [@container(min-width:36rem)]:inline">v{item.latestVersion}</span>
353
+ <span aria-hidden="true" className="hidden [@container(min-width:36rem)]:inline">·</span>
354
+ <span className="hidden [@container(min-width:36rem)]:inline">{supportedPlatforms}</span>
329
355
  <ChevronRight className="ml-0.5 h-3 w-3 opacity-0 transition-opacity group-hover:opacity-60" />
330
356
  </span>
331
357
  </button>
332
358
  </div>
333
- <div className="mt-3 flex items-center justify-between gap-3 border-t border-border/50 pt-3">
359
+ <div className="flex shrink-0 items-center justify-end gap-2 [@container(min-width:36rem)]:mt-3 [@container(min-width:36rem)]:border-t [@container(min-width:36rem)]:border-border/50 [@container(min-width:36rem)]:pt-3">
334
360
  <MarketplaceCompatibilityStatus
335
361
  blocked={blockAction}
336
362
  presentation={compatibility}
337
- className="min-w-0 text-[11px] font-medium text-muted-foreground"
363
+ className="hidden min-w-0 text-[11px] font-medium text-muted-foreground [@container(min-width:36rem)]:block"
338
364
  />
339
365
  <MarketplaceInstallButton
366
+ onInstalled={onManagePackage ? () => onManagePackage(item.appId) : undefined}
340
367
  active={active}
341
368
  canUpdate={canUpdate}
342
369
  installed={Boolean(installedPackage)}
@@ -350,7 +377,7 @@ function MarketplaceCatalogCard({
350
377
  />
351
378
  </div>
352
379
  </div>
353
- {operation && !blockAction && active ? <div className="px-4 pb-4"><OperationProgress operation={operation} /></div> : null}
380
+ {operation && !blockAction && (active || operation.status === 'failed' || operation.status === 'interrupted') ? <div className="px-4 pb-4"><OperationProgress operation={operation} /></div> : null}
354
381
  </article>
355
382
  );
356
383
  }
@@ -1,5 +1,6 @@
1
1
  import { useState, type CSSProperties } from 'react';
2
2
  import { cn } from '@/shared/lib/utils';
3
+ import { AppArtwork } from './app-artwork';
3
4
 
4
5
  const COVER_PREVIEW_LABEL = import.meta.env.VITE_APP_MARKETPLACE_PREVIEW_LABEL;
5
6
 
@@ -9,12 +10,14 @@ export function AppMarketplaceCover({
9
10
  coverPreview,
10
11
  coverUrl,
11
12
  name,
13
+ icon,
12
14
  }: {
13
15
  accentColor?: string;
14
16
  className?: string;
15
17
  coverPreview?: boolean;
16
18
  coverUrl?: string;
17
19
  name: string;
20
+ icon?: string;
18
21
  }) {
19
22
  const [failedUrl, setFailedUrl] = useState<string>();
20
23
  const visibleCover = coverUrl && failedUrl !== coverUrl ? coverUrl : undefined;
@@ -46,9 +49,9 @@ export function AppMarketplaceCover({
46
49
  aria-label={`${name} 暂无封面`}
47
50
  className="flex h-full w-full items-center justify-center bg-[radial-gradient(circle_at_30%_25%,color-mix(in_srgb,var(--app-accent)_28%,transparent),transparent_50%),linear-gradient(145deg,var(--muted),var(--background))]"
48
51
  >
49
- <span className="flex h-14 w-14 items-center justify-center rounded-2xl bg-background/65 text-xl font-semibold text-foreground/65 shadow-sm ring-1 ring-black/[0.05] backdrop-blur-sm">
52
+ {icon ? <AppArtwork icon={icon} name={name} className="h-16 w-16 rounded-2xl" /> : <span className="flex h-14 w-14 items-center justify-center rounded-2xl bg-background/65 text-xl font-semibold text-foreground/65 shadow-sm ring-1 ring-black/[0.05] backdrop-blur-sm">
50
53
  {readCoverMonogram(name)}
51
- </span>
54
+ </span>}
52
55
  </span>
53
56
  )}
54
57
  </span>
@@ -16,7 +16,7 @@ import {
16
16
  resolveAppMarketplaceInstallability,
17
17
  } from '@/features/apps/utils/app-marketplace-platform.utils';
18
18
  import { pickLocalizedText } from '@/features/marketplace';
19
- import { Skeleton } from '@/shared/components/ui/skeleton';
19
+ import { Skeleton, SkeletonContent } from '@/shared/components/ui/skeleton';
20
20
  import { t } from '@/shared/lib/i18n';
21
21
 
22
22
  export function MarketplaceDetail({
@@ -29,6 +29,7 @@ export function MarketplaceDetail({
29
29
  localeFallbacks,
30
30
  onInstall,
31
31
  onUpdate,
32
+ onManagePackage,
32
33
  operation,
33
34
  }: {
34
35
  detail?: AppMarketplaceDetailView;
@@ -40,10 +41,20 @@ export function MarketplaceDetail({
40
41
  localeFallbacks: string[];
41
42
  onInstall: (source: string, registryUrl: string) => void;
42
43
  onUpdate: (appId: string) => void;
44
+ onManagePackage?: (appId: string) => void;
43
45
  operation?: AppPackageOperationView;
44
46
  }) {
45
47
  if (isLoading) {
46
- return <div className="space-y-4 p-6"><Skeleton className="h-24 w-full rounded-2xl" /><Skeleton className="h-40 w-full rounded-2xl" /></div>;
48
+ return (
49
+ <div className="mx-auto max-w-3xl space-y-6 px-5 py-5" role="status" aria-label={t('appPackagesMarketplaceLoading')}>
50
+ <SkeletonContent />
51
+ <div className="space-y-3">
52
+ <Skeleton className="h-3 w-full" />
53
+ <Skeleton className="h-3 w-5/6" />
54
+ <Skeleton className="h-3 w-2/3" />
55
+ </div>
56
+ </div>
57
+ );
47
58
  }
48
59
  if (error || !detail) {
49
60
  return <div role="alert" className="m-6 rounded-xl border border-destructive/20 bg-destructive/5 px-4 py-5 text-sm text-destructive">{error?.message ?? t('appPackagesMarketplaceFailed')}</div>;
@@ -69,9 +80,9 @@ export function MarketplaceDetail({
69
80
  );
70
81
  const blockAction = Boolean(compatibility && (!installedPackage || canUpdate));
71
82
  return (
72
- <div className="mx-auto w-full max-w-3xl px-5 py-5 sm:px-7 sm:py-6">
73
- <div className="grid items-stretch gap-5 sm:grid-cols-[minmax(0,1.18fr)_minmax(240px,0.82fr)]">
74
- <AppMarketplaceCover accentColor={detail.accentColor} coverPreview={detail.coverPreview} coverUrl={detail.coverUrl} name={detail.name} className="aspect-[16/9] rounded-2xl" />
83
+ <div className="mx-auto w-full max-w-3xl px-5 py-5 [@container(min-width:40rem)]:px-7 [@container(min-width:40rem)]:py-6">
84
+ <div className="grid items-stretch gap-5 [@container(min-width:40rem)]:grid-cols-[minmax(0,1.18fr)_minmax(240px,0.82fr)]">
85
+ <AppMarketplaceCover icon={detail.iconUrl ?? installedPackage?.icon} accentColor={detail.accentColor} coverPreview={detail.coverPreview} coverUrl={detail.coverUrl} name={detail.name} className="aspect-[16/9] rounded-2xl" />
75
86
  <div className="flex min-w-0 flex-col rounded-2xl border border-border/60 bg-card p-4">
76
87
  <div className="flex items-start gap-3">
77
88
  <AppArtwork icon={detail.iconUrl ?? installedPackage?.icon} name={detail.name} className="h-14 w-14 rounded-2xl" />
@@ -92,6 +103,7 @@ export function MarketplaceDetail({
92
103
  className="mb-2 text-xs font-medium text-muted-foreground"
93
104
  />
94
105
  <MarketplaceInstallButton
106
+ onInstalled={onManagePackage ? () => onManagePackage(detail.appId) : undefined}
95
107
  active={active}
96
108
  canUpdate={canUpdate}
97
109
  installed={Boolean(installedPackage)}
@@ -106,14 +118,14 @@ export function MarketplaceDetail({
106
118
  </div>
107
119
  </div>
108
120
  </div>
109
- {operation && !blockAction && active ? <OperationProgress operation={operation} /> : null}
121
+ {operation && !blockAction && (active || operation.status === 'failed' || operation.status === 'interrupted') ? <OperationProgress operation={operation} /> : null}
110
122
 
111
123
  <section className="mt-7">
112
124
  <h3 className="text-sm font-semibold text-foreground">{t('appPackagesAboutApp')}</h3>
113
125
  <p className="mt-2 text-sm leading-6 text-muted-foreground">{description}</p>
114
126
  </section>
115
127
 
116
- <div className="mt-6 grid gap-3 sm:grid-cols-2">
128
+ <div className="mt-6 grid gap-3 [@container(min-width:40rem)]:grid-cols-2">
117
129
  <DetailFact
118
130
  icon={Monitor}
119
131
  label={t('appPackagesPlatformsLabel')}
@@ -155,7 +167,7 @@ export function MarketplaceDetail({
155
167
  href={detail.webUrl}
156
168
  target="_blank"
157
169
  rel="noreferrer"
158
- className="mt-6 inline-flex items-center gap-1.5 text-xs font-medium text-muted-foreground underline-offset-4 hover:text-foreground hover:underline focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
170
+ className="mt-6 inline-flex items-center gap-1.5 text-xs font-medium text-muted-foreground underline underline-offset-4 hover:text-foreground hover:underline focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
159
171
  >
160
172
  {t('appPackagesOpenPublicDetails')}
161
173
  <ExternalLink className="h-3.5 w-3.5" />
@@ -70,6 +70,7 @@ export function MarketplaceInstallButton({
70
70
  installed,
71
71
  isStarting,
72
72
  onAction,
73
+ onInstalled,
73
74
  operation,
74
75
  unavailableLabel,
75
76
  unavailableReason,
@@ -79,21 +80,22 @@ export function MarketplaceInstallButton({
79
80
  installed: boolean;
80
81
  isStarting: boolean;
81
82
  onAction: () => void;
83
+ onInstalled?: () => void;
82
84
  operation?: AppPackageOperationView;
83
85
  unavailableLabel?: string;
84
86
  unavailableReason?: string;
85
87
  }) {
86
- const disabled = Boolean(unavailableReason) || installed && !canUpdate || active || isStarting;
88
+ const disabled = Boolean(unavailableReason) || installed && !canUpdate && !onInstalled || active || isStarting;
87
89
  const button = (
88
90
  <Button
89
91
  type="button"
90
92
  size="sm"
91
93
  variant={installed && !canUpdate || active ? 'secondary' : 'default'}
92
94
  disabled={disabled}
93
- onClick={onAction}
95
+ onClick={installed && !canUpdate && onInstalled ? onInstalled : onAction}
94
96
  className="shrink-0 rounded-full px-4"
95
97
  >
96
- {renderInstallButtonContent({
98
+ {installed && !canUpdate && onInstalled && !active && !isStarting ? t('appPackagesViewInstalled') : renderInstallButtonContent({
97
99
  active,
98
100
  canUpdate,
99
101
  installed,
@@ -153,6 +155,9 @@ function renderInstallButtonContent({
153
155
  }
154
156
 
155
157
  export function OperationProgress({ operation }: { operation: AppPackageOperationView }) {
158
+ if (operation.status === 'failed' || operation.status === 'interrupted') {
159
+ return <p role="alert" className="mt-2 text-xs leading-5 text-destructive">{operation.error || t('appPackagesActionFailed')}</p>;
160
+ }
156
161
  const progress = Math.max(4, Math.round((operation.completedSteps / operation.totalSteps) * 100));
157
162
  return (
158
163
  <div className="mt-2" role="status" aria-live="polite">
@@ -0,0 +1,168 @@
1
+ import { useEffect, useMemo, useRef, useState, type RefObject } from 'react';
2
+ import type { AppPackageHostTarget, AppPackageOperationView, AppPackageView } from '@nextclaw/client-sdk';
3
+ import { ArrowLeft } from 'lucide-react';
4
+ import {
5
+ AppMarketplaceCatalog,
6
+ type MarketplaceFilter,
7
+ } from '@/features/apps/components/app-marketplace-catalog';
8
+ import { MarketplaceDetail } from '@/features/apps/components/app-marketplace-detail';
9
+ import { findLatestAppPackageOperation } from '@/features/apps/components/app-marketplace-operation';
10
+ import {
11
+ useAppMarketplace,
12
+ useAppMarketplaceDetail,
13
+ } from '@/features/apps/hooks/use-app-marketplace';
14
+ import { buildLocaleFallbacks } from '@/features/marketplace';
15
+ import {
16
+ getAppMarketplaceInstallabilityRank,
17
+ resolveAppMarketplaceInstallability,
18
+ } from '@/features/apps/utils/app-marketplace-platform.utils';
19
+ import { Button } from '@/shared/components/ui/button';
20
+ import { TooltipProvider } from '@/shared/components/ui/tooltip';
21
+ import { getLanguage, t } from '@/shared/lib/i18n';
22
+
23
+ const HIDDEN_ENGINEERING_APPS = new Set([
24
+ 'nextclaw.starter-card',
25
+ 'nextclaw.validation-task-board',
26
+ ]);
27
+
28
+ export function AppMarketplacePanel({
29
+ error,
30
+ hostTarget,
31
+ installedPackages,
32
+ isStarting,
33
+ onInstall,
34
+ onCustomInstall,
35
+ onManagePackage,
36
+ sourceButtonRef,
37
+ onUpdate,
38
+ active,
39
+ operations,
40
+ startingSource,
41
+ }: {
42
+ error: Error | null;
43
+ hostTarget?: AppPackageHostTarget;
44
+ installedPackages: AppPackageView[];
45
+ isStarting: boolean;
46
+ onInstall: (source: string, registryUrl: string) => void;
47
+ onCustomInstall: () => void;
48
+ onManagePackage: (appId: string) => void;
49
+ sourceButtonRef: RefObject<HTMLButtonElement>;
50
+ onUpdate: (appId: string) => void;
51
+ active: boolean;
52
+ operations: AppPackageOperationView[];
53
+ startingSource?: string;
54
+ }) {
55
+ const [filter, setFilter] = useState<MarketplaceFilter>('all');
56
+ const [search, setSearch] = useState('');
57
+ const [debouncedSearch, setDebouncedSearch] = useState('');
58
+ const [selectedSlug, setSelectedSlug] = useState<string | null>(null);
59
+ useEffect(() => {
60
+ const timer = window.setTimeout(() => setDebouncedSearch(search.trim()), 250);
61
+ return () => window.clearTimeout(timer);
62
+ }, [search]);
63
+ const marketplaceParams = useMemo(() => ({
64
+ q: debouncedSearch || undefined,
65
+ featured: filter === 'featured' ? true : undefined,
66
+ tags: filter === 'personal'
67
+ ? ['personal', 'productivity', 'notes', 'calendar']
68
+ : undefined,
69
+ tag: filter === 'local'
70
+ ? 'local'
71
+ : undefined,
72
+ sort: debouncedSearch ? 'relevance' as const : 'featured' as const,
73
+ }), [debouncedSearch, filter]);
74
+ const marketplace = useAppMarketplace(marketplaceParams, active);
75
+ const detail = useAppMarketplaceDetail(selectedSlug, active);
76
+ const installedById = useMemo(
77
+ () => new Map(installedPackages.map((entry) => [entry.id, entry])),
78
+ [installedPackages],
79
+ );
80
+ const localeFallbacks = buildLocaleFallbacks(getLanguage() === 'zh' ? 'zh-CN' : 'en-US');
81
+ const items = useMemo(() => (marketplace.data?.items ?? [])
82
+ .filter((item) => !HIDDEN_ENGINEERING_APPS.has(item.appId))
83
+ .map((item, index) => ({
84
+ item,
85
+ index,
86
+ rank: getAppMarketplaceInstallabilityRank(
87
+ resolveAppMarketplaceInstallability(item.availability, hostTarget),
88
+ ),
89
+ }))
90
+ .sort((left, right) => left.rank - right.rank || left.index - right.index)
91
+ .map(({ item }) => item), [hostTarget, marketplace.data?.items]);
92
+
93
+ const selectedTrigger = useRef<HTMLElement | null>(null);
94
+ const backButton = useRef<HTMLButtonElement>(null);
95
+ const selectItem = (slug: string) => {
96
+ selectedTrigger.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
97
+ setSelectedSlug(slug);
98
+ };
99
+ const backToCatalog = () => {
100
+ setSelectedSlug(null);
101
+ requestAnimationFrame(() => selectedTrigger.current?.focus({ preventScroll: true }));
102
+ };
103
+ useEffect(() => {
104
+ if (selectedSlug) backButton.current?.focus();
105
+ }, [selectedSlug]);
106
+
107
+ return (
108
+ <TooltipProvider>
109
+ <div className="[container-type:inline-size] flex h-full min-h-0 flex-col bg-card">
110
+ {selectedSlug ? (
111
+ <>
112
+ <div className="shrink-0 border-b border-border/50 px-4 py-3">
113
+ <Button ref={backButton} type="button" variant="ghost" size="sm" onClick={backToCatalog}>
114
+ <ArrowLeft className="mr-2 h-4 w-4" />{t('appPackagesBackToMarketplace')}
115
+ </Button>
116
+ </div>
117
+ <div className="custom-scrollbar min-h-0 flex-1 overflow-y-auto bg-background">
118
+ {error ? <p role="alert" className="mx-5 mt-4 text-sm text-destructive">{error.message || t('appPackagesActionFailed')}</p> : null}
119
+ <MarketplaceDetail
120
+ detail={detail.data}
121
+ error={detail.error instanceof Error ? detail.error : null}
122
+ installedPackage={detail.data ? installedById.get(detail.data.appId) : undefined}
123
+ hostTarget={hostTarget}
124
+ isLoading={detail.isLoading}
125
+ isStarting={isStarting && detail.data?.install.spec === startingSource}
126
+ localeFallbacks={localeFallbacks}
127
+ onInstall={onInstall}
128
+ onUpdate={onUpdate}
129
+ onManagePackage={onManagePackage}
130
+ operation={detail.data
131
+ ? findLatestAppPackageOperation(operations, detail.data.appId, detail.data.install.spec)
132
+ : undefined}
133
+ />
134
+ </div>
135
+ </>
136
+ ) : null}
137
+ <div hidden={Boolean(selectedSlug)} className={selectedSlug ? 'hidden' : 'flex min-h-0 flex-1 flex-col'}>
138
+ <AppMarketplaceCatalog
139
+ error={error}
140
+ filter={filter}
141
+ installedById={installedById}
142
+ hostTarget={hostTarget}
143
+ isError={marketplace.isError}
144
+ isFetchingNextPage={marketplace.isFetchingNextPage}
145
+ isLoading={marketplace.isLoading}
146
+ isStarting={isStarting}
147
+ items={items}
148
+ localeFallbacks={localeFallbacks}
149
+ onFilterChange={setFilter}
150
+ onInstall={onInstall}
151
+ onLoadMore={() => void marketplace.fetchNextPage()}
152
+ onSearchChange={setSearch}
153
+ onSelect={selectItem}
154
+ onCustomInstall={onCustomInstall}
155
+ sourceButtonRef={sourceButtonRef}
156
+ onManagePackage={onManagePackage}
157
+ onRetry={() => void marketplace.refetch()}
158
+ onUpdate={onUpdate}
159
+ operations={operations}
160
+ hasNextPage={marketplace.hasNextPage}
161
+ search={search}
162
+ startingSource={startingSource}
163
+ />
164
+ </div>
165
+ </div>
166
+ </TooltipProvider>
167
+ );
168
+ }