@nextclaw/ui 0.24.1 → 0.24.3

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 (353) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/.vite/manifest.json +2477 -0
  3. package/dist/assets/{abnfDiagram-VRR7QNED-BcFJp_1X.js → abnfDiagram-VRR7QNED-Kzlh3ZEC.js} +1 -1
  4. package/dist/assets/account-panel-BRTSwNvA.js +1 -0
  5. package/dist/assets/{aiden0z-pptx-renderer.es-Dp2ezlQn.js → aiden0z-pptx-renderer.es-k1xZLzeo.js} +1 -1
  6. package/dist/assets/api-BnUzdltV.js +13 -0
  7. package/dist/assets/app-data-Bjh_zM45.js +1 -0
  8. package/dist/assets/app-presenter-provider-CBt-lyr_.js +109 -0
  9. package/dist/assets/app-presenter-provider-D3BuuOyZ.css +1 -0
  10. package/dist/assets/appearance-settings-page-BrOYSgG0.js +1 -0
  11. package/dist/assets/{arc-CkgyPMyW.js → arc-CpivM836.js} +1 -1
  12. package/dist/assets/architecture-TIHT7OUA-CVRF_cYQ.js +1 -0
  13. package/dist/assets/{architectureDiagram-ZJ3FMSHR-CMd4cIjI.js → architectureDiagram-ZJ3FMSHR-ifjW1qjI.js} +1 -1
  14. package/dist/assets/{blockDiagram-677ZJIJ3-Bz3tbhet.js → blockDiagram-677ZJIJ3-C_zeJrKF.js} +1 -1
  15. package/dist/assets/{book-open-o2x7OLiO.js → book-open-xqEj1OLE.js} +1 -1
  16. package/dist/assets/boxes-D6uPnkGo.js +1 -0
  17. package/dist/assets/{c4Diagram-LMCZKHZV-D9hFNAGv.js → c4Diagram-LMCZKHZV-CpapRftp.js} +1 -1
  18. package/dist/assets/card-CS8su2Zh.js +1 -0
  19. package/dist/assets/channel-CBrWRr4N.js +1 -0
  20. package/dist/assets/channels-list-page-BE0TxB3B.js +8 -0
  21. package/dist/assets/chevron-down-BL-yMYcX.js +1 -0
  22. package/dist/assets/chunk-2Q5K7J3B-B8mmRk7d.js +1 -0
  23. package/dist/assets/{chunk-32BRIVSS-7NrjEITq.js → chunk-32BRIVSS-BKBwdmKR.js} +1 -1
  24. package/dist/assets/{chunk-52WLFC77-viIcqj9q.js → chunk-52WLFC77-BgZRCpDx.js} +1 -1
  25. package/dist/assets/{chunk-5FCAYU7R-Vsu4J-VM.js → chunk-5FCAYU7R-YWfOINJi.js} +1 -1
  26. package/dist/assets/{chunk-5HE753X5-C-w6CQZK.js → chunk-5HE753X5-BZ6I07d2.js} +1 -1
  27. package/dist/assets/{chunk-5JV3BV7I-CuKgJQ4W.js → chunk-5JV3BV7I-B7QYgZU5.js} +1 -1
  28. package/dist/assets/{chunk-5TONJI2A-CYeiWZKb.js → chunk-5TONJI2A-DjyQwgL2.js} +1 -1
  29. package/dist/assets/{chunk-5VM5RSS4-DRCbfwIn.js → chunk-5VM5RSS4-DheHV7X2.js} +1 -1
  30. package/dist/assets/{chunk-7BUUIJ7U-BvydOcm3.js → chunk-7BUUIJ7U-D6bq2PKF.js} +1 -1
  31. package/dist/assets/{chunk-BIQX33UG-RlppOXKo.js → chunk-BIQX33UG-CL9x0ibm.js} +1 -1
  32. package/dist/assets/{chunk-C7G6YPKG-DAizzYwr.js → chunk-C7G6YPKG-8z3B6RUH.js} +1 -1
  33. package/dist/assets/{chunk-CQNSW5MT-5eChJHca.js → chunk-CQNSW5MT-DpHkxY3n.js} +1 -1
  34. package/dist/assets/{chunk-CYSBUYHQ-YHPr53fv.js → chunk-CYSBUYHQ-DIJDLsdJ.js} +1 -1
  35. package/dist/assets/{chunk-EMLP6XTP-CK4D7Hz5.js → chunk-EMLP6XTP-B-LjAyVd.js} +1 -1
  36. package/dist/assets/{chunk-EX3LRPZG-BmlDFIRW.js → chunk-EX3LRPZG-BChuEPvO.js} +1 -1
  37. package/dist/assets/{chunk-FWX5IMBZ-D0ksHZZ9.js → chunk-FWX5IMBZ-fBFt0u3f.js} +2 -2
  38. package/dist/assets/{chunk-HOUHSVGY-DPkq8FCm.js → chunk-HOUHSVGY-MD0SpW5A.js} +1 -1
  39. package/dist/assets/{chunk-ICXQ74PX-FAatv5fC.js → chunk-ICXQ74PX-DvCcw_hz.js} +1 -1
  40. package/dist/assets/{chunk-JG7HCLWE-DLkIi4F7.js → chunk-JG7HCLWE-B8zqBnU9.js} +1 -1
  41. package/dist/assets/{chunk-JWPE2WC7-DawOjNE3.js → chunk-JWPE2WC7-C9efnkGb.js} +1 -1
  42. package/dist/assets/{chunk-MOJQB5TN-Di52TorW.js → chunk-MOJQB5TN-gXbfqoqq.js} +1 -1
  43. package/dist/assets/{chunk-MOZMSUNE-PfyK9w1-.js → chunk-MOZMSUNE-twIwdkqC.js} +1 -1
  44. package/dist/assets/{chunk-OGEWGWER-C3jdH3Ty.js → chunk-OGEWGWER-DdR0_cWK.js} +1 -1
  45. package/dist/assets/{chunk-OSBZ3O6U-CecHo-f0.js → chunk-OSBZ3O6U-D7D58Foa.js} +1 -1
  46. package/dist/assets/{chunk-PUDLZKDR-f3IJh3sN.js → chunk-PUDLZKDR-DPILgOVY.js} +1 -1
  47. package/dist/assets/{chunk-Q4XR5HBZ-DQFeUPxZ.js → chunk-Q4XR5HBZ-C0JJx7lW.js} +1 -1
  48. package/dist/assets/{chunk-QBLGF6JB-BhUeG0y2.js → chunk-QBLGF6JB-Dbsf69ng.js} +1 -1
  49. package/dist/assets/{chunk-R7FJI6CG-C3XpZ-2u.js → chunk-R7FJI6CG-Bb8n616-.js} +1 -1
  50. package/dist/assets/{chunk-RYQCIY6F-CAqa5klQ.js → chunk-RYQCIY6F-1HOsOrSl.js} +1 -1
  51. package/dist/assets/{chunk-U6XO7XAA-D_WXezeD.js → chunk-U6XO7XAA-BAFDVb1v.js} +1 -1
  52. package/dist/assets/{chunk-V7JOEXUC-CZ70oOtp.js → chunk-V7JOEXUC-8-g68lu5.js} +1 -1
  53. package/dist/assets/chunk-VAUOI2AC-Cpml0inz.js +1 -0
  54. package/dist/assets/{chunk-VR4S4FIN-B7AHEYYk.js → chunk-VR4S4FIN-P6UGmaYd.js} +1 -1
  55. package/dist/assets/{chunk-WYO6CB5R-Dn9To_OI.js → chunk-WYO6CB5R-6wjFTXNP.js} +2 -2
  56. package/dist/assets/chunk-XXDRQBXY-nCiqnCpF.js +1 -0
  57. package/dist/assets/{chunk-YOTPTUD7-BYEgRBk3.js → chunk-YOTPTUD7-CLYXVZAi.js} +1 -1
  58. package/dist/assets/{chunk-ZGVPDNZ5-C6YtZDU0.js → chunk-ZGVPDNZ5-BRTmSAhp.js} +1 -1
  59. package/dist/assets/{chunk-ZIRB5QZD-DMuYtnHF.js → chunk-ZIRB5QZD-CH_1eoSV.js} +1 -1
  60. package/dist/assets/circle-alert-lSa3LRvS.js +1 -0
  61. package/dist/assets/circle-dashed-CU3yApvP.js +1 -0
  62. package/dist/assets/classDiagram-OUVF2IWQ-C-DRqAaW.js +1 -0
  63. package/dist/assets/classDiagram-v2-EOCWNBFH-DXCcZ42U.js +1 -0
  64. package/dist/assets/client-BtGBwLTs.js +1 -0
  65. package/dist/assets/config-split-page-BxDwwAGa.js +1 -0
  66. package/dist/assets/confirm-dialog-S5JxZcS1.js +1 -0
  67. package/dist/assets/{cose-bilkent-JH36ORCC-Bc2Ex5Y3.js → cose-bilkent-JH36ORCC-L7w_qScX.js} +1 -1
  68. package/dist/assets/{createLucideIcon-rwwpqyks.js → createLucideIcon-BNKf0_kc.js} +1 -1
  69. package/dist/assets/cynefin-VYW2F7L2-2SOTgxxC.js +1 -0
  70. package/dist/assets/{cynefinDiagram-TSTJHNR4-DVysQoGz.js → cynefinDiagram-TSTJHNR4-Bay7uDSR.js} +1 -1
  71. package/dist/assets/{dagre-CMhQ1cAG.js → dagre-CJ_hX8xv.js} +1 -1
  72. package/dist/assets/{dagre-VKFMJZFB-RYyWpPJZ.js → dagre-VKFMJZFB-DDhk-2B3.js} +1 -1
  73. package/dist/assets/desktop-capabilities-page-BwHxJpbl.js +1 -0
  74. package/dist/assets/desktop-update-config-Bfg7OdJ2.js +1 -0
  75. package/dist/assets/{diagram-FQU43EPY-BD6KONdF.js → diagram-FQU43EPY-somFq5y8.js} +1 -1
  76. package/dist/assets/{diagram-G47NLZAW-CGB2ptRR.js → diagram-G47NLZAW-hzgyQsPd.js} +1 -1
  77. package/dist/assets/{diagram-NH7WQ7WH-DnkOI6cU.js → diagram-NH7WQ7WH-BkJ4gEQJ.js} +1 -1
  78. package/dist/assets/{diagram-OA4YK3LP-DF82RZ7P.js → diagram-OA4YK3LP-CS3ZkK4w.js} +1 -1
  79. package/dist/assets/{diagram-WEI45ONY-Be2v7Ck9.js → diagram-WEI45ONY-BApo-JHS.js} +1 -1
  80. package/dist/assets/dialog-Xe73hpQz.js +5 -0
  81. package/dist/assets/dist-BiIcnf9j.js +1 -0
  82. package/dist/assets/dist-C5I0v8Qn.js +1 -0
  83. package/dist/assets/{dist--ta5rX12.js → dist-Cnhwure9.js} +1 -1
  84. package/dist/assets/{dist-aNN3iQxV.js → dist-czPa8xFO.js} +1 -1
  85. package/dist/assets/doc-browser-BgRP0Wni.js +1 -0
  86. package/dist/assets/doc-browser-C8eqJLi_.js +1 -0
  87. package/dist/assets/doc-browser-context-BPCDFcC-.js +1 -0
  88. package/dist/assets/{docx-preview-BqwAjrj3.js → docx-preview-ByCKKIVT.js} +1 -1
  89. package/dist/assets/{ebnfDiagram-CCIWWBDH-CP98OYk8.js → ebnfDiagram-CCIWWBDH-DWjfeEie.js} +1 -1
  90. package/dist/assets/ellipsis-C5YXdOUx.js +1 -0
  91. package/dist/assets/{erDiagram-Q63AITRT-ZLlx8xfs.js → erDiagram-Q63AITRT-DR7vWYHM.js} +1 -1
  92. package/dist/assets/es2015-cuwbYI-l.js +41 -0
  93. package/dist/assets/eventmodeling-45OFAUF4-CXZNG56U.js +1 -0
  94. package/dist/assets/extensions-DgKQRebe.js +1 -0
  95. package/dist/assets/eye-C84inPcV.js +1 -0
  96. package/dist/assets/flowDiagram-23GEKE2U-2065oyKr.js +1 -0
  97. package/dist/assets/form-actions-AIdXOoCL.js +1 -0
  98. package/dist/assets/{ganttDiagram-NO4QXBWP-DXCDjHR2.js → ganttDiagram-NO4QXBWP-E3l9tuaL.js} +1 -1
  99. package/dist/assets/gitGraph-TEB2WS4Q-B0Ln3ZuK.js +1 -0
  100. package/dist/assets/{gitGraphDiagram-IHSO6WYX-l2HWrTJp.js → gitGraphDiagram-IHSO6WYX-DiMvbHKf.js} +1 -1
  101. package/dist/assets/i18n-CKvm9zyk.js +2 -0
  102. package/dist/assets/i18n-provider-CPV43pMX.js +1 -0
  103. package/dist/assets/info-DKCQHKI2-B06uqGM4.js +1 -0
  104. package/dist/assets/{infoDiagram-FWYZ7A6U-D-DjX-bn.js → infoDiagram-FWYZ7A6U-BZDL0NDJ.js} +1 -1
  105. package/dist/assets/{ishikawaDiagram-FXEZZL3T-y_Xy128F.js → ishikawaDiagram-FXEZZL3T-BZ9WvJb2.js} +1 -1
  106. package/dist/assets/{journeyDiagram-5HDEW3XC-DJn5xYcQ.js → journeyDiagram-5HDEW3XC-C3TZvKM8.js} +1 -1
  107. package/dist/assets/{jszip.min-8hyJpgpx.js → jszip.min-D_AtKL_8.js} +1 -1
  108. package/dist/assets/{kanban-definition-HUTT4EX6-DJVIOR21.js → kanban-definition-HUTT4EX6-9FqauDEi.js} +1 -1
  109. package/dist/assets/{line-Cos7PIOj.js → line-Ca49mj80.js} +1 -1
  110. package/dist/assets/{linear-BtDLqtzF.js → linear-DlCeG66S.js} +1 -1
  111. package/dist/assets/loader-circle-K1BDdHR5.js +1 -0
  112. package/dist/assets/login-page-ClcrvN04.js +1 -0
  113. package/dist/assets/login-page-DeDQjVxv.js +1 -0
  114. package/dist/assets/logo-badge-C-5-zim6.js +1 -0
  115. package/dist/assets/main-DGqlaAaI.css +1 -0
  116. package/dist/assets/main-i18n-catalog.config-CpNF5aVc.js +1 -0
  117. package/dist/assets/main-nMVfHb5K.js +2 -0
  118. package/dist/assets/{map-BKnQyvd0.js → map-WMnNq9UV.js} +1 -1
  119. package/dist/assets/mcp-marketplace-page-CWjJGp_D.js +10 -0
  120. package/dist/assets/mcp-marketplace-page-fvu2NcXT.js +1 -0
  121. package/dist/assets/{mermaid-parser.core-XUNZhr2W.js → mermaid-parser.core-B8xk4hpS.js} +2 -2
  122. package/dist/assets/{mermaid.core-ySrvolIe.js → mermaid.core-CFPiczKH.js} +3 -3
  123. package/dist/assets/{mindmap-definition-LN4V7U3C-BypL9tei.js → mindmap-definition-LN4V7U3C-CnxA52L6.js} +1 -1
  124. package/dist/assets/model-config-page-Dv_zE7HN.js +1 -0
  125. package/dist/assets/{navigation-link-C_6oj3zz.js → navigation-link-BAQjgx2F.js} +1 -1
  126. package/dist/assets/{ordinal-CxxVWxYU.js → ordinal-PgiFlfBJ.js} +1 -1
  127. package/dist/assets/packet-7NZHBO7P-CHx-igbz.js +1 -0
  128. package/dist/assets/panel-app-BUUle0gP.js +1 -0
  129. package/dist/assets/panel-app-i18n-catalog.config-BzxE3tZb.js +1 -0
  130. package/dist/assets/panelStandalone-CFRBHV94.js +2 -0
  131. package/dist/assets/panelStandalone-Y91OJkgV.css +1 -0
  132. package/dist/assets/{pegDiagram-2B236MQR-D-U2KBGv.js → pegDiagram-2B236MQR-A8oz7dTH.js} +1 -1
  133. package/dist/assets/pie-RZYD4A2V-DOaMc-x9.js +1 -0
  134. package/dist/assets/{pieDiagram-ENE6RG2P-CBi3GusJ.js → pieDiagram-ENE6RG2P-mtBnkYY0.js} +1 -1
  135. package/dist/assets/plus-LA8-jpxP.js +1 -0
  136. package/dist/assets/popover-NkrFlWHp.js +1 -0
  137. package/dist/assets/privacy-settings-page-D6uc9f-A.js +1 -0
  138. package/dist/assets/projects-BD1rG75R.js +1 -0
  139. package/dist/assets/provider-models-5PGHb6mP.js +1 -0
  140. package/dist/assets/provider-scoped-model-input-DUa_9uwg.js +1 -0
  141. package/dist/assets/providers-config-page-DAiqxlF_.js +1 -0
  142. package/dist/assets/puzzle-D6gulz7u.js +1 -0
  143. package/dist/assets/pwa-C_Zte1xe.js +1 -0
  144. package/dist/assets/{quadrantDiagram-ABIIQ3AL-H0ZuvnZL.js → quadrantDiagram-ABIIQ3AL-DE1VybGO.js} +1 -1
  145. package/dist/assets/radar-I7S5WNFK-CXsdndDk.js +1 -0
  146. package/dist/assets/railroad-3IZDKUUU-DxgXdrYP.js +1 -0
  147. package/dist/assets/railroad-abnf-AHOZXSZD-CR1tnyjz.js +1 -0
  148. package/dist/assets/railroad-ebnf-EBAXGLYW-CjjxZR2U.js +1 -0
  149. package/dist/assets/railroad-peg-LSFZ7HO6-DgVGJCHN.js +1 -0
  150. package/dist/assets/{railroadDiagram-RFXS5EU6-D7Y2EqSd.js → railroadDiagram-RFXS5EU6-u9EMg14B.js} +1 -1
  151. package/dist/assets/{refresh-cw-DsT2kvXi.js → refresh-cw-h9Xq3LY3.js} +1 -1
  152. package/dist/assets/remote-BO0QP7ua.js +1 -0
  153. package/dist/assets/{requirementDiagram-TGXJPOKE-BiXNX1NN.js → requirementDiagram-TGXJPOKE-BAWHAqEi.js} +1 -1
  154. package/dist/assets/{rotate-cw-BCAs6c3R.js → rotate-cw-B6xm41Wn.js} +1 -1
  155. package/dist/assets/runtime-config-page-w1UAkGF_.js +1 -0
  156. package/dist/assets/{sankeyDiagram-HTMAVEWB-qzDeLztW.js → sankeyDiagram-HTMAVEWB-aDy-jdwF.js} +1 -1
  157. package/dist/assets/{save-CadRMTMQ.js → save-fff_WpY2.js} +1 -1
  158. package/dist/assets/{search-B6tB4fzB.js → search-CUe41wjm.js} +1 -1
  159. package/dist/assets/search-config-page-3xbhRlW2.js +1 -0
  160. package/dist/assets/secrets-config-page-Dn8_rdOj.js +3 -0
  161. package/dist/assets/security-config-Y1nEGM3A.js +1 -0
  162. package/dist/assets/select-CG5YWnwe.js +1 -0
  163. package/dist/assets/{sequenceDiagram-DBY2YBRQ-BtRbPQtL.js → sequenceDiagram-DBY2YBRQ-DwHC4mbX.js} +1 -1
  164. package/dist/assets/service-apps-panel-CGc04aMn.js +1 -0
  165. package/dist/assets/settings-2-CE3ELQyk.js +1 -0
  166. package/dist/assets/{sizeCapture-X5ZJPWSS-CMYvM3SL.js → sizeCapture-X5ZJPWSS-oOMY0Fag.js} +1 -1
  167. package/dist/assets/skeleton-BL9h32W7.js +1 -0
  168. package/dist/assets/{src-Bw-mzbQb.js → src-CLPoo5iL.js} +1 -1
  169. package/dist/assets/{stateDiagram-2N3HPSRC-BJ-mFeOz.js → stateDiagram-2N3HPSRC-B0Epk-VR.js} +1 -1
  170. package/dist/assets/stateDiagram-v2-6OUMAXLB-Ct4zTw8P.js +1 -0
  171. package/dist/assets/{swimlanes-5IMT3BWC-BsucVOO2.js → swimlanes-5IMT3BWC-T0w-Iuzf.js} +2 -2
  172. package/dist/assets/swimlanesDiagram-G3AALYLV-CdmN0PBd.js +8 -0
  173. package/dist/assets/tabs-BuE0qKMh.js +1 -0
  174. package/dist/assets/{tag-chip-BZKk0UkK.js → tag-chip-BDzpHEli.js} +1 -1
  175. package/dist/assets/theme-provider-B6FinATQ.js +1 -0
  176. package/dist/assets/{timeline-definition-FHXFAJF6-Bicewlzo.js → timeline-definition-FHXFAJF6-BEonB5Np.js} +1 -1
  177. package/dist/assets/tooltip-DYcuWhuP.js +1 -0
  178. package/dist/assets/trash-2-BPPYt2NV.js +1 -0
  179. package/dist/assets/treeView-QDETBFTQ-Dad4_Wc7.js +1 -0
  180. package/dist/assets/treemap-6X3UGDF4-9_GWWZsY.js +1 -0
  181. package/dist/assets/use-config-BPUM2lbo.js +1 -0
  182. package/dist/assets/use-desktop-capabilities-BDjArQP3.js +1 -0
  183. package/dist/assets/use-panel-app-scroll-restoration-DsV1IJx-.js +1 -0
  184. package/dist/assets/use-viewport-layout-BS18drMT.js +1 -0
  185. package/dist/assets/utils-CBZPzC_b.js +8 -0
  186. package/dist/assets/{vennDiagram-L72KCM5P-BxOOnO9x.js → vennDiagram-L72KCM5P-BDvcOCo2.js} +1 -1
  187. package/dist/assets/wardley-OPB4EBWU-BXpvyee9.js +1 -0
  188. package/dist/assets/{wardleyDiagram-EHGQE667-Cl7NltMv.js → wardleyDiagram-EHGQE667-jMLMgjzE.js} +1 -1
  189. package/dist/assets/x-DdXOqLnX.js +1 -0
  190. package/dist/assets/{xychartDiagram-FW5EYKEG-DiMIxQ7N.js → xychartDiagram-FW5EYKEG-pzrpclEv.js} +1 -1
  191. package/dist/index.html +56 -25
  192. package/dist/panel-standalone.html +30 -0
  193. package/package.json +4 -4
  194. package/panel-standalone.html +13 -0
  195. package/panel-standalone.tailwind.config.js +16 -0
  196. package/src/app/components/app-presenter-provider.tsx +8 -1
  197. package/src/app/components/theme-provider.tsx +0 -5
  198. package/src/app/index.tsx +18 -4
  199. package/src/app/presenters/app.presenter.ts +4 -4
  200. package/src/app/styles/panel-app-standalone.css +31 -0
  201. package/src/app/test/vitest-setup.ts +3 -0
  202. package/src/features/account/hooks/use-auth.ts +7 -57
  203. package/src/features/account/index.ts +3 -2
  204. package/src/features/apps/components/__tests__/apps-panel.test.tsx +7 -5
  205. package/src/features/apps/components/apps-panel.tsx +9 -3
  206. package/src/features/chat/features/message/utils/__tests__/chat-message-timeline.utils.test.ts +10 -0
  207. package/src/features/chat/features/session/components/__tests__/chat-sidebar-project-groups.test.tsx +90 -6
  208. package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +64 -2
  209. package/src/features/chat/features/session/utils/__tests__/chat-sidebar-session-groups.utils.test.ts +27 -2
  210. package/src/features/chat/features/session/utils/chat-sidebar-session-groups.utils.ts +0 -11
  211. package/src/features/panel-apps/components/__tests__/panel-app-list-item.test.tsx +18 -0
  212. package/src/features/panel-apps/components/__tests__/panel-app-open-standalone-menu-item.test.tsx +57 -0
  213. package/src/features/panel-apps/components/__tests__/panel-app-toolbar.test.tsx +15 -0
  214. package/src/features/panel-apps/components/panel-app-list-item.tsx +5 -0
  215. package/src/features/panel-apps/components/panel-app-open-standalone-menu-item.tsx +32 -0
  216. package/src/features/panel-apps/components/panel-app-runtime-surface.tsx +141 -0
  217. package/src/features/{service-apps/components/service-action-authorization-dialog.tsx → panel-apps/components/panel-app-service-action-authorization-dialog.tsx} +4 -4
  218. package/src/features/panel-apps/components/panel-app-toolbar.tsx +5 -0
  219. package/src/features/panel-apps/hooks/use-panel-app-client-grant.ts +2 -2
  220. package/src/features/panel-apps/hooks/{use-panel-app-main-runtime.ts → use-panel-app-runtime.ts} +7 -5
  221. package/src/features/panel-apps/hooks/use-panel-apps.ts +14 -0
  222. package/src/features/panel-apps/index.ts +5 -0
  223. package/src/features/panel-apps/managers/__tests__/panel-app-bridge.manager.test.ts +2 -2
  224. package/src/features/panel-apps/managers/panel-app-bridge.manager.ts +2 -2
  225. package/src/features/panel-apps/managers/panel-app-service-action-authorization.manager.ts +10 -0
  226. package/src/features/panel-apps/pages/__tests__/panel-app-main-page.test.tsx +12 -3
  227. package/src/features/panel-apps/pages/__tests__/panel-app-standalone-page.test.tsx +63 -0
  228. package/src/features/panel-apps/pages/panel-app-main-page.tsx +9 -121
  229. package/src/features/panel-apps/pages/panel-app-standalone-page.tsx +29 -0
  230. package/src/features/panel-apps/presenters/panel-app-host.presenter.ts +9 -0
  231. package/src/features/panel-apps/providers/panel-app-host.provider.tsx +45 -0
  232. package/src/features/panel-apps/routes/__tests__/panel-app-standalone.route.test.tsx +50 -0
  233. package/src/features/panel-apps/routes/panel-app-standalone.route.tsx +94 -0
  234. package/src/features/{service-apps/stores/service-action-authorization.store.ts → panel-apps/stores/panel-app-service-action-authorization.store.ts} +6 -6
  235. package/src/features/projects/AGENTS.md +1 -2
  236. package/src/features/projects/components/project-agreement.tsx +36 -77
  237. package/src/features/projects/components/project-artifacts.test.tsx +90 -62
  238. package/src/features/projects/components/project-artifacts.tsx +81 -160
  239. package/src/features/projects/components/project-materials.test.tsx +80 -0
  240. package/src/features/projects/components/project-overview.test.tsx +80 -0
  241. package/src/features/projects/components/project-overview.tsx +115 -56
  242. package/src/features/projects/components/project-skills.tsx +24 -14
  243. package/src/features/projects/components/work/project-work-item-drawer.test.tsx +3 -2
  244. package/src/features/projects/components/work/project-work-item-drawer.tsx +8 -10
  245. package/src/features/projects/components/work/project-work-items.test.tsx +180 -4
  246. package/src/features/projects/components/work/project-work-items.tsx +278 -50
  247. package/src/features/projects/components/work/project-work-state-settings.tsx +7 -3
  248. package/src/features/projects/hooks/use-project-materials.test.tsx +65 -0
  249. package/src/features/projects/hooks/use-project-materials.ts +24 -0
  250. package/src/features/projects/hooks/use-project-work.test.tsx +165 -7
  251. package/src/features/projects/hooks/use-project-work.ts +88 -9
  252. package/src/features/projects/pages/project-home-page.tsx +52 -89
  253. package/src/features/projects/pages/projects-page.test.tsx +81 -32
  254. package/src/features/projects/presenters/project-home.presenter.test.ts +1 -64
  255. package/src/features/projects/presenters/project-home.presenter.ts +17 -54
  256. package/src/features/projects/utils/project-artifact-view.utils.test.ts +19 -53
  257. package/src/features/projects/utils/project-artifact-view.utils.ts +17 -47
  258. package/src/features/projects/utils/project-work-state-label.utils.test.ts +28 -0
  259. package/src/features/projects/utils/project-work-state-label.utils.ts +20 -0
  260. package/src/features/service-apps/index.ts +3 -3
  261. package/src/main.tsx +3 -0
  262. package/src/shared/hooks/use-auth-status.ts +49 -0
  263. package/src/shared/hooks/use-projects.ts +15 -1
  264. package/src/shared/lib/api/projects/project.utils.ts +4 -0
  265. package/src/shared/lib/i18n/configs/main-i18n-catalog.config.ts +78 -0
  266. package/src/shared/lib/i18n/configs/panel-app-i18n-catalog.config.ts +12 -0
  267. package/src/shared/lib/i18n/index.ts +30 -82
  268. package/src/shared/lib/i18n/locales/en-US/doc-browser.json +0 -55
  269. package/src/shared/lib/i18n/locales/en-US/panel-app.json +59 -0
  270. package/src/shared/lib/i18n/locales/en-US/projects.json +24 -59
  271. package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +0 -55
  272. package/src/shared/lib/i18n/locales/zh-CN/panel-app.json +59 -0
  273. package/src/shared/lib/i18n/locales/zh-CN/projects.json +24 -59
  274. package/vite.config.ts +36 -1
  275. package/dist/assets/api-BqVIq0lF.js +0 -13
  276. package/dist/assets/appearance-settings-page-CTWn1eAT.js +0 -1
  277. package/dist/assets/architecture-TIHT7OUA-DO2x53FK.js +0 -1
  278. package/dist/assets/channel-nBvMaVyP.js +0 -1
  279. package/dist/assets/channels-list-page-Bzn-pzyJ.js +0 -8
  280. package/dist/assets/chunk-2Q5K7J3B-CJgqFDS4.js +0 -1
  281. package/dist/assets/chunk-VAUOI2AC-BGvh3yIx.js +0 -1
  282. package/dist/assets/chunk-XXDRQBXY-DaBxG5gs.js +0 -1
  283. package/dist/assets/classDiagram-OUVF2IWQ-P6N03G2R.js +0 -1
  284. package/dist/assets/classDiagram-v2-EOCWNBFH-B1_uLvMv.js +0 -1
  285. package/dist/assets/config-split-page-CnRbXXlh.js +0 -1
  286. package/dist/assets/confirm-dialog-B_Hbcra2.js +0 -5
  287. package/dist/assets/cynefin-VYW2F7L2-B-H8Qp-n.js +0 -1
  288. package/dist/assets/desktop-capabilities-page-C2ayYQTr.js +0 -1
  289. package/dist/assets/desktop-update-config-C13czpyL.js +0 -1
  290. package/dist/assets/dist-BsF3hfOi.js +0 -1
  291. package/dist/assets/doc-browser-D8dIOo9E.js +0 -1
  292. package/dist/assets/doc-browser-DcuOOtpP.js +0 -1
  293. package/dist/assets/doc-browser-context-Dhsit2Ma.js +0 -1
  294. package/dist/assets/eventmodeling-45OFAUF4-YVtShyFA.js +0 -1
  295. package/dist/assets/extensions-CD6xvKF_.js +0 -1
  296. package/dist/assets/flowDiagram-23GEKE2U-BeKXabVO.js +0 -1
  297. package/dist/assets/form-actions-CC4Wz_lL.js +0 -1
  298. package/dist/assets/gitGraph-TEB2WS4Q-jTSiBj-p.js +0 -1
  299. package/dist/assets/index-BTsbdtv6.js +0 -109
  300. package/dist/assets/index-Bcfy2kTh.css +0 -1
  301. package/dist/assets/info-DKCQHKI2-BIporNWb.js +0 -1
  302. package/dist/assets/loader-circle-B6aFbB-8.js +0 -1
  303. package/dist/assets/mcp-marketplace-page-BtUAypA7.js +0 -1
  304. package/dist/assets/mcp-marketplace-page-r2MmD9xO.js +0 -10
  305. package/dist/assets/model-config-page-DboxoT-I.js +0 -1
  306. package/dist/assets/packet-7NZHBO7P-CuFMADV0.js +0 -1
  307. package/dist/assets/pie-RZYD4A2V-XUeIXhM9.js +0 -1
  308. package/dist/assets/plus-DRsq9Kvs.js +0 -1
  309. package/dist/assets/privacy-settings-page-C2sDBqhb.js +0 -1
  310. package/dist/assets/projects-BcPcx-uD.js +0 -1
  311. package/dist/assets/providers-config-page-CmUFl9RF.js +0 -1
  312. package/dist/assets/radar-I7S5WNFK-D-NNGh1k.js +0 -1
  313. package/dist/assets/railroad-3IZDKUUU-C67_uDaM.js +0 -1
  314. package/dist/assets/railroad-abnf-AHOZXSZD-BZ8Yflnd.js +0 -1
  315. package/dist/assets/railroad-ebnf-EBAXGLYW-B7zO7RoK.js +0 -1
  316. package/dist/assets/railroad-peg-LSFZ7HO6-R63PTgLz.js +0 -1
  317. package/dist/assets/react-BjO9I4WZ.js +0 -8
  318. package/dist/assets/remote-Ci6x91ES.js +0 -1
  319. package/dist/assets/runtime-config-page-cQKNeAjL.js +0 -1
  320. package/dist/assets/search-config-page-C8lOIkxn.js +0 -1
  321. package/dist/assets/secrets-config-page-8clzAag2.js +0 -3
  322. package/dist/assets/security-config-DPbM6IVT.js +0 -1
  323. package/dist/assets/select-CO9S_C2C.js +0 -41
  324. package/dist/assets/skeleton-IHILNhIW.js +0 -1
  325. package/dist/assets/stateDiagram-v2-6OUMAXLB-BE-HqxOK.js +0 -1
  326. package/dist/assets/swimlanesDiagram-G3AALYLV-Dr1H9LJH.js +0 -8
  327. package/dist/assets/treeView-QDETBFTQ-npJ5dbqS.js +0 -1
  328. package/dist/assets/treemap-6X3UGDF4-pYrBx6oa.js +0 -1
  329. package/dist/assets/wardley-OPB4EBWU-CmSRKLR8.js +0 -1
  330. package/dist/assets/x-BuvHIb1d.js +0 -1
  331. package/src/features/projects/components/project-requests.tsx +0 -57
  332. package/src/features/projects/components/project-runs.tsx +0 -60
  333. package/src/features/projects/hooks/use-project-observation.test.tsx +0 -93
  334. package/src/features/projects/hooks/use-project-observation.ts +0 -115
  335. package/src/features/projects/utils/project-request-response.utils.test.ts +0 -44
  336. package/src/features/projects/utils/project-request-response.utils.ts +0 -39
  337. package/src/features/service-apps/managers/service-action-authorization.manager.ts +0 -10
  338. /package/dist/assets/{array-BQVzeGRt.js → array-BHDgItFN.js} +0 -0
  339. /package/dist/assets/{chunk-DseTPa7n.js → chunk-DF37yw5_.js} +0 -0
  340. /package/dist/assets/{chunk-KEIR6QF5-f9psyCXK.js → chunk-KEIR6QF5-DstBw0Hk.js} +0 -0
  341. /package/dist/assets/{chunk-Y2CYZVJY-D1mAU_Po.js → chunk-Y2CYZVJY-CA3ymQuH.js} +0 -0
  342. /package/dist/assets/{config-hints-nV5HPOvq.js → config-hints-CBPHrfYk.js} +0 -0
  343. /package/dist/assets/{cytoscape.esm-0uDtdD0l.js → cytoscape.esm-C7xr90o_.js} +0 -0
  344. /package/dist/assets/{defaultLocale-DSWXGgt0.js → defaultLocale-BG1oDVag.js} +0 -0
  345. /package/dist/assets/{graphlib-CQ6QV4yP.js → graphlib-CNMGfuTb.js} +0 -0
  346. /package/dist/assets/{host-capabilities-Tk038i04.js → host-capabilities-B107nwS3.js} +0 -0
  347. /package/dist/assets/{init-Y6h9jGtZ.js → init-wQIZuRSH.js} +0 -0
  348. /package/dist/assets/{katex-ARhY9PS1.js → katex-J8JuvgNl.js} +0 -0
  349. /package/dist/assets/{middleware-DXsbf9xI.js → middleware-0o3JF3tS.js} +0 -0
  350. /package/dist/assets/{path-10BjdyLh.js → path-N-C4MRP0.js} +0 -0
  351. /package/dist/assets/{preload-helper-D4M6sveU.js → preload-helper-ca-nBW7U.js} +0 -0
  352. /package/dist/assets/{rough.esm-DxgC_14r.js → rough.esm-BeWA068d.js} +0 -0
  353. /package/dist/assets/{xlsx-DrDuDNAa.js → xlsx-CwUXNtD3.js} +0 -0
@@ -1,187 +1,108 @@
1
- import { useMemo, useState } from "react";
2
- import type { ProjectObservationSnapshot } from "@nextclaw/client-sdk";
1
+ import { useState } from "react";
2
+ import { useProjectArtifacts } from "@/features/projects/hooks/use-project-work";
3
+ import { formatProjectRelativeTime } from "@/features/projects/utils/project-artifact-view.utils";
3
4
  import { formatDateTime, formatNumber, t } from "@/shared/lib/i18n";
4
- import {
5
- Select,
6
- SelectContent,
7
- SelectItem,
8
- SelectTrigger,
9
- SelectValue,
10
- } from "@/shared/components/ui/select";
11
5
  import { ProjectEmptyState, ProjectFilePreviewButton } from "./project-section";
12
- import {
13
- DEFAULT_PROJECT_ARTIFACT_SORT,
14
- formatProjectRelativeTime,
15
- sortProjectArtifacts,
16
- type ProjectArtifactSort,
17
- } from "../utils/project-artifact-view.utils";
18
6
 
19
- const INITIAL_VISIBLE_COUNT = 10;
20
-
21
- type ArtifactGroup = {
22
- id: string;
23
- label: string;
24
- artifacts: ProjectObservationSnapshot["artifacts"];
25
- };
26
-
27
- function createArtifactGroups(
28
- snapshot: ProjectObservationSnapshot,
29
- query: string,
30
- sort: ProjectArtifactSort,
31
- ): ArtifactGroup[] {
32
- const normalizedQuery = query.trim().toLocaleLowerCase();
33
- const filteredArtifacts = normalizedQuery
34
- ? snapshot.artifacts.filter((artifact) => artifact.path.toLocaleLowerCase().includes(normalizedQuery))
35
- : snapshot.artifacts;
36
- const artifacts = sortProjectArtifacts(filteredArtifacts, sort);
37
- const artifactsByCategory = new Map<string, ProjectObservationSnapshot["artifacts"]>();
38
- for (const artifact of artifacts) {
39
- const group = artifactsByCategory.get(artifact.categoryId) ?? [];
40
- group.push(artifact);
41
- artifactsByCategory.set(artifact.categoryId, group);
42
- }
43
- const configuredCategories = snapshot.artifactCategories ?? [];
44
- const configuredIds = new Set(configuredCategories.map((category) => category.id));
45
- const groups = configuredCategories.flatMap((category) => {
46
- const groupArtifacts = artifactsByCategory.get(category.id) ?? [];
47
- return groupArtifacts.length ? [{ ...category, artifacts: groupArtifacts }] : [];
48
- });
49
- const unconfiguredGroups = [...artifactsByCategory.entries()]
50
- .filter(([categoryId]) => !configuredIds.has(categoryId))
51
- .map(([id, groupArtifacts]) => ({
52
- id,
53
- label: groupArtifacts[0]?.categoryLabel ?? id,
54
- artifacts: groupArtifacts,
55
- }))
56
- .sort((left, right) => left.label.localeCompare(right.label));
57
- return [...groups, ...unconfiguredGroups];
58
- }
7
+ const PAGE_SIZE = 20;
59
8
 
60
9
  export function ProjectArtifacts({
61
- snapshot,
10
+ projectId,
62
11
  onOpenFile,
63
12
  }: {
64
- snapshot: ProjectObservationSnapshot;
13
+ projectId: string;
65
14
  onOpenFile: (path: string, label: string) => void;
66
15
  }) {
67
16
  const [query, setQuery] = useState("");
68
- const [sort, setSort] = useState<ProjectArtifactSort>(DEFAULT_PROJECT_ARTIFACT_SORT);
69
- const [collapsedGroups, setCollapsedGroups] = useState<Set<string>>(() => new Set());
70
- const [visibleCounts, setVisibleCounts] = useState<Record<string, number>>({});
71
- const groups = useMemo(() => createArtifactGroups(snapshot, query, sort), [query, snapshot, sort]);
72
- const canSortByCreated = snapshot.artifacts.some((artifact) => artifact.fileCreatedAt);
17
+ const artifacts = useProjectArtifacts(projectId, {
18
+ limit: PAGE_SIZE,
19
+ ...(query.trim() ? { query: query.trim() } : {}),
20
+ });
21
+ const pages = artifacts.data?.pages ?? [];
22
+ const items = pages.flatMap((page) => page.artifacts);
23
+ const total = pages[0]?.total ?? 0;
73
24
 
74
- if (!snapshot.artifacts.length) {
75
- return <ProjectEmptyState>{t("projectsNoArtifacts")}</ProjectEmptyState>;
25
+ if (artifacts.isLoading) {
26
+ return (
27
+ <p className="py-5 text-sm text-muted-foreground">
28
+ {t("projectsLoading")}
29
+ </p>
30
+ );
31
+ }
32
+ if (artifacts.isError) {
33
+ return (
34
+ <p className="py-5 text-sm text-destructive">{t("projectsLoadFailed")}</p>
35
+ );
76
36
  }
77
37
 
78
38
  return (
79
39
  <section className="min-w-0" aria-label={t("projectsArtifacts")}>
80
40
  <div className="mb-4 flex flex-wrap items-center justify-between gap-3">
81
41
  <p className="text-sm text-muted-foreground">
82
- {formatNumber(snapshot.artifacts.length)} {t("projectsArtifactsCountSuffix")}
42
+ {formatNumber(total)} {t("projectsArtifactsCountSuffix")}
83
43
  </p>
84
- <div className="flex w-full flex-wrap items-center gap-2 sm:w-auto">
85
- <Select value={sort} onValueChange={(value) => setSort(value as ProjectArtifactSort)}>
86
- <SelectTrigger aria-label={t("projectsArtifactsSort")} className="h-8 w-32 rounded-lg">
87
- <SelectValue />
88
- </SelectTrigger>
89
- <SelectContent>
90
- <SelectItem value="updated-desc">{t("projectsArtifactsSortUpdatedDesc")}</SelectItem>
91
- <SelectItem value="updated-asc">{t("projectsArtifactsSortUpdatedAsc")}</SelectItem>
92
- {canSortByCreated ? (
93
- <SelectItem value="created-desc">{t("projectsArtifactsSortCreatedDesc")}</SelectItem>
94
- ) : null}
95
- <SelectItem value="name">{t("projectsArtifactsSortName")}</SelectItem>
96
- </SelectContent>
97
- </Select>
98
- <input
99
- type="search"
100
- value={query}
101
- className="h-8 min-w-0 flex-1 rounded-lg border border-border/60 bg-transparent px-3 text-sm outline-none placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-border sm:w-60"
102
- placeholder={t("projectsArtifactsSearchPlaceholder")}
103
- onChange={(event) => {
104
- setQuery(event.target.value);
105
- setVisibleCounts({});
106
- }}
107
- />
108
- </div>
44
+ <input
45
+ type="search"
46
+ value={query}
47
+ className="h-8 w-full min-w-0 rounded-lg border border-border/60 bg-transparent px-3 text-sm outline-none placeholder:text-muted-foreground sm:w-60"
48
+ placeholder={t("projectsArtifactsSearchPlaceholder")}
49
+ onChange={(event) => setQuery(event.target.value)}
50
+ />
109
51
  </div>
110
- {groups.length ? (
111
- <div className="space-y-2">
112
- {groups.map((group) => {
113
- const collapsed = collapsedGroups.has(group.id);
114
- const visibleCount = visibleCounts[group.id] ?? INITIAL_VISIBLE_COUNT;
115
- const visibleArtifacts = group.artifacts.slice(0, visibleCount);
116
- return (
117
- <section key={group.id} className="overflow-hidden rounded-xl border border-border/60">
118
- <button
119
- type="button"
120
- className="flex w-full items-center justify-between gap-3 bg-muted/30 px-3 py-2.5 text-left text-sm transition-colors hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
121
- aria-label={`${group.label} ${formatNumber(group.artifacts.length)}`}
122
- aria-expanded={!collapsed}
123
- onClick={() => setCollapsedGroups((current) => {
124
- const next = new Set(current);
125
- if (next.has(group.id)) next.delete(group.id);
126
- else next.add(group.id);
127
- return next;
128
- })}
52
+ {items.length ? (
53
+ <div className="overflow-hidden rounded-xl border border-border/60">
54
+ <div className="divide-y divide-border/60">
55
+ {items.map((artifact) => (
56
+ <ProjectFilePreviewButton
57
+ key={artifact.id}
58
+ available={artifact.exists}
59
+ path={artifact.path}
60
+ label={artifact.label ?? artifact.path}
61
+ onOpen={onOpenFile}
62
+ className="flex w-full min-w-0 items-center gap-3 px-3 py-3 text-left text-sm transition-colors enabled:hover:bg-[var(--interaction-hover)] enabled:focus-visible:outline-none enabled:focus-visible:ring-1 enabled:focus-visible:ring-border"
63
+ >
64
+ <span className="min-w-0 flex-1">
65
+ <span className="block truncate font-medium">
66
+ {artifact.label ?? artifact.path}
67
+ </span>
68
+ <span className="mt-1 block truncate text-xs text-muted-foreground">
69
+ {artifact.path} · {artifact.workItemTitle}
70
+ </span>
71
+ </span>
72
+ <time
73
+ className="shrink-0 text-xs text-muted-foreground"
74
+ dateTime={artifact.createdAt}
75
+ title={formatDateTime(artifact.createdAt)}
129
76
  >
130
- <span className="min-w-0 truncate font-medium">{group.label}</span>
131
- <span className="shrink-0 text-xs text-muted-foreground">
132
- {formatNumber(group.artifacts.length)} {collapsed ? "▸" : "▾"}
77
+ {formatProjectRelativeTime(artifact.createdAt)}
78
+ </time>
79
+ {!artifact.exists ? (
80
+ <span className="shrink-0 text-xs text-destructive">
81
+ {t("projectsUnavailable")}
133
82
  </span>
134
- </button>
135
- {!collapsed ? (
136
- <div className="divide-y divide-border/60">
137
- {visibleArtifacts.map((artifact) => (
138
- <ProjectFilePreviewButton
139
- key={artifact.id}
140
- available={artifact.exists}
141
- path={artifact.path}
142
- label={artifact.path}
143
- onOpen={onOpenFile}
144
- className="flex w-full min-w-0 items-center gap-3 px-3 py-2.5 text-left text-sm transition-colors enabled:hover:bg-[var(--interaction-hover)] enabled:focus-visible:outline-none enabled:focus-visible:ring-1 enabled:focus-visible:ring-border"
145
- >
146
- <span className="min-w-0 flex-1 truncate">{artifact.path}</span>
147
- {artifact.fileUpdatedAt ? (
148
- <time
149
- className="shrink-0 text-xs text-muted-foreground"
150
- dateTime={artifact.fileUpdatedAt}
151
- title={formatDateTime(artifact.fileUpdatedAt)}
152
- >
153
- {formatProjectRelativeTime(artifact.fileUpdatedAt)}
154
- </time>
155
- ) : null}
156
- {!artifact.exists ? (
157
- <span className="shrink-0 text-xs text-destructive">
158
- {t("projectsUnavailable")}
159
- </span>
160
- ) : null}
161
- </ProjectFilePreviewButton>
162
- ))}
163
- {group.artifacts.length > visibleArtifacts.length ? (
164
- <button
165
- type="button"
166
- className="w-full px-3 py-2.5 text-left text-sm text-muted-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
167
- onClick={() => setVisibleCounts((current) => ({
168
- ...current,
169
- [group.id]: visibleCount + INITIAL_VISIBLE_COUNT,
170
- }))}
171
- >
172
- {t("projectsArtifactsShowMore")} ({formatNumber(
173
- Math.min(INITIAL_VISIBLE_COUNT, group.artifacts.length - visibleArtifacts.length),
174
- )})
175
- </button>
176
- ) : null}
177
- </div>
178
83
  ) : null}
179
- </section>
180
- );
181
- })}
84
+ </ProjectFilePreviewButton>
85
+ ))}
86
+ </div>
87
+ {artifacts.hasNextPage ? (
88
+ <button
89
+ type="button"
90
+ className="w-full border-t border-border/60 px-3 py-2.5 text-left text-sm text-muted-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
91
+ disabled={artifacts.isFetchingNextPage}
92
+ onClick={() => void artifacts.fetchNextPage()}
93
+ >
94
+ {artifacts.isFetchingNextPage
95
+ ? t("projectsLoading")
96
+ : t("projectsArtifactsShowMore")}
97
+ </button>
98
+ ) : null}
182
99
  </div>
183
100
  ) : (
184
- <ProjectEmptyState>{t("projectsArtifactsNoMatches")}</ProjectEmptyState>
101
+ <ProjectEmptyState>
102
+ {query.trim()
103
+ ? t("projectsArtifactsNoMatches")
104
+ : t("projectsNoArtifacts")}
105
+ </ProjectEmptyState>
185
106
  )}
186
107
  </section>
187
108
  );
@@ -0,0 +1,80 @@
1
+ import { fireEvent, render, screen } from "@testing-library/react";
2
+ import { describe, expect, it, vi } from "vitest";
3
+ import { ProjectAgreement } from "./project-agreement";
4
+ import { ProjectSkills } from "./project-skills";
5
+
6
+ describe("project materials", () => {
7
+ it("opens the root agreement and renders a missing-file empty state", () => {
8
+ const onOpenFile = vi.fn();
9
+ const { rerender } = render(
10
+ <ProjectAgreement
11
+ agreement={{ path: "AGENTS.md", available: true }}
12
+ isLoading={false}
13
+ isError={false}
14
+ onOpenFile={onOpenFile}
15
+ />,
16
+ );
17
+
18
+ fireEvent.click(screen.getByRole("button", { name: /AGENTS\.md/ }));
19
+ expect(onOpenFile).toHaveBeenCalledWith("AGENTS.md", "AGENTS.md");
20
+
21
+ rerender(
22
+ <ProjectAgreement
23
+ agreement={{ path: "AGENTS.md", available: false }}
24
+ isLoading={false}
25
+ isError={false}
26
+ onOpenFile={onOpenFile}
27
+ />,
28
+ );
29
+ expect(
30
+ screen.getByText(/No AGENTS\.md exists|还没有 AGENTS\.md/),
31
+ ).toBeTruthy();
32
+ });
33
+
34
+ it("opens project skills from the fixed source and renders an empty state", () => {
35
+ const onOpen = vi.fn();
36
+ const skill = {
37
+ ref: "project:alpha",
38
+ name: "alpha",
39
+ description: "Alpha project skill",
40
+ path: ".agents/skills/alpha/SKILL.md",
41
+ };
42
+ const { rerender } = render(
43
+ <ProjectSkills
44
+ skills={[skill]}
45
+ isLoading={false}
46
+ isError={false}
47
+ onOpen={onOpen}
48
+ />,
49
+ );
50
+
51
+ fireEvent.click(screen.getByRole("button", { name: /alpha/ }));
52
+ expect(onOpen).toHaveBeenCalledWith(skill);
53
+
54
+ rerender(
55
+ <ProjectSkills
56
+ skills={[]}
57
+ isLoading={false}
58
+ isError={false}
59
+ onOpen={onOpen}
60
+ />,
61
+ );
62
+ expect(
63
+ screen.getByText(/No project Skills found|暂无项目 Skills/),
64
+ ).toBeTruthy();
65
+ });
66
+
67
+ it("shows bounded loading and error states", () => {
68
+ const { rerender } = render(
69
+ <ProjectSkills skills={[]} isLoading isError={false} onOpen={vi.fn()} />,
70
+ );
71
+ expect(screen.getByText(/Loading project|正在读取项目/)).toBeTruthy();
72
+
73
+ rerender(
74
+ <ProjectSkills skills={[]} isLoading={false} isError onOpen={vi.fn()} />,
75
+ );
76
+ expect(
77
+ screen.getByText(/Failed to load project|项目读取失败/),
78
+ ).toBeTruthy();
79
+ });
80
+ });
@@ -0,0 +1,80 @@
1
+ import { fireEvent, render, screen } from "@testing-library/react";
2
+ import { describe, expect, it, vi } from "vitest";
3
+ import { ProjectOverview } from "./project-overview";
4
+
5
+ vi.mock(
6
+ "@/features/projects/hooks/use-project-work",
7
+ async (importOriginal) => ({
8
+ ...(await importOriginal()),
9
+ useProjectWorkEvents: vi.fn(),
10
+ useProjectWorkSummary: () => ({
11
+ data: { total: 4, active: 2, attention: 1, completed: 1 },
12
+ isLoading: false,
13
+ isError: false,
14
+ }),
15
+ useProjectWork: () => ({
16
+ data: {
17
+ pages: [
18
+ {
19
+ items: [
20
+ {
21
+ id: "work-1",
22
+ title: "Current work",
23
+ state: { name: "In Progress" },
24
+ },
25
+ ],
26
+ },
27
+ ],
28
+ },
29
+ isLoading: false,
30
+ isError: false,
31
+ }),
32
+ useProjectArtifacts: () => ({
33
+ data: {
34
+ pages: [
35
+ {
36
+ artifacts: [
37
+ {
38
+ id: "artifact-1",
39
+ path: "docs/design.md",
40
+ label: "Design",
41
+ workItemTitle: "Current work",
42
+ createdAt: "2026-09-03T00:00:00.000Z",
43
+ exists: true,
44
+ },
45
+ ],
46
+ nextCursor: null,
47
+ total: 1,
48
+ },
49
+ ],
50
+ },
51
+ isLoading: false,
52
+ isError: false,
53
+ }),
54
+ }),
55
+ );
56
+
57
+ describe("ProjectOverview", () => {
58
+ it("renders current work and recent artifacts as equal wide-layout columns", () => {
59
+ const onOpenWorkItem = vi.fn();
60
+ const onOpenArtifact = vi.fn();
61
+ const { container } = render(
62
+ <ProjectOverview
63
+ projectId="project-1"
64
+ onOpenWorkItem={onOpenWorkItem}
65
+ onOpenArtifact={onOpenArtifact}
66
+ />,
67
+ );
68
+
69
+ expect(screen.getByText(/Recently updated|最近更新/)).toBeTruthy();
70
+ expect(screen.getByText(/Recent artifacts|最近产物/)).toBeTruthy();
71
+ expect(container.querySelector(".lg\\:grid-cols-2")).toBeTruthy();
72
+
73
+ fireEvent.click(
74
+ screen.getAllByRole("button", { name: /Current work/ })[0]!,
75
+ );
76
+ fireEvent.click(screen.getByRole("button", { name: /Design/ }));
77
+ expect(onOpenWorkItem).toHaveBeenCalledWith("work-1");
78
+ expect(onOpenArtifact).toHaveBeenCalledWith("docs/design.md", "Design");
79
+ });
80
+ });
@@ -1,81 +1,140 @@
1
- import { t } from "@/shared/lib/i18n";
1
+ import { formatDateTime, t } from "@/shared/lib/i18n";
2
2
  import {
3
+ useProjectArtifacts,
3
4
  useProjectWork,
5
+ useProjectWorkEvents,
4
6
  useProjectWorkSummary,
5
7
  } from "@/features/projects/hooks/use-project-work";
8
+ import { getProjectWorkStateLabel } from "@/features/projects/utils/project-work-state-label.utils";
9
+ import { formatProjectRelativeTime } from "@/features/projects/utils/project-artifact-view.utils";
10
+ import {
11
+ ProjectEmptyState,
12
+ ProjectFilePreviewButton,
13
+ ProjectSection,
14
+ } from "./project-section";
6
15
 
7
16
  export function ProjectOverview({
8
17
  projectId,
18
+ onOpenArtifact,
9
19
  onOpenWorkItem,
10
20
  }: {
11
21
  projectId: string;
22
+ onOpenArtifact: (path: string, label: string) => void;
12
23
  onOpenWorkItem: (workItemId: string) => void;
13
24
  }) {
25
+ useProjectWorkEvents(projectId);
14
26
  const summary = useProjectWorkSummary(projectId);
15
- const work = useProjectWork(projectId);
16
- if (summary.isLoading || work.isLoading)
17
- return (
18
- <div className="rounded-xl border border-border/60 p-5 text-sm text-muted-foreground">
19
- {t("projectsLoading")}
20
- </div>
21
- );
22
- if (summary.isError || work.isError)
23
- return (
24
- <div className="rounded-xl border border-destructive/40 p-5 text-sm text-destructive">
25
- {t("projectsLoadFailed")}
26
- </div>
27
- );
28
- const recent = work.data!.items.slice(0, 5);
27
+ const work = useProjectWork(projectId, { limit: 5 });
28
+ const artifacts = useProjectArtifacts(projectId, { limit: 5 });
29
+ const recentArtifacts = artifacts.data?.pages[0]?.artifacts ?? [];
30
+ const recent =
31
+ work.data?.pages.flatMap((page) => page.items).slice(0, 5) ?? [];
29
32
  return (
30
33
  <div className="space-y-5">
31
34
  <section
32
35
  className="grid gap-3 sm:grid-cols-2 lg:grid-cols-4"
33
36
  aria-label={t("projectsWorkSummary")}
34
37
  >
35
- {(
36
- [
37
- ["projectsWorkTotal", summary.data!.total],
38
- ["projectsWorkActive", summary.data!.active],
39
- ["projectsWorkNeedsAttention", summary.data!.attention],
40
- ["projectsWorkCompleted", summary.data!.completed],
41
- ] as const
42
- ).map(([label, value]) => (
43
- <div
44
- key={label}
45
- className="rounded-xl border border-border/60 bg-card p-4"
46
- >
47
- <div className="text-2xl font-semibold">{value}</div>
48
- <div className="mt-1 text-xs text-muted-foreground">{t(label)}</div>
49
- </div>
50
- ))}
51
- </section>
52
- <section>
53
- <h2 className="mb-3 text-sm font-semibold">
54
- {t("projectsWorkRecentlyUpdated")}
55
- </h2>
56
- <div className="space-y-2">
57
- {recent.map((item) => (
58
- <button
59
- key={item.id}
60
- type="button"
61
- className="flex w-full items-center justify-between gap-3 rounded-xl border border-border/60 bg-card px-4 py-3 text-left hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
62
- onClick={() => onOpenWorkItem(item.id)}
38
+ {summary.data ? (
39
+ (
40
+ [
41
+ ["projectsWorkTotal", summary.data!.total],
42
+ ["projectsWorkActive", summary.data!.active],
43
+ ["projectsWorkNeedsAttention", summary.data!.attention],
44
+ ["projectsWorkCompleted", summary.data!.completed],
45
+ ] as const
46
+ ).map(([label, value]) => (
47
+ <div
48
+ key={label}
49
+ className="rounded-xl border border-border/60 bg-card p-4"
63
50
  >
64
- <span className="min-w-0 truncate text-sm font-medium">
65
- {item.title}
66
- </span>
67
- <span className="shrink-0 text-xs text-muted-foreground">
68
- {item.state.name}
69
- </span>
70
- </button>
71
- ))}
72
- {!recent.length ? (
73
- <div className="rounded-xl border border-dashed border-border/60 p-8 text-center text-sm text-muted-foreground">
74
- {t("projectsWorkEmpty")}
51
+ <div className="text-2xl font-semibold">{value}</div>
52
+ <div className="mt-1 text-xs text-muted-foreground">
53
+ {t(label)}
54
+ </div>
75
55
  </div>
76
- ) : null}
77
- </div>
56
+ ))
57
+ ) : (
58
+ <div className="col-span-full rounded-xl border border-border/60 p-5 text-sm text-muted-foreground">
59
+ {summary.isError ? t("projectsLoadFailed") : t("projectsLoading")}
60
+ </div>
61
+ )}
78
62
  </section>
63
+ <div className="grid min-w-0 gap-4 lg:grid-cols-2">
64
+ <ProjectSection title={t("projectsWorkRecentlyUpdated")}>
65
+ {work.isLoading ? (
66
+ <p className="py-5 text-sm text-muted-foreground">
67
+ {t("projectsLoading")}
68
+ </p>
69
+ ) : work.isError ? (
70
+ <p className="py-5 text-sm text-destructive">
71
+ {t("projectsLoadFailed")}
72
+ </p>
73
+ ) : recent.length ? (
74
+ <div className="space-y-2">
75
+ {recent.map((item) => (
76
+ <button
77
+ key={item.id}
78
+ type="button"
79
+ className="flex w-full items-center justify-between gap-3 rounded-xl bg-muted/45 px-3 py-3 text-left transition-colors hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
80
+ onClick={() => onOpenWorkItem(item.id)}
81
+ >
82
+ <span className="min-w-0 truncate text-sm font-medium">
83
+ {item.title}
84
+ </span>
85
+ <span className="shrink-0 text-xs text-muted-foreground">
86
+ {getProjectWorkStateLabel(item.state.name)}
87
+ </span>
88
+ </button>
89
+ ))}
90
+ </div>
91
+ ) : (
92
+ <ProjectEmptyState>{t("projectsWorkEmpty")}</ProjectEmptyState>
93
+ )}
94
+ </ProjectSection>
95
+ <ProjectSection title={t("projectsRecentArtifacts")}>
96
+ {artifacts.isLoading ? (
97
+ <p className="py-5 text-sm text-muted-foreground">
98
+ {t("projectsLoading")}
99
+ </p>
100
+ ) : artifacts.isError ? (
101
+ <p className="py-5 text-sm text-destructive">
102
+ {t("projectsLoadFailed")}
103
+ </p>
104
+ ) : recentArtifacts.length ? (
105
+ <div className="space-y-2">
106
+ {recentArtifacts.map((artifact) => (
107
+ <ProjectFilePreviewButton
108
+ key={artifact.id}
109
+ available={artifact.exists}
110
+ path={artifact.path}
111
+ label={artifact.label ?? artifact.path}
112
+ onOpen={onOpenArtifact}
113
+ className="block w-full rounded-xl bg-muted/45 p-3 text-left text-sm transition-colors enabled:hover:bg-[var(--interaction-hover)] enabled:focus-visible:outline-none enabled:focus-visible:ring-1 enabled:focus-visible:ring-border"
114
+ >
115
+ <span className="block truncate font-medium">
116
+ {artifact.label ?? artifact.path}
117
+ </span>
118
+ <span className="mt-1 block truncate text-xs text-muted-foreground">
119
+ {artifact.workItemTitle}
120
+ <time
121
+ dateTime={artifact.createdAt}
122
+ title={formatDateTime(artifact.createdAt)}
123
+ >
124
+ {` · ${formatProjectRelativeTime(artifact.createdAt)}`}
125
+ </time>
126
+ {!artifact.exists ? ` · ${t("projectsUnavailable")}` : ""}
127
+ </span>
128
+ </ProjectFilePreviewButton>
129
+ ))}
130
+ </div>
131
+ ) : (
132
+ <ProjectEmptyState>
133
+ {t("projectsNoRecentArtifacts")}
134
+ </ProjectEmptyState>
135
+ )}
136
+ </ProjectSection>
137
+ </div>
79
138
  </div>
80
139
  );
81
140
  }