@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
@@ -1,69 +1,19 @@
1
- import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
2
- import { useEffect, useState } from 'react';
1
+ import { useMutation, useQueryClient } from '@tanstack/react-query';
3
2
  import {
4
- fetchAuthStatus,
5
3
  loginAuth,
6
4
  logoutAuth,
7
5
  setupAuth,
8
6
  updateAuthEnabled,
9
7
  updateAuthPassword
10
8
  } from '@/shared/lib/api';
11
- import type { AuthStatusView } from '@/shared/lib/api';
12
9
  import { toast } from 'sonner';
13
10
  import { t } from '@/shared/lib/i18n';
14
- import { isTransientRuntimeConnectionErrorMessage } from '@/shared/lib/transport';
15
-
16
- const AUTH_STATUS_BOOTSTRAP_PROBE_POLICY = {
17
- maxRetries: 8,
18
- startupTimeoutMs: 2_000,
19
- settledTimeoutMs: 5_000,
20
- retryBaseDelayMs: 500,
21
- retryMaxDelayMs: 3_000,
22
- } as const;
23
-
24
- export function isTransientAuthStatusBootstrapError(error: unknown): boolean {
25
- if (!(error instanceof Error)) {
26
- return false;
27
- }
28
- return isTransientRuntimeConnectionErrorMessage(error.message);
29
- }
30
-
31
- export function shouldRetryAuthStatusBootstrap(failureCount: number, error: unknown): boolean {
32
- if (failureCount >= AUTH_STATUS_BOOTSTRAP_PROBE_POLICY.maxRetries) {
33
- return false;
34
- }
35
- return isTransientAuthStatusBootstrapError(error);
36
- }
37
-
38
- export function resolveAuthStatusBootstrapRetryDelay(failureCount: number): number {
39
- return Math.min(
40
- AUTH_STATUS_BOOTSTRAP_PROBE_POLICY.retryMaxDelayMs,
41
- AUTH_STATUS_BOOTSTRAP_PROBE_POLICY.retryBaseDelayMs * 2 ** Math.max(0, failureCount - 1)
42
- );
43
- }
44
-
45
- export function useAuthStatus() {
46
- const [bootstrapSettled, setBootstrapSettled] = useState(false);
47
- const query = useQuery<AuthStatusView>({
48
- queryKey: ['auth-status'],
49
- queryFn: () => fetchAuthStatus({
50
- timeoutMs: bootstrapSettled
51
- ? AUTH_STATUS_BOOTSTRAP_PROBE_POLICY.settledTimeoutMs
52
- : AUTH_STATUS_BOOTSTRAP_PROBE_POLICY.startupTimeoutMs,
53
- }),
54
- staleTime: 5_000,
55
- retry: shouldRetryAuthStatusBootstrap,
56
- retryDelay: resolveAuthStatusBootstrapRetryDelay
57
- });
58
-
59
- useEffect(() => {
60
- if (query.isSuccess && !bootstrapSettled) {
61
- setBootstrapSettled(true);
62
- }
63
- }, [bootstrapSettled, query.isSuccess]);
64
-
65
- return query;
66
- }
11
+ export {
12
+ isTransientAuthStatusBootstrapError,
13
+ resolveAuthStatusBootstrapRetryDelay,
14
+ shouldRetryAuthStatusBootstrap,
15
+ useAuthStatus,
16
+ } from "@/shared/hooks/use-auth-status";
67
17
 
68
18
  function invalidateProtectedQueries(queryClient: ReturnType<typeof useQueryClient>): Promise<unknown[]> {
69
19
  return Promise.all([
@@ -1,4 +1,5 @@
1
- export { AccountPanel } from './components/account-panel';
2
- export { LoginPage } from './components/login-page';
3
1
  export { AccountManager } from './managers/account.manager';
4
2
  export { useAccountStore } from './stores/account.store';
3
+ export async function loadAccountPanel() {
4
+ return await import('./components/account-panel');
5
+ }
@@ -14,11 +14,13 @@ vi.mock('@/features/panel-apps', () => ({
14
14
  PanelAppsList: () => <div>panel-apps-content</div>,
15
15
  }));
16
16
  vi.mock('@/features/service-apps', () => ({
17
- ServiceAppsPanel: ({ onManagePackage }: { onManagePackage: (packageId: string) => void }) => (
18
- <button type="button" onClick={() => onManagePackage('nextclaw.personal-organizer')}>
19
- service-apps-content
20
- </button>
21
- ),
17
+ loadServiceAppsPanel: async () => ({
18
+ ServiceAppsPanel: ({ onManagePackage }: { onManagePackage: (packageId: string) => void }) => (
19
+ <button type="button" onClick={() => onManagePackage('nextclaw.personal-organizer')}>
20
+ service-apps-content
21
+ </button>
22
+ ),
23
+ }),
22
24
  }));
23
25
 
24
26
  function AppsPanelHarness() {
@@ -1,14 +1,18 @@
1
- import { useState } from 'react';
1
+ import { lazy, Suspense, useState } from 'react';
2
2
  import { AppWindow, Boxes, Server } from 'lucide-react';
3
3
  import type { PanelAppEntryView } from '@/shared/lib/api';
4
4
  import { AppPackagesPanel } from '@/features/apps/components/app-packages-panel';
5
5
  import { PanelAppsList } from '@/features/panel-apps';
6
- import { ServiceAppsPanel } from '@/features/service-apps';
6
+ import { loadServiceAppsPanel } from '@/features/service-apps';
7
7
  import { Tabs, TabsList, TabsTrigger } from '@/shared/components/ui/tabs';
8
8
  import { t } from '@/shared/lib/i18n';
9
9
 
10
10
  export type AppsPanelTab = 'apps' | 'panel-apps' | 'service-apps';
11
11
 
12
+ const ServiceAppsPanel = lazy(async () => ({
13
+ default: (await loadServiceAppsPanel()).ServiceAppsPanel,
14
+ }));
15
+
12
16
  export function AppsPanel({
13
17
  activeTab,
14
18
  onActiveTabChange,
@@ -54,7 +58,9 @@ export function AppsPanel({
54
58
  ) : activeTab === 'panel-apps' ? (
55
59
  <PanelAppsList onOpenPanelApp={onOpenPanelApp} />
56
60
  ) : (
57
- <ServiceAppsPanel onManagePackage={managePackage} />
61
+ <Suspense fallback={null}>
62
+ <ServiceAppsPanel onManagePackage={managePackage} />
63
+ </Suspense>
58
64
  )}
59
65
  </div>
60
66
  </div>
@@ -10,7 +10,7 @@ describe("groupSessionsByProject", () => {
10
10
  template: "knowledge-base",
11
11
  createdAt: "2026-07-15T00:00:00.000Z",
12
12
  updatedAt: "2026-07-15T00:00:00.000Z",
13
- }]);
13
+ },]);
14
14
 
15
15
  expect(groups).toEqual([{
16
16
  projectId: "project-knowledge",
@@ -19,6 +19,31 @@ describe("groupSessionsByProject", () => {
19
19
  items: [],
20
20
  latestUpdatedAt: new Date("2026-07-15T00:00:00.000Z").getTime(),
21
21
  isPinned: false,
22
- }]);
22
+ },
23
+ ]);
24
+ });
25
+
26
+ it("keeps sessions for removed projects out of the project-first view", () => {
27
+ const groups = groupSessionsByProject(
28
+ [
29
+ {
30
+ session: {
31
+ key: "session:removed-project",
32
+ projectRoot: "/tmp/removed",
33
+ projectName: "Removed",
34
+ createdAt: "2026-07-15T00:00:00.000Z",
35
+ updatedAt: "2026-07-15T00:00:00.000Z",
36
+ sessionType: "native",
37
+ sessionTypeMutable: false,
38
+ messageCount: 1,
39
+ },
40
+ },
41
+ ],
42
+ new Set(),
43
+ new Set(),
44
+ [],
45
+ );
46
+
47
+ expect(groups).toEqual([]);
23
48
  });
24
49
  });
@@ -1,6 +1,5 @@
1
1
  import type { ProjectView, SessionEntryView } from "@/shared/lib/api";
2
2
  import type { NcpSessionListItemView } from "@/features/chat/features/ncp/hooks/use-ncp-session-list-view";
3
- import { getSessionProjectName } from "@/shared/lib/session-project";
4
3
  import { t } from "@/shared/lib/i18n";
5
4
 
6
5
  export type ChatSidebarDateGroup = {
@@ -127,16 +126,6 @@ export function groupSessionsByProject(
127
126
  );
128
127
  continue;
129
128
  }
130
- grouped.set(projectRoot, {
131
- projectRoot,
132
- projectName:
133
- item.session.projectName?.trim() ||
134
- getSessionProjectName(projectRoot) ||
135
- projectRoot,
136
- items: [item],
137
- latestUpdatedAt: updatedAt,
138
- isPinned: pinnedProjectRoots.has(projectRoot),
139
- });
140
129
  }
141
130
 
142
131
  return [...grouped.values()]
@@ -124,4 +124,22 @@ describe('PanelAppListItem', () => {
124
124
  preferences: { mainSidebar: false },
125
125
  });
126
126
  });
127
+
128
+ it('offers the standalone app link from the more-actions menu', async () => {
129
+ const user = userEvent.setup();
130
+ render(
131
+ <PanelAppListItem
132
+ deletePending={false}
133
+ entry={baseEntry}
134
+ favoritePending={false}
135
+ onDelete={vi.fn()}
136
+ onOpen={vi.fn()}
137
+ onToggleFavorite={vi.fn()}
138
+ />,
139
+ );
140
+
141
+ await user.click(screen.getByRole('button', { name: 'More panel app actions' }));
142
+ const link = screen.getByRole('link', { name: 'Open in New Tab' });
143
+ expect(link.getAttribute('href')).toBe('/apps/panel/demo/standalone');
144
+ });
127
145
  });
@@ -0,0 +1,56 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import { afterEach, describe, expect, it, vi } from "vitest";
3
+ import { PanelAppOpenStandaloneMenuItem } from "@/features/panel-apps/components/panel-app-open-standalone-menu-item";
4
+ import type { PanelAppEntryView } from "@/shared/lib/api";
5
+
6
+ const entry: PanelAppEntryView = {
7
+ appId: "publisher.todo board",
8
+ clientDeclared: false,
9
+ clientGranted: false,
10
+ contentPath: "/api/panel-apps/publisher.todo%20board/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: "Todo",
20
+ updatedAt: "2026-09-03T00:00:00.000Z",
21
+ };
22
+
23
+ function setDesktopHost(value: Window["nextclawDesktop"] | undefined) {
24
+ Object.defineProperty(window, "nextclawDesktop", {
25
+ configurable: true,
26
+ value,
27
+ });
28
+ }
29
+
30
+ describe("PanelAppOpenStandaloneMenuItem", () => {
31
+ afterEach(() => {
32
+ setDesktopHost(undefined);
33
+ });
34
+
35
+ it("uses a real new-tab link on the web", () => {
36
+ const onSelect = vi.fn();
37
+ setDesktopHost(undefined);
38
+ render(
39
+ <PanelAppOpenStandaloneMenuItem entry={entry} onSelect={onSelect} />,
40
+ );
41
+
42
+ const link = screen.getByRole("link", { name: "Open in New Tab" });
43
+ expect(link.getAttribute("href")).toBe(
44
+ "/apps/panel/publisher.todo%20board/standalone",
45
+ );
46
+ expect(link.getAttribute("target")).toBe("_blank");
47
+ expect(link.getAttribute("rel")).toBe("noopener noreferrer");
48
+ });
49
+
50
+ it("describes the same link as opening in the browser inside Desktop", () => {
51
+ setDesktopHost({ platform: "darwin" } as Window["nextclawDesktop"]);
52
+ render(<PanelAppOpenStandaloneMenuItem entry={entry} />);
53
+
54
+ expect(screen.getByRole("link", { name: "Open in Browser" })).toBeTruthy();
55
+ });
56
+ });
@@ -82,4 +82,19 @@ describe('PanelAppToolbar', () => {
82
82
  preferences: { mainSidebar: false },
83
83
  });
84
84
  });
85
+
86
+ it('offers the standalone app link from the toolbar menu', async () => {
87
+ const user = userEvent.setup();
88
+ render(
89
+ <PanelAppToolbar
90
+ appTitle="墨爪助手"
91
+ entry={entry}
92
+ onRefresh={vi.fn()}
93
+ />,
94
+ );
95
+
96
+ await user.click(screen.getByRole('button', { name: 'More panel app actions' }));
97
+ const link = screen.getByRole('link', { name: 'Open in New Tab' });
98
+ expect(link.getAttribute('href')).toBe('/apps/panel/ink-assistant/standalone');
99
+ });
85
100
  });
@@ -3,6 +3,7 @@ import { MoreVertical, Star, Trash2, type LucideIcon } from 'lucide-react';
3
3
  import type { PanelAppEntryView } from '@/shared/lib/api';
4
4
  import { PanelAppIcon } from '@/features/panel-apps/components/panel-app-icon';
5
5
  import { PanelAppMainSidebarMenuItem } from '@/features/panel-apps/components/panel-app-main-sidebar-menu-item';
6
+ import { PanelAppOpenStandaloneMenuItem } from '@/features/panel-apps/components/panel-app-open-standalone-menu-item';
6
7
  import { ConfirmDialog } from '@/shared/components/ui/confirm-dialog';
7
8
  import { Popover, PopoverContent, PopoverTrigger } from '@/shared/components/ui/popover';
8
9
  import { getLanguage, getLocale, t } from '@/shared/lib/i18n';
@@ -76,6 +77,10 @@ export function PanelAppListItem({
76
77
  </button>
77
78
  </PopoverTrigger>
78
79
  <PopoverContent align="end" className="w-48 rounded-xl p-1.5">
80
+ <PanelAppOpenStandaloneMenuItem
81
+ entry={entry}
82
+ onSelect={() => setIsMenuOpen(false)}
83
+ />
79
84
  <PanelAppMainSidebarMenuItem
80
85
  entry={entry}
81
86
  onSelect={() => setIsMenuOpen(false)}
@@ -0,0 +1,29 @@
1
+ import { ExternalLink } from "lucide-react";
2
+ import type { PanelAppEntryView } from "@/shared/lib/api";
3
+ import { t } from "@/shared/lib/i18n";
4
+
5
+ export function PanelAppOpenStandaloneMenuItem({
6
+ entry,
7
+ onSelect,
8
+ }: {
9
+ entry: PanelAppEntryView;
10
+ onSelect?: () => void;
11
+ }) {
12
+ const label = typeof window !== "undefined" && window.nextclawDesktop
13
+ ? t("panelAppsOpenInBrowser")
14
+ : t("panelAppsOpenInNewTab");
15
+ const href = `/apps/panel/${encodeURIComponent(entry.appId)}/standalone`;
16
+
17
+ return (
18
+ <a
19
+ href={href}
20
+ target="_blank"
21
+ rel="noopener noreferrer"
22
+ className="flex w-full items-center gap-2 rounded-lg px-2.5 py-2 text-left text-sm text-muted-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-accent-foreground"
23
+ onClick={onSelect}
24
+ >
25
+ <ExternalLink className="h-4 w-4 shrink-0" />
26
+ <span>{label}</span>
27
+ </a>
28
+ );
29
+ }
@@ -0,0 +1,141 @@
1
+ import { useEffect, useMemo, useRef } from "react";
2
+ import { Boxes, RotateCcw } from "lucide-react";
3
+ import { usePanelAppHostPresenter } from "@/features/panel-apps/providers/panel-app-host.provider";
4
+ import { usePanelAppRuntime } from "@/features/panel-apps/hooks/use-panel-app-runtime";
5
+ import { usePanelApp } from "@/features/panel-apps/hooks/use-panel-apps";
6
+ import {
7
+ PANEL_APP_IFRAME_SANDBOX,
8
+ focusPanelAppIframe,
9
+ } from "@/features/panel-apps/utils/panel-app-iframe.utils";
10
+ import { usePanelAppScrollRestoration } from "@/shared/hooks/use-panel-app-scroll-restoration";
11
+ import { t } from "@/shared/lib/i18n";
12
+
13
+ type PanelAppUnavailableAction = {
14
+ label: string;
15
+ onAction: () => void;
16
+ };
17
+
18
+ export function PanelAppRuntimeSurface({
19
+ appId,
20
+ restorationScope,
21
+ unavailableAction,
22
+ }: {
23
+ appId: string;
24
+ restorationScope: "main" | "standalone";
25
+ unavailableAction?: PanelAppUnavailableAction;
26
+ }) {
27
+ const presenter = usePanelAppHostPresenter();
28
+ const panelApp = usePanelApp(appId);
29
+ const iframeRef = useRef<HTMLIFrameElement>(null);
30
+ const entry = useMemo(
31
+ () => panelApp.data,
32
+ [panelApp.data],
33
+ );
34
+ const runtime = usePanelAppRuntime(entry);
35
+ const restoreScroll = usePanelAppScrollRestoration({
36
+ currentUrl: entry?.contentPath ?? null,
37
+ iframeRef,
38
+ isEnabled: Boolean(entry),
39
+ restorationKey: entry
40
+ ? `panel-app:${restorationScope}:${entry.appId}`
41
+ : null,
42
+ });
43
+
44
+ useEffect(() => {
45
+ const handleMessage = (event: MessageEvent) => {
46
+ presenter.panelAppBridgeManager.handleIframeMessage({
47
+ event,
48
+ iframe: iframeRef.current,
49
+ });
50
+ };
51
+ window.addEventListener("message", handleMessage);
52
+ return () => window.removeEventListener("message", handleMessage);
53
+ }, [presenter]);
54
+
55
+ if (panelApp.isLoading) {
56
+ return <PanelAppRuntimeStatus message={t("panelAppsLoading")} />;
57
+ }
58
+
59
+ if (panelApp.isError) {
60
+ return (
61
+ <PanelAppRuntimeStatus
62
+ message={panelApp.error instanceof Error
63
+ ? panelApp.error.message
64
+ : t("panelAppsLoadFailed")}
65
+ actionLabel={t("panelAppsTryAgain")}
66
+ onAction={() => void panelApp.refetch()}
67
+ />
68
+ );
69
+ }
70
+
71
+ if (!entry) {
72
+ return (
73
+ <PanelAppRuntimeStatus
74
+ message={t("panelAppsMainUnavailable")}
75
+ actionLabel={unavailableAction?.label}
76
+ onAction={unavailableAction?.onAction}
77
+ />
78
+ );
79
+ }
80
+
81
+ if (runtime.state === "checking" || runtime.state === "idle") {
82
+ return <PanelAppRuntimeStatus message={t("panelAppsCheckingPermission")} />;
83
+ }
84
+
85
+ if (runtime.state === "denied" || runtime.state === "error") {
86
+ return (
87
+ <PanelAppRuntimeStatus
88
+ message={runtime.state === "denied"
89
+ ? t("panelAppsPermissionDenied")
90
+ : t("panelAppsPermissionFailed")}
91
+ actionLabel={t("panelAppsTryAgain")}
92
+ onAction={() => void runtime.retryClientGrant()}
93
+ />
94
+ );
95
+ }
96
+
97
+ return (
98
+ <div className="h-full min-h-0 bg-background">
99
+ <iframe
100
+ key={entry.appId}
101
+ ref={iframeRef}
102
+ src={entry.contentPath}
103
+ title={entry.title}
104
+ sandbox={PANEL_APP_IFRAME_SANDBOX}
105
+ className="block h-full w-full border-0 bg-background"
106
+ onLoad={restoreScroll}
107
+ onPointerOver={(event) => focusPanelAppIframe(event.currentTarget)}
108
+ />
109
+ </div>
110
+ );
111
+ }
112
+
113
+ function PanelAppRuntimeStatus({
114
+ actionLabel,
115
+ message,
116
+ onAction,
117
+ }: {
118
+ actionLabel?: string;
119
+ message: string;
120
+ onAction?: () => void;
121
+ }) {
122
+ return (
123
+ <div className="flex h-full min-h-0 items-center justify-center bg-background px-6 text-center">
124
+ <div className="max-w-sm">
125
+ <div className="mx-auto flex h-10 w-10 items-center justify-center rounded-lg bg-muted text-muted-foreground">
126
+ {onAction ? <RotateCcw className="h-5 w-5" /> : <Boxes className="h-5 w-5" />}
127
+ </div>
128
+ <p className="mt-3 text-sm leading-6 text-muted-foreground">{message}</p>
129
+ {actionLabel && onAction ? (
130
+ <button
131
+ type="button"
132
+ 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"
133
+ onClick={onAction}
134
+ >
135
+ {actionLabel}
136
+ </button>
137
+ ) : null}
138
+ </div>
139
+ </div>
140
+ );
141
+ }
@@ -9,11 +9,11 @@ import {
9
9
  } from '@/shared/components/ui/dialog';
10
10
  import { Button } from '@/shared/components/ui/button';
11
11
  import { t } from '@/shared/lib/i18n';
12
- import { useServiceActionAuthorizationStore } from '@/features/service-apps/stores/service-action-authorization.store';
12
+ import { usePanelAppServiceActionAuthorizationStore } from '@/features/panel-apps/stores/panel-app-service-action-authorization.store';
13
13
 
14
- export function ServiceActionAuthorizationDialog() {
15
- const pending = useServiceActionAuthorizationStore((state) => state.pending);
16
- const resolveAuthorization = useServiceActionAuthorizationStore(
14
+ export function PanelAppServiceActionAuthorizationDialog() {
15
+ const pending = usePanelAppServiceActionAuthorizationStore((state) => state.pending);
16
+ const resolveAuthorization = usePanelAppServiceActionAuthorizationStore(
17
17
  (state) => state.resolveAuthorization,
18
18
  );
19
19
 
@@ -1,6 +1,7 @@
1
1
  import { useMemo, useState } from 'react';
2
2
  import { MoreVertical, RefreshCw } from 'lucide-react';
3
3
  import { PanelAppMainSidebarMenuItem } from '@/features/panel-apps/components/panel-app-main-sidebar-menu-item';
4
+ import { PanelAppOpenStandaloneMenuItem } from '@/features/panel-apps/components/panel-app-open-standalone-menu-item';
4
5
  import { usePanelApps } from '@/features/panel-apps/hooks/use-panel-apps';
5
6
  import { readPanelAppIdFromTab } from '@/features/right-panel-resources';
6
7
  import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
@@ -39,6 +40,10 @@ export function PanelAppToolbar({
39
40
  />
40
41
  </PopoverTrigger>
41
42
  <PopoverContent align="end" className="w-48 rounded-xl p-1.5">
43
+ <PanelAppOpenStandaloneMenuItem
44
+ entry={entry}
45
+ onSelect={() => setIsMenuOpen(false)}
46
+ />
42
47
  <PanelAppMainSidebarMenuItem
43
48
  entry={entry}
44
49
  onSelect={() => setIsMenuOpen(false)}
@@ -1,11 +1,11 @@
1
1
  import { useCallback, useRef } from "react";
2
- import { useAppPresenter } from "@/app/components/app-presenter-provider";
2
+ import { usePanelAppHostPresenter } from "@/features/panel-apps/providers/panel-app-host.provider";
3
3
  import { useGrantPanelAppClient } from "@/features/panel-apps/hooks/use-panel-apps";
4
4
  import type { PanelAppEntryView } from "@/shared/lib/api";
5
5
  import { t } from "@/shared/lib/i18n";
6
6
 
7
7
  export function usePanelAppClientGrant() {
8
- const presenter = useAppPresenter();
8
+ const presenter = usePanelAppHostPresenter();
9
9
  const { isPending, mutateAsync: grantPanelAppClient } = useGrantPanelAppClient();
10
10
  const pendingGrantsRef = useRef(new Map<string, Promise<boolean>>());
11
11
 
@@ -2,6 +2,7 @@ import { useId } from "react";
2
2
  import { useQuery, useQueryClient } from "@tanstack/react-query";
3
3
  import { usePanelAppClientGrant } from "@/features/panel-apps/hooks/use-panel-app-client-grant";
4
4
  import {
5
+ PANEL_APP_QUERY_KEY,
5
6
  PANEL_APPS_QUERY_KEY,
6
7
  replacePanelAppListEntry,
7
8
  } from "@/features/panel-apps/hooks/use-panel-apps";
@@ -11,9 +12,9 @@ import {
11
12
  type PanelAppListView,
12
13
  } from "@/shared/lib/api";
13
14
 
14
- export type PanelAppMainRuntimeState = "allowed" | "checking" | "denied" | "error" | "idle";
15
+ export type PanelAppRuntimeState = "allowed" | "checking" | "denied" | "error" | "idle";
15
16
 
16
- export function usePanelAppMainRuntime(entry: PanelAppEntryView | undefined) {
17
+ export function usePanelAppRuntime(entry: PanelAppEntryView | undefined) {
17
18
  const queryClient = useQueryClient();
18
19
  const runtimeInstanceId = useId();
19
20
  const { ensurePanelAppClientGrant } = usePanelAppClientGrant();
@@ -22,7 +23,7 @@ export function usePanelAppMainRuntime(entry: PanelAppEntryView | undefined) {
22
23
  );
23
24
  const grantQuery = useQuery({
24
25
  queryKey: [
25
- "panel-app-main-client-grant",
26
+ "panel-app-client-grant",
26
27
  entry?.appId ?? "none",
27
28
  entry?.clientGranted ?? false,
28
29
  ],
@@ -32,7 +33,7 @@ export function usePanelAppMainRuntime(entry: PanelAppEntryView | undefined) {
32
33
  retry: false,
33
34
  staleTime: Number.POSITIVE_INFINITY,
34
35
  });
35
- const state: PanelAppMainRuntimeState = !entry
36
+ const state: PanelAppRuntimeState = !entry
36
37
  ? "idle"
37
38
  : !requiresClientGrant
38
39
  ? "allowed"
@@ -45,13 +46,14 @@ export function usePanelAppMainRuntime(entry: PanelAppEntryView | undefined) {
45
46
  : "denied";
46
47
 
47
48
  useQuery({
48
- queryKey: ["panel-app-main-open", runtimeInstanceId, entry?.appId ?? "none"],
49
+ queryKey: ["panel-app-open", runtimeInstanceId, entry?.appId ?? "none"],
49
50
  queryFn: async () => {
50
51
  const opened = await nextclawClient.panelApps.recordPanelAppOpened(entry!.id);
51
52
  queryClient.setQueryData<PanelAppListView>(
52
53
  PANEL_APPS_QUERY_KEY,
53
54
  (current) => replacePanelAppListEntry(current, opened),
54
55
  );
56
+ queryClient.setQueryData([...PANEL_APP_QUERY_KEY, opened.appId], opened);
55
57
  return opened;
56
58
  },
57
59
  enabled: Boolean(entry && state === "allowed"),
@@ -9,6 +9,7 @@ import type {
9
9
  import { t } from '@/shared/lib/i18n';
10
10
 
11
11
  export const PANEL_APPS_QUERY_KEY = ['panel-apps'] as const;
12
+ export const PANEL_APP_QUERY_KEY = ['panel-app'] as const;
12
13
 
13
14
  type PanelAppPreferencesMutation = {
14
15
  id: string;
@@ -75,6 +76,15 @@ export function usePanelApps(options: { enabled?: boolean } = {}) {
75
76
  });
76
77
  }
77
78
 
79
+ export function usePanelApp(id: string, options: { enabled?: boolean } = {}) {
80
+ return useQuery({
81
+ queryKey: [...PANEL_APP_QUERY_KEY, id],
82
+ queryFn: () => nextclawClient.panelApps.getPanelApp(id),
83
+ enabled: Boolean(id) && (options.enabled ?? true),
84
+ staleTime: 5_000,
85
+ });
86
+ }
87
+
78
88
  export function useUpdatePanelAppPreferences() {
79
89
  const queryClient = useQueryClient();
80
90
  return useMutation({
@@ -96,6 +106,7 @@ export function useUpdatePanelAppPreferences() {
96
106
  PANEL_APPS_QUERY_KEY,
97
107
  (current) => replacePanelAppListEntry(current, entry),
98
108
  );
109
+ queryClient.setQueryData([...PANEL_APP_QUERY_KEY, entry.appId], entry);
99
110
  },
100
111
  onError: (error, mutation, context) => {
101
112
  const previousEntry = context?.previousEntry;
@@ -124,6 +135,7 @@ export function useRecordPanelAppOpened() {
124
135
  PANEL_APPS_QUERY_KEY,
125
136
  (current) => replacePanelAppListEntry(current, entry),
126
137
  );
138
+ queryClient.setQueryData([...PANEL_APP_QUERY_KEY, entry.appId], entry);
127
139
  },
128
140
  });
129
141
  }
@@ -134,6 +146,7 @@ export function useGrantPanelAppClient() {
134
146
  mutationFn: (appId: string) => nextclawClient.panelApps.grantClient(appId),
135
147
  onSuccess: () => {
136
148
  void queryClient.invalidateQueries({ queryKey: PANEL_APPS_QUERY_KEY });
149
+ void queryClient.invalidateQueries({ queryKey: PANEL_APP_QUERY_KEY });
137
150
  },
138
151
  });
139
152
  }
@@ -144,6 +157,7 @@ export function useDeletePanelApp() {
144
157
  mutationFn: (id: string) => nextclawClient.panelApps.deletePanelApp(id),
145
158
  onSuccess: () => {
146
159
  void queryClient.invalidateQueries({ queryKey: PANEL_APPS_QUERY_KEY });
160
+ void queryClient.invalidateQueries({ queryKey: PANEL_APP_QUERY_KEY });
147
161
  },
148
162
  });
149
163
  }
@@ -1,7 +1,12 @@
1
1
  export { PanelAppsList } from './components/panel-apps-list';
2
2
  export { PanelAppMainSidebarNav } from './components/panel-app-main-sidebar-nav';
3
3
  export { PanelAppMainPage } from './pages/panel-app-main-page';
4
+ export { PanelAppStandalonePage } from './pages/panel-app-standalone-page';
5
+ export { PanelAppServiceActionAuthorizationDialog } from './components/panel-app-service-action-authorization-dialog';
6
+ export { PanelAppHostPresenter } from './presenters/panel-app-host.presenter';
7
+ export { PanelAppHostProvider } from './providers/panel-app-host.provider';
4
8
  export {
9
+ usePanelApp,
5
10
  useGrantPanelAppClient,
6
11
  usePanelApps,
7
12
  useRecordPanelAppOpened,