@nextclaw/ui 0.24.0 → 0.24.2

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 (333) hide show
  1. package/CHANGELOG.md +18 -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-BxMlLXYH.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-Utt-xzrT.js +13 -0
  7. package/dist/assets/app-data-DYXDL6X2.js +1 -0
  8. package/dist/assets/app-presenter-provider-CLsFiXvV.js +109 -0
  9. package/dist/assets/app-presenter-provider-D3BuuOyZ.css +1 -0
  10. package/dist/assets/appearance-settings-page-BfYznAK5.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-DDW_3XpM.js} +1 -1
  16. package/dist/assets/boxes-DwJeuK_h.js +1 -0
  17. package/dist/assets/{c4Diagram-LMCZKHZV-D9hFNAGv.js → c4Diagram-LMCZKHZV-CpapRftp.js} +1 -1
  18. package/dist/assets/card-IevY2nm-.js +1 -0
  19. package/dist/assets/channel-CBrWRr4N.js +1 -0
  20. package/dist/assets/channels-list-page-DitnqbMR.js +8 -0
  21. package/dist/assets/chevron-down-An7Km-t4.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-CDXqELuo.js +1 -0
  61. package/dist/assets/circle-dashed-CapXEpiV.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-B0krol7A.js +1 -0
  65. package/dist/assets/config-split-page-BtnkqWVp.js +1 -0
  66. package/dist/assets/confirm-dialog-DFt4jpN7.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-BTHK0Ot9.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-CCf14WId.js +1 -0
  74. package/dist/assets/desktop-update-config-DVoVgfFi.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-BFN_1DBH.js +5 -0
  81. package/dist/assets/dist-Bc9hOVNN.js +1 -0
  82. package/dist/assets/dist-CEhIDAnr.js +1 -0
  83. package/dist/assets/{dist--ta5rX12.js → dist-Cnhwure9.js} +1 -1
  84. package/dist/assets/{dist-aNN3iQxV.js → dist-hkVPP1th.js} +1 -1
  85. package/dist/assets/doc-browser-BNUxmwD6.js +1 -0
  86. package/dist/assets/doc-browser-context-C4yQrKrH.js +1 -0
  87. package/dist/assets/doc-browser-w4eGZXLu.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-BRI6ROeu.js +1 -0
  91. package/dist/assets/{erDiagram-Q63AITRT-ZLlx8xfs.js → erDiagram-Q63AITRT-DR7vWYHM.js} +1 -1
  92. package/dist/assets/es2015-MOCbM0Eu.js +41 -0
  93. package/dist/assets/eventmodeling-45OFAUF4-CXZNG56U.js +1 -0
  94. package/dist/assets/extensions-DxUBMtHW.js +1 -0
  95. package/dist/assets/eye-cnynUDGt.js +1 -0
  96. package/dist/assets/flowDiagram-23GEKE2U-2065oyKr.js +1 -0
  97. package/dist/assets/form-actions-gQ0JEUwB.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-B9yXA8KO.js +2 -0
  102. package/dist/assets/i18n-provider-BYBJua91.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-rWr5Yo0E.js +1 -0
  112. package/dist/assets/login-page-CfMSkOsg.js +1 -0
  113. package/dist/assets/login-page-CqrHhzaN.js +1 -0
  114. package/dist/assets/logo-badge-Cr03YceJ.js +1 -0
  115. package/dist/assets/main-8cVkMfgE.css +1 -0
  116. package/dist/assets/main-Bys58GxY.js +2 -0
  117. package/dist/assets/main-i18n-catalog.config-BSq9yiUQ.js +1 -0
  118. package/dist/assets/{map-BKnQyvd0.js → map-WMnNq9UV.js} +1 -1
  119. package/dist/assets/mcp-marketplace-page-CifiVgFD.js +10 -0
  120. package/dist/assets/mcp-marketplace-page-DX5VE3mU.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-C6jVNbSj.js +1 -0
  125. package/dist/assets/{navigation-link-C_6oj3zz.js → navigation-link-kbCLRSr_.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-C2St67SP.js +1 -0
  130. package/dist/assets/panelStandalone-DMBnYyTw.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-BHnKwuPq.js +1 -0
  136. package/dist/assets/popover-XVDgjxcl.js +1 -0
  137. package/dist/assets/privacy-settings-page-BN27MBVA.js +1 -0
  138. package/dist/assets/projects-DV3UuJMS.js +1 -0
  139. package/dist/assets/provider-models-5PGHb6mP.js +1 -0
  140. package/dist/assets/provider-scoped-model-input-BGZMCThn.js +1 -0
  141. package/dist/assets/providers-config-page-D5aBwbOD.js +1 -0
  142. package/dist/assets/puzzle-D5Dhacmb.js +1 -0
  143. package/dist/assets/pwa-ClQK56Qe.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-Bw5BY7vp.js} +1 -1
  152. package/dist/assets/remote-Bl005fzu.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-BksCLAeE.js} +1 -1
  155. package/dist/assets/runtime-config-page-CmktQcMW.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-CVi8VWzb.js} +1 -1
  158. package/dist/assets/{search-B6tB4fzB.js → search-DN-f7IIC.js} +1 -1
  159. package/dist/assets/search-config-page-BmuZTVxs.js +1 -0
  160. package/dist/assets/secrets-config-page-NPHpg9sb.js +3 -0
  161. package/dist/assets/security-config-Djptuyf2.js +1 -0
  162. package/dist/assets/select-CmDTqk2C.js +1 -0
  163. package/dist/assets/{sequenceDiagram-DBY2YBRQ-BtRbPQtL.js → sequenceDiagram-DBY2YBRQ-DwHC4mbX.js} +1 -1
  164. package/dist/assets/service-apps-panel-BYGJ9_pO.js +1 -0
  165. package/dist/assets/settings-2-B62YtZon.js +1 -0
  166. package/dist/assets/{sizeCapture-X5ZJPWSS-CMYvM3SL.js → sizeCapture-X5ZJPWSS-oOMY0Fag.js} +1 -1
  167. package/dist/assets/skeleton-Eh64l4T2.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-Bk_mG7ql.js +1 -0
  174. package/dist/assets/{tag-chip-BZKk0UkK.js → tag-chip-DgqKlI5D.js} +1 -1
  175. package/dist/assets/theme-provider-CeBY2pyu.js +1 -0
  176. package/dist/assets/{timeline-definition-FHXFAJF6-Bicewlzo.js → timeline-definition-FHXFAJF6-BEonB5Np.js} +1 -1
  177. package/dist/assets/tooltip-CgGbBdYf.js +1 -0
  178. package/dist/assets/trash-2-CVOev8yc.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-b2DN67gs.js +1 -0
  182. package/dist/assets/use-desktop-capabilities-B3tLU1yl.js +1 -0
  183. package/dist/assets/use-panel-app-scroll-restoration-BekzoX6z.js +1 -0
  184. package/dist/assets/use-viewport-layout-CUA3jQsA.js +1 -0
  185. package/dist/assets/utils-UBHTdG5Q.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-C0iaOsRW.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 +3 -3
  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/session/utils/__tests__/chat-sidebar-session-groups.utils.test.ts +27 -2
  207. package/src/features/chat/features/session/utils/chat-sidebar-session-groups.utils.ts +0 -11
  208. package/src/features/panel-apps/components/__tests__/panel-app-list-item.test.tsx +18 -0
  209. package/src/features/panel-apps/components/__tests__/panel-app-open-standalone-menu-item.test.tsx +56 -0
  210. package/src/features/panel-apps/components/__tests__/panel-app-toolbar.test.tsx +15 -0
  211. package/src/features/panel-apps/components/panel-app-list-item.tsx +5 -0
  212. package/src/features/panel-apps/components/panel-app-open-standalone-menu-item.tsx +29 -0
  213. package/src/features/panel-apps/components/panel-app-runtime-surface.tsx +141 -0
  214. package/src/features/{service-apps/components/service-action-authorization-dialog.tsx → panel-apps/components/panel-app-service-action-authorization-dialog.tsx} +4 -4
  215. package/src/features/panel-apps/components/panel-app-toolbar.tsx +5 -0
  216. package/src/features/panel-apps/hooks/use-panel-app-client-grant.ts +2 -2
  217. package/src/features/panel-apps/hooks/{use-panel-app-main-runtime.ts → use-panel-app-runtime.ts} +7 -5
  218. package/src/features/panel-apps/hooks/use-panel-apps.ts +14 -0
  219. package/src/features/panel-apps/index.ts +5 -0
  220. package/src/features/panel-apps/managers/__tests__/panel-app-bridge.manager.test.ts +2 -2
  221. package/src/features/panel-apps/managers/panel-app-bridge.manager.ts +2 -2
  222. package/src/features/panel-apps/managers/panel-app-service-action-authorization.manager.ts +10 -0
  223. package/src/features/panel-apps/pages/__tests__/panel-app-main-page.test.tsx +12 -3
  224. package/src/features/panel-apps/pages/__tests__/panel-app-standalone-page.test.tsx +63 -0
  225. package/src/features/panel-apps/pages/panel-app-main-page.tsx +9 -121
  226. package/src/features/panel-apps/pages/panel-app-standalone-page.tsx +29 -0
  227. package/src/features/panel-apps/presenters/panel-app-host.presenter.ts +9 -0
  228. package/src/features/panel-apps/providers/panel-app-host.provider.tsx +45 -0
  229. package/src/features/panel-apps/routes/__tests__/panel-app-standalone.route.test.tsx +50 -0
  230. package/src/features/panel-apps/routes/panel-app-standalone.route.tsx +94 -0
  231. package/src/features/{service-apps/stores/service-action-authorization.store.ts → panel-apps/stores/panel-app-service-action-authorization.store.ts} +6 -6
  232. package/src/features/projects/components/project-overview.test.tsx +70 -0
  233. package/src/features/projects/components/project-overview.tsx +114 -56
  234. package/src/features/projects/components/work/project-work-item-drawer.tsx +8 -10
  235. package/src/features/projects/components/work/project-work-items.test.tsx +168 -4
  236. package/src/features/projects/components/work/project-work-items.tsx +277 -49
  237. package/src/features/projects/components/work/project-work-state-settings.tsx +7 -3
  238. package/src/features/projects/hooks/use-project-work.test.tsx +108 -6
  239. package/src/features/projects/hooks/use-project-work.ts +82 -9
  240. package/src/features/projects/pages/project-home-page.tsx +45 -6
  241. package/src/features/projects/pages/projects-page.test.tsx +56 -0
  242. package/src/features/projects/utils/project-artifact-view.utils.test.ts +30 -18
  243. package/src/features/projects/utils/project-artifact-view.utils.ts +29 -12
  244. package/src/features/projects/utils/project-work-state-label.utils.test.ts +28 -0
  245. package/src/features/projects/utils/project-work-state-label.utils.ts +20 -0
  246. package/src/features/service-apps/index.ts +3 -3
  247. package/src/main.tsx +3 -0
  248. package/src/shared/hooks/use-auth-status.ts +49 -0
  249. package/src/shared/hooks/use-projects.ts +15 -1
  250. package/src/shared/lib/api/projects/project.utils.ts +4 -0
  251. package/src/shared/lib/i18n/configs/main-i18n-catalog.config.ts +78 -0
  252. package/src/shared/lib/i18n/configs/panel-app-i18n-catalog.config.ts +12 -0
  253. package/src/shared/lib/i18n/index.ts +30 -82
  254. package/src/shared/lib/i18n/locales/en-US/doc-browser.json +0 -55
  255. package/src/shared/lib/i18n/locales/en-US/panel-app.json +59 -0
  256. package/src/shared/lib/i18n/locales/en-US/projects.json +16 -0
  257. package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +0 -55
  258. package/src/shared/lib/i18n/locales/zh-CN/panel-app.json +59 -0
  259. package/src/shared/lib/i18n/locales/zh-CN/projects.json +16 -0
  260. package/vite.config.ts +36 -1
  261. package/dist/assets/api-BqVIq0lF.js +0 -13
  262. package/dist/assets/appearance-settings-page-CTWn1eAT.js +0 -1
  263. package/dist/assets/architecture-TIHT7OUA-DO2x53FK.js +0 -1
  264. package/dist/assets/channel-nBvMaVyP.js +0 -1
  265. package/dist/assets/channels-list-page-Bzn-pzyJ.js +0 -8
  266. package/dist/assets/chunk-2Q5K7J3B-CJgqFDS4.js +0 -1
  267. package/dist/assets/chunk-VAUOI2AC-BGvh3yIx.js +0 -1
  268. package/dist/assets/chunk-XXDRQBXY-DaBxG5gs.js +0 -1
  269. package/dist/assets/classDiagram-OUVF2IWQ-P6N03G2R.js +0 -1
  270. package/dist/assets/classDiagram-v2-EOCWNBFH-B1_uLvMv.js +0 -1
  271. package/dist/assets/config-split-page-CnRbXXlh.js +0 -1
  272. package/dist/assets/confirm-dialog-B_Hbcra2.js +0 -5
  273. package/dist/assets/cynefin-VYW2F7L2-B-H8Qp-n.js +0 -1
  274. package/dist/assets/desktop-capabilities-page-C2ayYQTr.js +0 -1
  275. package/dist/assets/desktop-update-config-C13czpyL.js +0 -1
  276. package/dist/assets/dist-BsF3hfOi.js +0 -1
  277. package/dist/assets/doc-browser-D8dIOo9E.js +0 -1
  278. package/dist/assets/doc-browser-DcuOOtpP.js +0 -1
  279. package/dist/assets/doc-browser-context-Dhsit2Ma.js +0 -1
  280. package/dist/assets/eventmodeling-45OFAUF4-YVtShyFA.js +0 -1
  281. package/dist/assets/extensions-CD6xvKF_.js +0 -1
  282. package/dist/assets/flowDiagram-23GEKE2U-BeKXabVO.js +0 -1
  283. package/dist/assets/form-actions-CC4Wz_lL.js +0 -1
  284. package/dist/assets/gitGraph-TEB2WS4Q-jTSiBj-p.js +0 -1
  285. package/dist/assets/index-BTsbdtv6.js +0 -109
  286. package/dist/assets/index-Bcfy2kTh.css +0 -1
  287. package/dist/assets/info-DKCQHKI2-BIporNWb.js +0 -1
  288. package/dist/assets/loader-circle-B6aFbB-8.js +0 -1
  289. package/dist/assets/mcp-marketplace-page-BtUAypA7.js +0 -1
  290. package/dist/assets/mcp-marketplace-page-r2MmD9xO.js +0 -10
  291. package/dist/assets/model-config-page-DboxoT-I.js +0 -1
  292. package/dist/assets/packet-7NZHBO7P-CuFMADV0.js +0 -1
  293. package/dist/assets/pie-RZYD4A2V-XUeIXhM9.js +0 -1
  294. package/dist/assets/plus-DRsq9Kvs.js +0 -1
  295. package/dist/assets/privacy-settings-page-C2sDBqhb.js +0 -1
  296. package/dist/assets/projects-BcPcx-uD.js +0 -1
  297. package/dist/assets/providers-config-page-CmUFl9RF.js +0 -1
  298. package/dist/assets/radar-I7S5WNFK-D-NNGh1k.js +0 -1
  299. package/dist/assets/railroad-3IZDKUUU-C67_uDaM.js +0 -1
  300. package/dist/assets/railroad-abnf-AHOZXSZD-BZ8Yflnd.js +0 -1
  301. package/dist/assets/railroad-ebnf-EBAXGLYW-B7zO7RoK.js +0 -1
  302. package/dist/assets/railroad-peg-LSFZ7HO6-R63PTgLz.js +0 -1
  303. package/dist/assets/react-BjO9I4WZ.js +0 -8
  304. package/dist/assets/remote-Ci6x91ES.js +0 -1
  305. package/dist/assets/runtime-config-page-cQKNeAjL.js +0 -1
  306. package/dist/assets/search-config-page-C8lOIkxn.js +0 -1
  307. package/dist/assets/secrets-config-page-8clzAag2.js +0 -3
  308. package/dist/assets/security-config-DPbM6IVT.js +0 -1
  309. package/dist/assets/select-CO9S_C2C.js +0 -41
  310. package/dist/assets/skeleton-IHILNhIW.js +0 -1
  311. package/dist/assets/stateDiagram-v2-6OUMAXLB-BE-HqxOK.js +0 -1
  312. package/dist/assets/swimlanesDiagram-G3AALYLV-Dr1H9LJH.js +0 -8
  313. package/dist/assets/treeView-QDETBFTQ-npJ5dbqS.js +0 -1
  314. package/dist/assets/treemap-6X3UGDF4-pYrBx6oa.js +0 -1
  315. package/dist/assets/wardley-OPB4EBWU-CmSRKLR8.js +0 -1
  316. package/dist/assets/x-BuvHIb1d.js +0 -1
  317. package/src/features/service-apps/managers/service-action-authorization.manager.ts +0 -10
  318. /package/dist/assets/{array-BQVzeGRt.js → array-BHDgItFN.js} +0 -0
  319. /package/dist/assets/{chunk-DseTPa7n.js → chunk-DF37yw5_.js} +0 -0
  320. /package/dist/assets/{chunk-KEIR6QF5-f9psyCXK.js → chunk-KEIR6QF5-DstBw0Hk.js} +0 -0
  321. /package/dist/assets/{chunk-Y2CYZVJY-D1mAU_Po.js → chunk-Y2CYZVJY-CA3ymQuH.js} +0 -0
  322. /package/dist/assets/{config-hints-nV5HPOvq.js → config-hints-CBPHrfYk.js} +0 -0
  323. /package/dist/assets/{cytoscape.esm-0uDtdD0l.js → cytoscape.esm-C7xr90o_.js} +0 -0
  324. /package/dist/assets/{defaultLocale-DSWXGgt0.js → defaultLocale-BG1oDVag.js} +0 -0
  325. /package/dist/assets/{graphlib-CQ6QV4yP.js → graphlib-CNMGfuTb.js} +0 -0
  326. /package/dist/assets/{host-capabilities-Tk038i04.js → host-capabilities-B107nwS3.js} +0 -0
  327. /package/dist/assets/{init-Y6h9jGtZ.js → init-wQIZuRSH.js} +0 -0
  328. /package/dist/assets/{katex-ARhY9PS1.js → katex-J8JuvgNl.js} +0 -0
  329. /package/dist/assets/{middleware-DXsbf9xI.js → middleware-0o3JF3tS.js} +0 -0
  330. /package/dist/assets/{path-10BjdyLh.js → path-N-C4MRP0.js} +0 -0
  331. /package/dist/assets/{preload-helper-D4M6sveU.js → preload-helper-ca-nBW7U.js} +0 -0
  332. /package/dist/assets/{rough.esm-DxgC_14r.js → rough.esm-BeWA068d.js} +0 -0
  333. /package/dist/assets/{xlsx-DrDuDNAa.js → xlsx-CwUXNtD3.js} +0 -0
@@ -2,7 +2,7 @@ import { NextClawClientError } from '@nextclaw/client-sdk';
2
2
  import { waitFor } from '@testing-library/react';
3
3
  import { afterEach, describe, expect, it, vi } from 'vitest';
4
4
  import { PanelAppBridgeManager } from '@/features/panel-apps/managers/panel-app-bridge.manager';
5
- import type { ServiceActionAuthorizationManager } from '@/features/service-apps';
5
+ import type { PanelAppServiceActionAuthorizationManager } from '@/features/panel-apps/managers/panel-app-service-action-authorization.manager';
6
6
 
7
7
  const mocks = vi.hoisted(() => ({
8
8
  generateAgentObject: vi.fn(),
@@ -45,7 +45,7 @@ afterEach(() => {
45
45
  function createManager(): PanelAppBridgeManager {
46
46
  return new PanelAppBridgeManager({
47
47
  requestAuthorization: mocks.requestAuthorization,
48
- } as unknown as ServiceActionAuthorizationManager);
48
+ } as unknown as PanelAppServiceActionAuthorizationManager);
49
49
  }
50
50
 
51
51
  function createIframeHarness(manager: PanelAppBridgeManager) {
@@ -13,7 +13,7 @@ import type {
13
13
  PortableRuntimeAcceptanceStatusApiView,
14
14
  RuntimeVerificationRecordListView,
15
15
  } from '@nextclaw/client-sdk';
16
- import type { ServiceActionAuthorizationManager } from '@/features/service-apps';
16
+ import type { PanelAppServiceActionAuthorizationManager } from '@/features/panel-apps/managers/panel-app-service-action-authorization.manager';
17
17
  import { nextclawClient } from '@/shared/lib/api';
18
18
 
19
19
  export type PanelAppIframeMessageParams = {
@@ -71,7 +71,7 @@ type PanelAppBridgeResponse =
71
71
  };
72
72
 
73
73
  export class PanelAppBridgeManager {
74
- constructor(private readonly authorizationManager: ServiceActionAuthorizationManager) {}
74
+ constructor(private readonly authorizationManager: PanelAppServiceActionAuthorizationManager) {}
75
75
 
76
76
  handleIframeMessage = ({ event, iframe }: PanelAppIframeMessageParams): void => {
77
77
  if (!this.isBridgeRequest(event.data)) {
@@ -0,0 +1,10 @@
1
+ import { usePanelAppServiceActionAuthorizationStore } from '@/features/panel-apps/stores/panel-app-service-action-authorization.store';
2
+ import type { PanelAppServiceActionAuthorizationRequest } from '@/features/panel-apps/stores/panel-app-service-action-authorization.store';
3
+
4
+ export class PanelAppServiceActionAuthorizationManager {
5
+ requestAuthorization = async (
6
+ request: Omit<PanelAppServiceActionAuthorizationRequest, 'id'>,
7
+ ): Promise<boolean> => {
8
+ return await usePanelAppServiceActionAuthorizationStore.getState().requestAuthorization(request);
9
+ };
10
+ }
@@ -19,8 +19,8 @@ const mocks = vi.hoisted(() => ({
19
19
  updatePreferences: vi.fn(),
20
20
  }));
21
21
 
22
- vi.mock("@/app/components/app-presenter-provider", () => ({
23
- useAppPresenter: () => ({
22
+ vi.mock("@/features/panel-apps/providers/panel-app-host.provider", () => ({
23
+ usePanelAppHostPresenter: () => ({
24
24
  panelAppBridgeManager: { handleIframeMessage: mocks.bridgeMessage },
25
25
  }),
26
26
  }));
@@ -33,6 +33,15 @@ vi.mock("@/features/panel-apps/hooks/use-panel-app-client-grant", () => ({
33
33
  }));
34
34
 
35
35
  vi.mock("@/features/panel-apps/hooks/use-panel-apps", () => ({
36
+ PANEL_APP_QUERY_KEY: ["panel-app"],
37
+ PANEL_APPS_QUERY_KEY: ["panel-apps"],
38
+ usePanelApp: (appId: string) => ({
39
+ data: mocks.entries.find((entry) => entry.appId === appId),
40
+ error: null,
41
+ isError: false,
42
+ isLoading: false,
43
+ refetch: mocks.refetch,
44
+ }),
36
45
  usePanelApps: () => ({
37
46
  data: { entries: mocks.entries },
38
47
  error: null,
@@ -161,7 +170,7 @@ describe("PanelAppMainPage", () => {
161
170
 
162
171
  first.unmount();
163
172
  await waitFor(() => expect(queryClient.getQueryData([
164
- "panel-app-main-client-grant",
173
+ "panel-app-client-grant",
165
174
  "publisher.todo",
166
175
  false,
167
176
  ])).toBeUndefined());
@@ -0,0 +1,63 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import { afterEach, describe, expect, it, vi } from "vitest";
3
+ import { PanelAppStandalonePage } from "@/features/panel-apps/pages/panel-app-standalone-page";
4
+ import type { PanelAppEntryView } from "@/shared/lib/api";
5
+
6
+ const entry: PanelAppEntryView = {
7
+ appId: "publisher.todo",
8
+ clientDeclared: false,
9
+ clientGranted: false,
10
+ contentPath: "/api/panel-apps/publisher.todo/content",
11
+ createdAt: "2026-09-03T00:00:00.000Z",
12
+ favorite: false,
13
+ fileName: "todo.panel.html",
14
+ id: "todo",
15
+ kind: "single-file",
16
+ mainSidebar: false,
17
+ openCount: 0,
18
+ sizeBytes: 10,
19
+ title: "Rust Todo",
20
+ updatedAt: "2026-09-03T00:00:00.000Z",
21
+ };
22
+
23
+ vi.mock("@/features/panel-apps/hooks/use-panel-apps", () => ({
24
+ usePanelApp: () => ({
25
+ data: entry,
26
+ }),
27
+ }));
28
+
29
+ vi.mock("@/features/panel-apps/components/panel-app-runtime-surface", () => ({
30
+ PanelAppRuntimeSurface: ({
31
+ appId,
32
+ restorationScope,
33
+ }: {
34
+ appId: string;
35
+ restorationScope: string;
36
+ }) => (
37
+ <div
38
+ data-testid="panel-app-runtime-surface"
39
+ data-app-id={appId}
40
+ data-restoration-scope={restorationScope}
41
+ />
42
+ ),
43
+ }));
44
+
45
+ describe("PanelAppStandalonePage", () => {
46
+ const originalTitle = document.title;
47
+
48
+ afterEach(() => {
49
+ document.title = originalTitle;
50
+ });
51
+
52
+ it("renders only the standalone runtime surface and sets the tab title", () => {
53
+ const { container } = render(
54
+ <PanelAppStandalonePage appId="publisher.todo" />,
55
+ );
56
+
57
+ const surface = screen.getByTestId("panel-app-runtime-surface");
58
+ expect(surface.getAttribute("data-app-id")).toBe("publisher.todo");
59
+ expect(surface.getAttribute("data-restoration-scope")).toBe("standalone");
60
+ expect(document.title).toBe("Rust Todo · NextClaw");
61
+ expect(container.querySelector("main")?.children).toHaveLength(1);
62
+ });
63
+ });
@@ -1,133 +1,21 @@
1
- import { useEffect, useMemo, useRef } from "react";
2
- import { Boxes, RotateCcw } from "lucide-react";
3
1
  import { useParams } from "react-router-dom";
4
- import { useAppPresenter } from "@/app/components/app-presenter-provider";
5
- import { usePanelAppMainRuntime } from "@/features/panel-apps/hooks/use-panel-app-main-runtime";
6
- import {
7
- usePanelApps,
8
- } from "@/features/panel-apps/hooks/use-panel-apps";
9
- import {
10
- PANEL_APP_IFRAME_SANDBOX,
11
- focusPanelAppIframe,
12
- } from "@/features/panel-apps/utils/panel-app-iframe.utils";
2
+ import { PanelAppRuntimeSurface } from "@/features/panel-apps/components/panel-app-runtime-surface";
13
3
  import { openApps } from "@/features/panel-apps/utils/panel-app-doc-browser.utils";
14
4
  import { useDocBrowser } from "@/shared/components/doc-browser";
15
- import { usePanelAppScrollRestoration } from "@/shared/hooks/use-panel-app-scroll-restoration";
16
5
  import { t } from "@/shared/lib/i18n";
17
6
 
18
7
  export function PanelAppMainPage() {
19
8
  const { appId = "" } = useParams<{ appId: string }>();
20
- const presenter = useAppPresenter();
21
9
  const docBrowser = useDocBrowser();
22
- const panelApps = usePanelApps();
23
- const iframeRef = useRef<HTMLIFrameElement>(null);
24
- const entry = useMemo(
25
- () => panelApps.data?.entries.find((candidate) => candidate.appId === appId),
26
- [appId, panelApps.data?.entries],
27
- );
28
- const runtime = usePanelAppMainRuntime(entry);
29
- const restoreScroll = usePanelAppScrollRestoration({
30
- currentUrl: entry?.contentPath ?? null,
31
- iframeRef,
32
- isEnabled: Boolean(entry),
33
- restorationKey: entry ? `panel-app:main:${entry.appId}` : null,
34
- });
35
-
36
- useEffect(() => {
37
- const handleMessage = (event: MessageEvent) => {
38
- presenter.panelAppBridgeManager.handleIframeMessage({
39
- event,
40
- iframe: iframeRef.current,
41
- });
42
- };
43
- window.addEventListener("message", handleMessage);
44
- return () => window.removeEventListener("message", handleMessage);
45
- }, [presenter]);
46
-
47
- if (panelApps.isLoading) {
48
- return <PanelAppMainStatus message={t("panelAppsLoading")} />;
49
- }
50
-
51
- if (panelApps.isError) {
52
- return (
53
- <PanelAppMainStatus
54
- message={panelApps.error instanceof Error
55
- ? panelApps.error.message
56
- : t("panelAppsLoadFailed")}
57
- actionLabel={t("panelAppsTryAgain")}
58
- onAction={() => void panelApps.refetch()}
59
- />
60
- );
61
- }
62
-
63
- if (!entry) {
64
- return (
65
- <PanelAppMainStatus
66
- message={t("panelAppsMainUnavailable")}
67
- actionLabel={t("panelAppsOpenApps")}
68
- onAction={() => openApps(docBrowser)}
69
- />
70
- );
71
- }
72
-
73
- if (runtime.state === "checking" || runtime.state === "idle") {
74
- return <PanelAppMainStatus message={t("panelAppsCheckingPermission")} />;
75
- }
76
-
77
- if (runtime.state === "denied" || runtime.state === "error") {
78
- return (
79
- <PanelAppMainStatus
80
- message={runtime.state === "denied"
81
- ? t("panelAppsPermissionDenied")
82
- : t("panelAppsPermissionFailed")}
83
- actionLabel={t("panelAppsTryAgain")}
84
- onAction={() => void runtime.retryClientGrant()}
85
- />
86
- );
87
- }
88
-
89
- return (
90
- <div className="h-full min-h-0 bg-background">
91
- <iframe
92
- key={entry.appId}
93
- ref={iframeRef}
94
- src={entry.contentPath}
95
- title={entry.title}
96
- sandbox={PANEL_APP_IFRAME_SANDBOX}
97
- className="block h-full w-full border-0 bg-background"
98
- onLoad={restoreScroll}
99
- onPointerOver={(event) => focusPanelAppIframe(event.currentTarget)}
100
- />
101
- </div>
102
- );
103
- }
104
10
 
105
- function PanelAppMainStatus({
106
- actionLabel,
107
- message,
108
- onAction,
109
- }: {
110
- actionLabel?: string;
111
- message: string;
112
- onAction?: () => void;
113
- }) {
114
11
  return (
115
- <div className="flex h-full min-h-0 items-center justify-center bg-background px-6 text-center">
116
- <div className="max-w-sm">
117
- <div className="mx-auto flex h-10 w-10 items-center justify-center rounded-lg bg-muted text-muted-foreground">
118
- {onAction ? <RotateCcw className="h-5 w-5" /> : <Boxes className="h-5 w-5" />}
119
- </div>
120
- <p className="mt-3 text-sm leading-6 text-muted-foreground">{message}</p>
121
- {actionLabel && onAction ? (
122
- <button
123
- type="button"
124
- className="mt-4 rounded-md border border-border px-3 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
125
- onClick={onAction}
126
- >
127
- {actionLabel}
128
- </button>
129
- ) : null}
130
- </div>
131
- </div>
12
+ <PanelAppRuntimeSurface
13
+ appId={appId}
14
+ restorationScope="main"
15
+ unavailableAction={{
16
+ label: t("panelAppsOpenApps"),
17
+ onAction: () => openApps(docBrowser),
18
+ }}
19
+ />
132
20
  );
133
21
  }
@@ -0,0 +1,29 @@
1
+ import { useEffect, useMemo } from "react";
2
+ import { PanelAppRuntimeSurface } from "@/features/panel-apps/components/panel-app-runtime-surface";
3
+ import { usePanelApp } from "@/features/panel-apps/hooks/use-panel-apps";
4
+ import { t } from "@/shared/lib/i18n";
5
+
6
+ export function PanelAppStandalonePage({ appId }: { appId: string }) {
7
+ const panelApp = usePanelApp(appId);
8
+ const entry = useMemo(
9
+ () => panelApp.data,
10
+ [panelApp.data],
11
+ );
12
+
13
+ useEffect(() => {
14
+ const previousTitle = document.title;
15
+ document.title = `${entry?.title ?? t("panelAppsTitle")} · NextClaw`;
16
+ return () => {
17
+ document.title = previousTitle;
18
+ };
19
+ }, [entry?.title]);
20
+
21
+ return (
22
+ <main className="h-dvh min-h-0 w-full overflow-hidden bg-background">
23
+ <PanelAppRuntimeSurface
24
+ appId={appId}
25
+ restorationScope="standalone"
26
+ />
27
+ </main>
28
+ );
29
+ }
@@ -0,0 +1,9 @@
1
+ import { PanelAppBridgeManager } from "@/features/panel-apps/managers/panel-app-bridge.manager";
2
+ import { PanelAppServiceActionAuthorizationManager } from "@/features/panel-apps/managers/panel-app-service-action-authorization.manager";
3
+
4
+ export class PanelAppHostPresenter {
5
+ readonly serviceActionAuthorizationManager = new PanelAppServiceActionAuthorizationManager();
6
+ readonly panelAppBridgeManager = new PanelAppBridgeManager(
7
+ this.serviceActionAuthorizationManager,
8
+ );
9
+ }
@@ -0,0 +1,45 @@
1
+ import {
2
+ createContext,
3
+ useContext,
4
+ useMemo,
5
+ type Context,
6
+ type ReactNode,
7
+ } from "react";
8
+ import { PanelAppHostPresenter } from "@/features/panel-apps/presenters/panel-app-host.presenter";
9
+
10
+ type PanelAppHostContextGlobal = typeof globalThis & {
11
+ __NEXTCLAW_PANEL_APP_HOST_CONTEXT__?: Context<PanelAppHostPresenter | null>;
12
+ };
13
+
14
+ const contextGlobal = globalThis as PanelAppHostContextGlobal;
15
+ const PanelAppHostContext =
16
+ contextGlobal.__NEXTCLAW_PANEL_APP_HOST_CONTEXT__ ??
17
+ createContext<PanelAppHostPresenter | null>(null);
18
+
19
+ contextGlobal.__NEXTCLAW_PANEL_APP_HOST_CONTEXT__ = PanelAppHostContext;
20
+
21
+ export function PanelAppHostProvider({
22
+ children,
23
+ presenter: providedPresenter,
24
+ }: {
25
+ children: ReactNode;
26
+ presenter?: PanelAppHostPresenter;
27
+ }) {
28
+ const presenter = useMemo(
29
+ () => providedPresenter ?? new PanelAppHostPresenter(),
30
+ [providedPresenter],
31
+ );
32
+ return (
33
+ <PanelAppHostContext.Provider value={presenter}>
34
+ {children}
35
+ </PanelAppHostContext.Provider>
36
+ );
37
+ }
38
+
39
+ export function usePanelAppHostPresenter(): PanelAppHostPresenter {
40
+ const presenter = useContext(PanelAppHostContext);
41
+ if (!presenter) {
42
+ throw new Error("usePanelAppHostPresenter must be used inside PanelAppHostProvider");
43
+ }
44
+ return presenter;
45
+ }
@@ -0,0 +1,50 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { describe, expect, it, vi } from 'vitest';
3
+ import {
4
+ PanelAppStandaloneRoute,
5
+ readStandalonePanelAppId,
6
+ } from '@/features/panel-apps/routes/panel-app-standalone.route';
7
+
8
+ vi.mock('sonner', () => ({
9
+ Toaster: () => <div data-testid="toaster" />,
10
+ }));
11
+
12
+ vi.mock('@/shared/hooks/use-auth-status', () => ({
13
+ isTransientAuthStatusBootstrapError: () => false,
14
+ useAuthStatus: () => ({
15
+ data: { authenticated: true, enabled: false },
16
+ isError: false,
17
+ isLoading: false,
18
+ }),
19
+ }));
20
+
21
+ vi.mock('@/features/panel-apps/pages/panel-app-standalone-page', () => ({
22
+ PanelAppStandalonePage: ({ appId }: { appId: string }) => (
23
+ <main data-testid="standalone-panel-app" data-app-id={appId} />
24
+ ),
25
+ }));
26
+
27
+ vi.mock('@/features/panel-apps/providers/panel-app-host.provider', () => ({
28
+ PanelAppHostProvider: ({ children }: { children: React.ReactNode }) => children,
29
+ }));
30
+
31
+ vi.mock('@/features/panel-apps/components/panel-app-service-action-authorization-dialog', () => ({
32
+ PanelAppServiceActionAuthorizationDialog: () => <div data-testid="authorization-dialog" />,
33
+ }));
34
+
35
+ describe('PanelAppStandaloneRoute', () => {
36
+ it('parses only the dedicated standalone route', () => {
37
+ expect(readStandalonePanelAppId('/apps/panel/publisher.todo/standalone')).toBe('publisher.todo');
38
+ expect(readStandalonePanelAppId('/apps/panel/a%20b/standalone/')).toBe('a b');
39
+ expect(readStandalonePanelAppId('/apps/panel/publisher.todo')).toBeNull();
40
+ });
41
+
42
+ it('renders the lightweight Panel host for the requested app', () => {
43
+ render(<PanelAppStandaloneRoute pathname="/apps/panel/publisher.todo/standalone" />);
44
+
45
+ expect(screen.getByTestId('standalone-panel-app').getAttribute('data-app-id'))
46
+ .toBe('publisher.todo');
47
+ expect(screen.getByTestId('authorization-dialog')).toBeTruthy();
48
+ expect(screen.getByTestId('toaster')).toBeTruthy();
49
+ });
50
+ });
@@ -0,0 +1,94 @@
1
+ import { lazy, StrictMode, Suspense } from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import { QueryClientProvider } from '@tanstack/react-query';
4
+ import { Toaster } from 'sonner';
5
+ import { appQueryClient } from '@/app-query-client';
6
+ import { I18nProvider } from '@/app/components/i18n-provider';
7
+ import { ThemeProvider } from '@/app/components/theme-provider';
8
+ import { PanelAppStandalonePage } from '@/features/panel-apps/pages/panel-app-standalone-page';
9
+ import { PanelAppHostProvider } from '@/features/panel-apps/providers/panel-app-host.provider';
10
+ import { PanelAppServiceActionAuthorizationDialog } from '@/features/panel-apps/components/panel-app-service-action-authorization-dialog';
11
+ import { installPanelAppI18nCatalog, t } from '@/shared/lib/i18n';
12
+ import { isTransientAuthStatusBootstrapError, useAuthStatus } from '@/shared/hooks/use-auth-status';
13
+ import '@/app/styles/panel-app-standalone.css';
14
+
15
+ const LoginPage = lazy(async () => ({
16
+ default: (await import('@/features/account/components/login-page')).LoginPage,
17
+ }));
18
+
19
+ const PANEL_APP_STANDALONE_PATH = /^\/apps\/panel\/([^/]+)\/standalone\/?$/;
20
+
21
+ export function readStandalonePanelAppId(pathname: string): string | null {
22
+ const match = PANEL_APP_STANDALONE_PATH.exec(pathname);
23
+ if (!match) return null;
24
+ try {
25
+ return decodeURIComponent(match[1]);
26
+ } catch {
27
+ return null;
28
+ }
29
+ }
30
+
31
+ function StandaloneAuthGate({ appId }: { appId: string }) {
32
+ const authStatus = useAuthStatus();
33
+ const isTransientBootstrapFailure =
34
+ authStatus.isError && isTransientAuthStatusBootstrapError(authStatus.error);
35
+
36
+ if (
37
+ (authStatus.isLoading && !authStatus.isError) ||
38
+ isTransientBootstrapFailure ||
39
+ authStatus.isError
40
+ ) {
41
+ return <PanelAppStandalonePage appId={appId} />;
42
+ }
43
+
44
+ if (authStatus.data?.enabled && !authStatus.data.authenticated) {
45
+ return (
46
+ <Suspense fallback={<StandaloneStatus message={t('loading')} />}>
47
+ <LoginPage username={authStatus.data.username} />
48
+ </Suspense>
49
+ );
50
+ }
51
+
52
+ return <PanelAppStandalonePage appId={appId} />;
53
+ }
54
+
55
+ function StandaloneStatus({ message }: { message: string }) {
56
+ return (
57
+ <main className="flex h-dvh items-center justify-center bg-background px-6 text-sm text-muted-foreground">
58
+ {message}
59
+ </main>
60
+ );
61
+ }
62
+
63
+ export function PanelAppStandaloneRoute({ pathname = window.location.pathname }: { pathname?: string }) {
64
+ const appId = readStandalonePanelAppId(pathname);
65
+
66
+ if (!appId) {
67
+ return <StandaloneStatus message={t('panelAppsMainUnavailable')} />;
68
+ }
69
+
70
+ return (
71
+ <QueryClientProvider client={appQueryClient}>
72
+ <PanelAppHostProvider>
73
+ <StandaloneAuthGate appId={appId} />
74
+ <PanelAppServiceActionAuthorizationDialog />
75
+ <Toaster position="top-right" richColors offset={16} />
76
+ </PanelAppHostProvider>
77
+ </QueryClientProvider>
78
+ );
79
+ }
80
+
81
+ await installPanelAppI18nCatalog();
82
+
83
+ const rootElement = document.getElementById('root');
84
+ if (rootElement) {
85
+ createRoot(rootElement).render(
86
+ <StrictMode>
87
+ <ThemeProvider>
88
+ <I18nProvider>
89
+ <PanelAppStandaloneRoute />
90
+ </I18nProvider>
91
+ </ThemeProvider>
92
+ </StrictMode>,
93
+ );
94
+ }
@@ -3,28 +3,28 @@ import type { ServiceActionListView } from '@nextclaw/client-sdk';
3
3
 
4
4
  type ServiceActionRisk = ServiceActionListView['actions'][number]['risk'];
5
5
 
6
- export type ServiceActionAuthorizationItem = {
6
+ export type PanelAppServiceActionAuthorizationItem = {
7
7
  actionId: string;
8
8
  actionTitle?: string;
9
9
  actionDescription?: string;
10
10
  risk?: ServiceActionRisk;
11
11
  };
12
12
 
13
- export type ServiceActionAuthorizationRequest = {
13
+ export type PanelAppServiceActionAuthorizationRequest = {
14
14
  id: string;
15
15
  panelAppId: string;
16
- actions: ServiceActionAuthorizationItem[];
16
+ actions: PanelAppServiceActionAuthorizationItem[];
17
17
  inputPreview?: string;
18
18
  };
19
19
 
20
- type PendingAuthorization = ServiceActionAuthorizationRequest & {
20
+ type PendingAuthorization = PanelAppServiceActionAuthorizationRequest & {
21
21
  resolve: (allowed: boolean) => void;
22
22
  };
23
23
 
24
24
  type ServiceActionAuthorizationState = {
25
25
  pending: PendingAuthorization | null;
26
26
  requestAuthorization: (
27
- request: Omit<ServiceActionAuthorizationRequest, 'id'>,
27
+ request: Omit<PanelAppServiceActionAuthorizationRequest, 'id'>,
28
28
  ) => Promise<boolean>;
29
29
  resolveAuthorization: (allowed: boolean) => void;
30
30
  };
@@ -33,7 +33,7 @@ function createAuthorizationId(): string {
33
33
  return `service-action-auth-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
34
34
  }
35
35
 
36
- export const useServiceActionAuthorizationStore = create<ServiceActionAuthorizationState>((set, get) => ({
36
+ export const usePanelAppServiceActionAuthorizationStore = create<ServiceActionAuthorizationState>((set, get) => ({
37
37
  pending: null,
38
38
  requestAuthorization: async (request) =>
39
39
  await new Promise<boolean>((resolve) => {
@@ -0,0 +1,70 @@
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("@/features/projects/hooks/use-project-work", () => ({
6
+ useProjectWorkEvents: vi.fn(),
7
+ useProjectWorkSummary: () => ({
8
+ data: { total: 4, active: 2, attention: 1, completed: 1 },
9
+ isLoading: false,
10
+ isError: false,
11
+ }),
12
+ useProjectWork: () => ({
13
+ data: {
14
+ pages: [
15
+ {
16
+ items: [
17
+ {
18
+ id: "work-1",
19
+ title: "Current work",
20
+ state: { name: "In Progress" },
21
+ },
22
+ ],
23
+ },
24
+ ],
25
+ },
26
+ isLoading: false,
27
+ isError: false,
28
+ }),
29
+ useProjectRecentArtifacts: () => ({
30
+ data: {
31
+ artifacts: [
32
+ {
33
+ id: "artifact-1",
34
+ path: "docs/design.md",
35
+ label: "Design",
36
+ workItemTitle: "Current work",
37
+ createdAt: "2026-09-03T00:00:00.000Z",
38
+ exists: true,
39
+ },
40
+ ],
41
+ },
42
+ isLoading: false,
43
+ isError: false,
44
+ }),
45
+ }));
46
+
47
+ describe("ProjectOverview", () => {
48
+ it("renders current work and recent artifacts as equal wide-layout columns", () => {
49
+ const onOpenWorkItem = vi.fn();
50
+ const onOpenArtifact = vi.fn();
51
+ const { container } = render(
52
+ <ProjectOverview
53
+ projectId="project-1"
54
+ onOpenWorkItem={onOpenWorkItem}
55
+ onOpenArtifact={onOpenArtifact}
56
+ />,
57
+ );
58
+
59
+ expect(screen.getByText(/Recently updated|最近更新/)).toBeTruthy();
60
+ expect(screen.getByText(/Recent artifacts|最近产物/)).toBeTruthy();
61
+ expect(container.querySelector(".lg\\:grid-cols-2")).toBeTruthy();
62
+
63
+ fireEvent.click(
64
+ screen.getAllByRole("button", { name: /Current work/ })[0]!,
65
+ );
66
+ fireEvent.click(screen.getByRole("button", { name: /Design/ }));
67
+ expect(onOpenWorkItem).toHaveBeenCalledWith("work-1");
68
+ expect(onOpenArtifact).toHaveBeenCalledWith("docs/design.md", "Design");
69
+ });
70
+ });