@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
@@ -5,20 +5,21 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
5
5
  import { ProjectsPage } from "./project-home-page";
6
6
 
7
7
  const mocks = vi.hoisted(() => ({
8
+ agreementProps: vi.fn(),
9
+ artifactsProps: vi.fn(),
8
10
  drawerProps: vi.fn(),
9
- useProjectObservation: vi.fn(),
11
+ skillsProps: vi.fn(),
12
+ useProjectAgreement: vi.fn(),
13
+ useProjectSkills: vi.fn(),
10
14
  useProjects: vi.fn(),
11
15
  }));
12
16
 
13
17
  vi.mock("@/shared/hooks/use-projects", () => ({
14
18
  useProjects: mocks.useProjects,
15
19
  }));
16
- vi.mock("@/features/projects/hooks/use-project-observation", () => ({
17
- projectObservationQueryKey: (projectId: string) => [
18
- "project-observation",
19
- projectId,
20
- ],
21
- useProjectObservation: mocks.useProjectObservation,
20
+ vi.mock("@/features/projects/hooks/use-project-materials", () => ({
21
+ useProjectAgreement: mocks.useProjectAgreement,
22
+ useProjectSkills: mocks.useProjectSkills,
22
23
  }));
23
24
  vi.mock("@/features/chat", () => ({
24
25
  ChatConversationWorkspaceSection: () => <div data-testid="workspace" />,
@@ -52,18 +53,23 @@ vi.mock("@/features/projects/components/work/project-work-item-drawer", () => ({
52
53
  },
53
54
  }));
54
55
  vi.mock("@/features/projects/components/project-artifacts", () => ({
55
- ProjectArtifacts: () => <div>Artifact content</div>,
56
+ ProjectArtifacts: (props: { projectId: string }) => {
57
+ mocks.artifactsProps(props);
58
+ return <div>Artifact content</div>;
59
+ },
56
60
  }));
57
61
  vi.mock("@/features/projects/components/project-skills", () => ({
58
- ProjectSkills: () => <div>Skills content</div>,
62
+ ProjectSkills: (props: { skills: unknown[] }) => {
63
+ mocks.skillsProps(props);
64
+ return <div>Skills content</div>;
65
+ },
59
66
  }));
60
67
  vi.mock("@/features/projects/components/project-agreement", () => ({
61
- ProjectAgreement: () => <div>Agreement content</div>,
62
- }));
63
- vi.mock("@/features/projects/components/project-requests", () => ({
64
- ProjectRequests: () => null,
68
+ ProjectAgreement: (props: { agreement?: unknown }) => {
69
+ mocks.agreementProps(props);
70
+ return <div>Agreement content</div>;
71
+ },
65
72
  }));
66
-
67
73
  function renderPage(path: string) {
68
74
  return render(
69
75
  <QueryClientProvider client={new QueryClient()}>
@@ -80,6 +86,9 @@ function renderPage(path: string) {
80
86
  describe("ProjectsPage", () => {
81
87
  beforeEach(() => {
82
88
  mocks.drawerProps.mockReset();
89
+ mocks.agreementProps.mockReset();
90
+ mocks.artifactsProps.mockReset();
91
+ mocks.skillsProps.mockReset();
83
92
  mocks.useProjects.mockReturnValue({
84
93
  data: {
85
94
  projects: [
@@ -89,38 +98,35 @@ describe("ProjectsPage", () => {
89
98
  isLoading: false,
90
99
  isError: false,
91
100
  });
92
- mocks.useProjectObservation.mockReturnValue({
101
+ mocks.useProjectAgreement.mockReturnValue({
102
+ data: undefined,
103
+ isLoading: false,
104
+ isError: false,
105
+ });
106
+ mocks.useProjectSkills.mockReturnValue({
93
107
  data: undefined,
94
108
  isLoading: false,
95
109
  isError: false,
96
110
  });
97
111
  });
98
112
 
99
- it("keeps overview scan-free and opens its work item in the unified drawer", () => {
113
+ it("keeps overview material-free and opens its work item in the unified drawer", () => {
100
114
  renderPage("/projects/project-1/overview");
101
115
 
102
- expect(mocks.useProjectObservation).toHaveBeenCalledWith(
103
- "project-1",
104
- "/tmp/research",
105
- false,
106
- );
116
+ expect(mocks.useProjectAgreement).toHaveBeenCalledWith(null);
117
+ expect(mocks.useProjectSkills).toHaveBeenCalledWith(null);
107
118
  expect(screen.getAllByRole("tab")).toHaveLength(5);
108
119
  fireEvent.click(screen.getByRole("button", { name: "Overview work" }));
109
120
  expect(screen.getByTestId("work-drawer").textContent).toBe("work-overview");
110
121
  });
111
122
 
112
- it("enables legacy observation only for preserved artifact, skill, and agreement surfaces", () => {
113
- mocks.useProjectObservation.mockReturnValue({
114
- data: { requests: [] },
115
- isLoading: false,
116
- isError: false,
117
- });
123
+ it("loads artifacts from project work without material observation", () => {
118
124
  renderPage("/projects/project-1/artifacts");
119
125
 
120
- expect(mocks.useProjectObservation).toHaveBeenCalledWith(
121
- "project-1",
122
- "/tmp/research",
123
- true,
126
+ expect(mocks.useProjectAgreement).toHaveBeenCalledWith(null);
127
+ expect(mocks.useProjectSkills).toHaveBeenCalledWith(null);
128
+ expect(mocks.artifactsProps).toHaveBeenCalledWith(
129
+ expect.objectContaining({ projectId: "project-1" }),
124
130
  );
125
131
  expect(screen.getByText("Artifact content")).toBeTruthy();
126
132
  expect(screen.getByRole("tab", { name: /Skills/ })).toBeTruthy();
@@ -131,7 +137,50 @@ describe("ProjectsPage", () => {
131
137
 
132
138
  it("asks the user to choose from the sidebar when no project route is selected", () => {
133
139
  renderPage("/projects");
134
- expect(mocks.useProjectObservation).toHaveBeenCalledWith(null, null, false);
140
+ expect(mocks.useProjectAgreement).toHaveBeenCalledWith(null);
141
+ expect(mocks.useProjectSkills).toHaveBeenCalledWith(null);
135
142
  expect(screen.getByText(/Choose a project|选择项目/)).toBeTruthy();
136
143
  });
144
+
145
+ it("loads each fixed project material only on its own tab", () => {
146
+ mocks.useProjectAgreement.mockReturnValue({
147
+ data: { path: "AGENTS.md", available: true },
148
+ isLoading: false,
149
+ isError: false,
150
+ });
151
+ const { unmount } = renderPage("/projects/project-1/agreement");
152
+ expect(mocks.useProjectAgreement).toHaveBeenCalledWith("project-1");
153
+ expect(mocks.useProjectSkills).toHaveBeenCalledWith(null);
154
+ expect(mocks.agreementProps).toHaveBeenCalledWith(
155
+ expect.objectContaining({
156
+ agreement: { path: "AGENTS.md", available: true },
157
+ }),
158
+ );
159
+ unmount();
160
+
161
+ mocks.useProjectSkills.mockReturnValue({
162
+ data: [{ ref: "project:alpha", name: "alpha" }],
163
+ isLoading: false,
164
+ isError: false,
165
+ });
166
+ renderPage("/projects/project-1/skills");
167
+ expect(mocks.useProjectAgreement).toHaveBeenLastCalledWith(null);
168
+ expect(mocks.useProjectSkills).toHaveBeenLastCalledWith("project-1");
169
+ expect(mocks.skillsProps).toHaveBeenCalledWith(
170
+ expect.objectContaining({
171
+ skills: [{ ref: "project:alpha", name: "alpha" }],
172
+ }),
173
+ );
174
+ });
175
+
176
+ it("does not expose project removal as a persistent detail-page action", () => {
177
+ renderPage("/projects/project-1/overview");
178
+
179
+ expect(
180
+ screen.queryByRole("button", {
181
+ name: /Remove from project list|从项目列表移除/,
182
+ }),
183
+ ).toBeNull();
184
+ expect(screen.getByText("Research")).toBeTruthy();
185
+ });
137
186
  });
@@ -1,17 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import type { ObservedRequest, ObservedWorkItem, ObservedWorkflow } from "@nextclaw/client-sdk";
3
- import {
4
- canReplyToProjectRequest,
5
- createProjectBoardColumns,
6
- getScheduledWorkItems,
7
- isProjectHomeTab,
8
- } from "./project-home.presenter";
9
-
10
- const reference = {
11
- kind: "ai-report" as const,
12
- label: "AI report",
13
- observedAt: "2026-08-30T00:00:00.000Z",
14
- };
2
+ import { isProjectHomeTab } from "./project-home.presenter";
15
3
 
16
4
  describe("project home presenter", () => {
17
5
  it("accepts only the project home tabs represented in the route", () => {
@@ -20,55 +8,4 @@ describe("project home presenter", () => {
20
8
  expect(isProjectHomeTab("missing")).toBe(false);
21
9
  expect(isProjectHomeTab(undefined)).toBe(false);
22
10
  });
23
-
24
- it("projects the same work items into board and scheduled views without inventing facts", () => {
25
- const workflows: ObservedWorkflow[] = [{
26
- id: "research",
27
- label: "Research",
28
- stages: [{ id: "draft", label: "Draft" }],
29
- reference,
30
- }];
31
- const workItems: ObservedWorkItem[] = [
32
- {
33
- id: "with-schedule",
34
- name: "Scheduled",
35
- status: "active",
36
- workflowId: "research",
37
- stageId: "draft",
38
- schedule: { start: "2026-08-30", end: "2026-09-02", milestone: false, dependsOn: [] },
39
- updatedAt: reference.observedAt,
40
- reference,
41
- },
42
- {
43
- id: "without-schedule",
44
- name: "Unscheduled",
45
- status: "blocked",
46
- updatedAt: reference.observedAt,
47
- reference,
48
- },
49
- ];
50
-
51
- expect(createProjectBoardColumns(workflows, workItems)[0]?.items.map((item) => item.id))
52
- .toEqual(["with-schedule"]);
53
- expect(getScheduledWorkItems(workItems).map((item) => item.id))
54
- .toEqual(["with-schedule"]);
55
- });
56
-
57
- it("offers direct replies only for open confirm-reject requests with a source session", () => {
58
- const request: ObservedRequest = {
59
- id: "approval",
60
- status: "open",
61
- response: "confirm-reject",
62
- prompt: "Ship?",
63
- updatedAt: reference.observedAt,
64
- reference: { ...reference, sessionId: "session-1" },
65
- };
66
- expect(canReplyToProjectRequest(request)).toBe(true);
67
- expect(canReplyToProjectRequest({ ...request, reply: {
68
- decision: "confirmed",
69
- sentAt: reference.observedAt,
70
- messageId: "response-1",
71
- } })).toBe(false);
72
- expect(canReplyToProjectRequest({ ...request, reference })).toBe(false);
73
- });
74
11
  });
@@ -1,55 +1,18 @@
1
- import type {
2
- ObservedRequest,
3
- ObservedWorkItem,
4
- ObservedWorkflow,
5
- ProjectObservationSnapshot,
6
- } from "@nextclaw/client-sdk";
7
-
8
- export type ProjectHomeTab = "overview" | "work" | "artifacts" | "skills" | "agreement";
9
- export type ProjectWorkView = "list" | "board" | "gantt";
10
-
11
- export type ProjectBoardColumn = {
12
- id: string;
13
- label: string;
14
- items: ObservedWorkItem[];
15
- };
16
-
17
- export function isProjectHomeTab(value: string | undefined): value is ProjectHomeTab {
18
- return value === "overview" || value === "work" || value === "artifacts" || value === "skills" || value === "agreement";
19
- }
20
-
21
- export function createProjectBoardColumns(
22
- workflows: readonly ObservedWorkflow[],
23
- workItems: readonly ObservedWorkItem[],
24
- ): ProjectBoardColumn[] {
25
- return workflows.flatMap((workflow) => workflow.stages.map((stage) => ({
26
- id: `${workflow.id}:${stage.id}`,
27
- label: stage.label,
28
- items: workItems.filter((item) => (
29
- item.workflowId === workflow.id && item.stageId === stage.id
30
- )),
31
- })));
32
- }
33
-
34
- export function getUnstagedWorkItems(
35
- workItems: readonly ObservedWorkItem[],
36
- ): ObservedWorkItem[] {
37
- return workItems.filter((item) => !item.workflowId || !item.stageId);
38
- }
39
-
40
- export function getScheduledWorkItems(
41
- workItems: readonly ObservedWorkItem[],
42
- ): ObservedWorkItem[] {
43
- return workItems.filter((item) => item.schedule?.start || item.schedule?.end);
44
- }
45
-
46
- export function canReplyToProjectRequest(request: ObservedRequest): boolean {
47
- return request.status === "open"
48
- && request.response === "confirm-reject"
49
- && Boolean(request.reference.sessionId)
50
- && !request.reply;
51
- }
52
-
53
- export function getOpenProjectRequests(snapshot: ProjectObservationSnapshot): ObservedRequest[] {
54
- return snapshot.requests.filter((request) => request.status === "open");
1
+ export type ProjectHomeTab =
2
+ | "overview"
3
+ | "work"
4
+ | "artifacts"
5
+ | "skills"
6
+ | "agreement";
7
+
8
+ export function isProjectHomeTab(
9
+ value: string | undefined,
10
+ ): value is ProjectHomeTab {
11
+ return (
12
+ value === "overview" ||
13
+ value === "work" ||
14
+ value === "artifacts" ||
15
+ value === "skills" ||
16
+ value === "agreement"
17
+ );
55
18
  }
@@ -1,63 +1,29 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import {
3
3
  formatProjectRelativeTime,
4
- sortProjectArtifacts,
4
+ joinProjectPath,
5
5
  } from "./project-artifact-view.utils";
6
6
 
7
- const artifacts = [
8
- {
9
- id: "older-update",
10
- path: "docs/designs/older.md",
11
- categoryId: "designs",
12
- categoryLabel: "Designs",
13
- exists: true,
14
- fileCreatedAt: "2026-08-01T00:00:00.000Z",
15
- fileUpdatedAt: "2026-08-28T00:00:00.000Z",
16
- references: [],
17
- },
18
- {
19
- id: "newer-update",
20
- path: "docs/designs/newer.md",
21
- categoryId: "designs",
22
- categoryLabel: "Designs",
23
- exists: true,
24
- fileCreatedAt: "2026-08-29T00:00:00.000Z",
25
- fileUpdatedAt: "2026-08-30T00:00:00.000Z",
26
- references: [],
27
- },
28
- {
29
- id: "untimed",
30
- path: "docs/designs/alpha.md",
31
- categoryId: "designs",
32
- categoryLabel: "Designs",
33
- exists: false,
34
- references: [],
35
- },
36
- ];
37
-
38
7
  describe("project artifact view", () => {
39
- it("prioritizes recent updates by default and supports alternate sort orders", () => {
40
- expect(sortProjectArtifacts(artifacts).map((artifact) => artifact.id)).toEqual([
41
- "newer-update",
42
- "older-update",
43
- "untimed",
44
- ]);
45
- expect(sortProjectArtifacts(artifacts, "created-desc").map((artifact) => artifact.id)).toEqual([
46
- "newer-update",
47
- "older-update",
48
- "untimed",
49
- ]);
50
- expect(sortProjectArtifacts(artifacts, "name").map((artifact) => artifact.id)).toEqual([
51
- "untimed",
52
- "newer-update",
53
- "older-update",
54
- ]);
55
- });
56
-
57
8
  it("renders recent timestamps in people-friendly language", () => {
58
9
  const now = new Date("2026-08-30T12:00:00.000Z");
59
- expect(formatProjectRelativeTime("2026-08-30T11:57:00.000Z", now)).toBe("3 minutes ago");
60
- expect(formatProjectRelativeTime("2026-08-30T09:00:00.000Z", now)).toBe("3 hours ago");
61
- expect(formatProjectRelativeTime("2026-08-29T12:00:00.000Z", now)).toBe("Yesterday");
10
+ expect(formatProjectRelativeTime("2026-08-30T11:57:00.000Z", now)).toBe(
11
+ "3 minutes ago",
12
+ );
13
+ expect(formatProjectRelativeTime("2026-08-30T09:00:00.000Z", now)).toBe(
14
+ "3 hours ago",
15
+ );
16
+ expect(formatProjectRelativeTime("2026-08-29T12:00:00.000Z", now)).toBe(
17
+ "Yesterday",
18
+ );
19
+ });
20
+
21
+ it("joins project-relative artifact paths across host path styles", () => {
22
+ expect(joinProjectPath("/tmp/project", "docs/design.md")).toBe(
23
+ "/tmp/project/docs/design.md",
24
+ );
25
+ expect(joinProjectPath("C:\\project\\", "docs/design.md")).toBe(
26
+ "C:\\project\\docs/design.md",
27
+ );
62
28
  });
63
29
  });
@@ -1,62 +1,32 @@
1
- import type { ProjectObservationSnapshot } from "@nextclaw/client-sdk";
2
1
  import { formatDateShort, t } from "@/shared/lib/i18n";
3
2
 
4
- export type ProjectArtifactSort =
5
- | "updated-desc"
6
- | "updated-asc"
7
- | "created-desc"
8
- | "name";
9
-
10
- export const DEFAULT_PROJECT_ARTIFACT_SORT: ProjectArtifactSort = "updated-desc";
11
-
12
- function timestamp(value?: string): number {
13
- if (!value) return Number.NEGATIVE_INFINITY;
14
- const parsed = new Date(value).getTime();
15
- return Number.isNaN(parsed) ? Number.NEGATIVE_INFINITY : parsed;
16
- }
17
-
18
- function byName(
19
- left: ProjectObservationSnapshot["artifacts"][number],
20
- right: ProjectObservationSnapshot["artifacts"][number],
21
- ): number {
22
- return left.path.localeCompare(right.path);
23
- }
24
-
25
- export function sortProjectArtifacts(
26
- artifacts: ProjectObservationSnapshot["artifacts"],
27
- sort: ProjectArtifactSort = DEFAULT_PROJECT_ARTIFACT_SORT,
28
- ): ProjectObservationSnapshot["artifacts"] {
29
- return [...artifacts].sort((left, right) => {
30
- if (sort === "name") return byName(left, right);
31
- const leftTimestamp = timestamp(
32
- sort === "created-desc"
33
- ? left.fileCreatedAt ?? left.fileUpdatedAt
34
- : left.fileUpdatedAt ?? left.fileCreatedAt,
35
- );
36
- const rightTimestamp = timestamp(
37
- sort === "created-desc"
38
- ? right.fileCreatedAt ?? right.fileUpdatedAt
39
- : right.fileUpdatedAt ?? right.fileCreatedAt,
40
- );
41
- const order = sort === "updated-asc"
42
- ? leftTimestamp - rightTimestamp
43
- : rightTimestamp - leftTimestamp;
44
- return order || byName(left, right);
45
- });
3
+ export function joinProjectPath(
4
+ rootPath: string,
5
+ relativePath: string,
6
+ ): string {
7
+ const separator =
8
+ rootPath.endsWith("/") || rootPath.endsWith("\\") ? "" : "/";
9
+ return `${rootPath}${separator}${relativePath}`;
46
10
  }
47
11
 
48
- export function formatProjectRelativeTime(value?: string, now: Date = new Date()): string {
12
+ export function formatProjectRelativeTime(
13
+ value?: string,
14
+ now: Date = new Date(),
15
+ ): string {
49
16
  if (!value) return "-";
50
17
  const date = new Date(value);
51
18
  const differenceMs = now.getTime() - date.getTime();
52
19
  if (Number.isNaN(date.getTime())) return value;
53
20
  if (differenceMs < 60_000) return t("projectsTimeJustNow");
54
21
  const minutes = Math.floor(differenceMs / 60_000);
55
- if (minutes < 60) return t("projectsTimeMinutesAgo").replace("{count}", String(minutes));
22
+ if (minutes < 60)
23
+ return t("projectsTimeMinutesAgo").replace("{count}", String(minutes));
56
24
  const hours = Math.floor(minutes / 60);
57
- if (hours < 24) return t("projectsTimeHoursAgo").replace("{count}", String(hours));
25
+ if (hours < 24)
26
+ return t("projectsTimeHoursAgo").replace("{count}", String(hours));
58
27
  const days = Math.floor(hours / 24);
59
28
  if (days === 1) return t("projectsTimeYesterday");
60
- if (days < 7) return t("projectsTimeDaysAgo").replace("{count}", String(days));
29
+ if (days < 7)
30
+ return t("projectsTimeDaysAgo").replace("{count}", String(days));
61
31
  return formatDateShort(value);
62
32
  }
@@ -0,0 +1,28 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { getProjectWorkStateLabel } from "./project-work-state-label.utils";
3
+
4
+ describe("getProjectWorkStateLabel", () => {
5
+ it.each([
6
+ ["Backlog", "待整理"],
7
+ ["Planned", "已计划"],
8
+ ["In Progress", "进行中"],
9
+ ["In Review", "评审中"],
10
+ ["Awaiting Acceptance", "等待验收"],
11
+ ["Completed", "已完成"],
12
+ ["Canceled", "已取消"],
13
+ ])("localizes the built-in %s state", (name, expected) => {
14
+ expect(getProjectWorkStateLabel(name, "zh")).toBe(expected);
15
+ });
16
+
17
+ it("keeps custom state names unchanged", () => {
18
+ expect(getProjectWorkStateLabel("Ready to publish", "zh")).toBe(
19
+ "Ready to publish",
20
+ );
21
+ });
22
+
23
+ it("keeps the built-in English labels in English", () => {
24
+ expect(getProjectWorkStateLabel("Awaiting Acceptance", "en")).toBe(
25
+ "Awaiting Acceptance",
26
+ );
27
+ });
28
+ });
@@ -0,0 +1,20 @@
1
+ import { t, type I18nLanguage } from "@/shared/lib/i18n";
2
+
3
+ const DEFAULT_STATE_MESSAGE_KEYS: Readonly<Record<string, string>> = {
4
+ Backlog: "projectsWorkState_backlog",
5
+ Planned: "projectsWorkState_planned",
6
+ "In Progress": "projectsWorkState_inProgress",
7
+ "In Review": "projectsWorkState_inReview",
8
+ "Awaiting Acceptance": "projectsWorkState_awaitingAcceptance",
9
+ Completed: "projectsWorkState_completed",
10
+ Canceled: "projectsWorkState_canceled",
11
+ };
12
+
13
+ export function getProjectWorkStateLabel(
14
+ name: string,
15
+ language?: I18nLanguage,
16
+ ): string {
17
+ const messageKey = DEFAULT_STATE_MESSAGE_KEYS[name];
18
+ if (!messageKey) return name;
19
+ return language ? t(messageKey, language) : t(messageKey);
20
+ }
@@ -1,3 +1,3 @@
1
- export { ServiceActionAuthorizationDialog } from '@/features/service-apps/components/service-action-authorization-dialog';
2
- export { ServiceActionAuthorizationManager } from '@/features/service-apps/managers/service-action-authorization.manager';
3
- export { ServiceAppsPanel } from '@/features/service-apps/components/service-apps-panel';
1
+ export async function loadServiceAppsPanel() {
2
+ return await import('@/features/service-apps/components/service-apps-panel');
3
+ }
package/src/main.tsx CHANGED
@@ -4,8 +4,11 @@ import { BrowserRouter, MemoryRouter } from 'react-router-dom';
4
4
  import App from './app';
5
5
  import { I18nProvider } from '@/components/providers/I18nProvider';
6
6
  import { ThemeProvider } from '@/components/providers/ThemeProvider';
7
+ import { installMainI18nCatalog } from '@/shared/lib/i18n';
7
8
  import './index.css';
8
9
 
10
+ await installMainI18nCatalog();
11
+
9
12
  const AppRouter = window.nextclawDesktop?.platform === 'win32' ? MemoryRouter : BrowserRouter;
10
13
  const root = createRoot(document.getElementById('root')!);
11
14
 
@@ -0,0 +1,49 @@
1
+ import { useRef } from 'react';
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import { fetchAuthStatus, type AuthStatusView } from "@/shared/lib/api";
4
+ import { isTransientRuntimeConnectionErrorMessage } from "@/shared/lib/transport";
5
+
6
+ const AUTH_STATUS_BOOTSTRAP_PROBE_POLICY = {
7
+ maxRetries: 8,
8
+ startupTimeoutMs: 2_000,
9
+ settledTimeoutMs: 5_000,
10
+ retryBaseDelayMs: 500,
11
+ retryMaxDelayMs: 3_000,
12
+ } as const;
13
+
14
+ export function isTransientAuthStatusBootstrapError(error: unknown): boolean {
15
+ return error instanceof Error && isTransientRuntimeConnectionErrorMessage(error.message);
16
+ }
17
+
18
+ export function shouldRetryAuthStatusBootstrap(failureCount: number, error: unknown): boolean {
19
+ return failureCount < AUTH_STATUS_BOOTSTRAP_PROBE_POLICY.maxRetries &&
20
+ isTransientAuthStatusBootstrapError(error);
21
+ }
22
+
23
+ export function resolveAuthStatusBootstrapRetryDelay(failureCount: number): number {
24
+ return Math.min(
25
+ AUTH_STATUS_BOOTSTRAP_PROBE_POLICY.retryMaxDelayMs,
26
+ AUTH_STATUS_BOOTSTRAP_PROBE_POLICY.retryBaseDelayMs * 2 ** Math.max(0, failureCount - 1),
27
+ );
28
+ }
29
+
30
+ export function useAuthStatus() {
31
+ const bootstrapSettled = useRef(false);
32
+ const query = useQuery<AuthStatusView>({
33
+ queryKey: ["auth-status"],
34
+ queryFn: async () => {
35
+ const status = await fetchAuthStatus({
36
+ timeoutMs: bootstrapSettled.current
37
+ ? AUTH_STATUS_BOOTSTRAP_PROBE_POLICY.settledTimeoutMs
38
+ : AUTH_STATUS_BOOTSTRAP_PROBE_POLICY.startupTimeoutMs,
39
+ });
40
+ bootstrapSettled.current = true;
41
+ return status;
42
+ },
43
+ staleTime: 5_000,
44
+ retry: shouldRetryAuthStatusBootstrap,
45
+ retryDelay: resolveAuthStatusBootstrapRetryDelay,
46
+ });
47
+
48
+ return query;
49
+ }
@@ -1,6 +1,6 @@
1
1
  import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
2
2
  import { toast } from "sonner";
3
- import { addExistingProject, createProject, fetchProjects } from "@/shared/lib/api";
3
+ import { addExistingProject, createProject, fetchProjects, removeProject } from "@/shared/lib/api";
4
4
  import { t } from "@/shared/lib/i18n";
5
5
 
6
6
  const PROJECTS_QUERY_KEY = ["projects"] as const;
@@ -41,3 +41,17 @@ export function useAddExistingProject() {
41
41
  },
42
42
  });
43
43
  }
44
+
45
+ export function useRemoveProject() {
46
+ const queryClient = useQueryClient();
47
+ return useMutation({
48
+ mutationFn: removeProject,
49
+ onSuccess: async () => {
50
+ await queryClient.invalidateQueries({ queryKey: PROJECTS_QUERY_KEY });
51
+ toast.success(t("projectsRemoveSuccess"));
52
+ },
53
+ onError: (error: Error) => {
54
+ toast.error(`${t("projectsRemoveFailed")}: ${error.message}`);
55
+ },
56
+ });
57
+ }
@@ -19,3 +19,7 @@ export async function addExistingProject(
19
19
  ): Promise<ProjectView> {
20
20
  return await nextclawClient.projects.addExisting(input);
21
21
  }
22
+
23
+ export async function removeProject(projectId: string): Promise<ProjectView> {
24
+ return await nextclawClient.projects.remove(projectId, projectId);
25
+ }