@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.
- package/CHANGELOG.md +18 -0
- package/dist/.vite/manifest.json +2477 -0
- package/dist/assets/{abnfDiagram-VRR7QNED-BcFJp_1X.js → abnfDiagram-VRR7QNED-Kzlh3ZEC.js} +1 -1
- package/dist/assets/account-panel-BxMlLXYH.js +1 -0
- package/dist/assets/{aiden0z-pptx-renderer.es-Dp2ezlQn.js → aiden0z-pptx-renderer.es-k1xZLzeo.js} +1 -1
- package/dist/assets/api-Utt-xzrT.js +13 -0
- package/dist/assets/app-data-DYXDL6X2.js +1 -0
- package/dist/assets/app-presenter-provider-CLsFiXvV.js +109 -0
- package/dist/assets/app-presenter-provider-D3BuuOyZ.css +1 -0
- package/dist/assets/appearance-settings-page-BfYznAK5.js +1 -0
- package/dist/assets/{arc-CkgyPMyW.js → arc-CpivM836.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-CVRF_cYQ.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-CMd4cIjI.js → architectureDiagram-ZJ3FMSHR-ifjW1qjI.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-Bz3tbhet.js → blockDiagram-677ZJIJ3-C_zeJrKF.js} +1 -1
- package/dist/assets/{book-open-o2x7OLiO.js → book-open-DDW_3XpM.js} +1 -1
- package/dist/assets/boxes-DwJeuK_h.js +1 -0
- package/dist/assets/{c4Diagram-LMCZKHZV-D9hFNAGv.js → c4Diagram-LMCZKHZV-CpapRftp.js} +1 -1
- package/dist/assets/card-IevY2nm-.js +1 -0
- package/dist/assets/channel-CBrWRr4N.js +1 -0
- package/dist/assets/channels-list-page-DitnqbMR.js +8 -0
- package/dist/assets/chevron-down-An7Km-t4.js +1 -0
- package/dist/assets/chunk-2Q5K7J3B-B8mmRk7d.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-7NrjEITq.js → chunk-32BRIVSS-BKBwdmKR.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-viIcqj9q.js → chunk-52WLFC77-BgZRCpDx.js} +1 -1
- package/dist/assets/{chunk-5FCAYU7R-Vsu4J-VM.js → chunk-5FCAYU7R-YWfOINJi.js} +1 -1
- package/dist/assets/{chunk-5HE753X5-C-w6CQZK.js → chunk-5HE753X5-BZ6I07d2.js} +1 -1
- package/dist/assets/{chunk-5JV3BV7I-CuKgJQ4W.js → chunk-5JV3BV7I-B7QYgZU5.js} +1 -1
- package/dist/assets/{chunk-5TONJI2A-CYeiWZKb.js → chunk-5TONJI2A-DjyQwgL2.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-DRCbfwIn.js → chunk-5VM5RSS4-DheHV7X2.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-BvydOcm3.js → chunk-7BUUIJ7U-D6bq2PKF.js} +1 -1
- package/dist/assets/{chunk-BIQX33UG-RlppOXKo.js → chunk-BIQX33UG-CL9x0ibm.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-DAizzYwr.js → chunk-C7G6YPKG-8z3B6RUH.js} +1 -1
- package/dist/assets/{chunk-CQNSW5MT-5eChJHca.js → chunk-CQNSW5MT-DpHkxY3n.js} +1 -1
- package/dist/assets/{chunk-CYSBUYHQ-YHPr53fv.js → chunk-CYSBUYHQ-DIJDLsdJ.js} +1 -1
- package/dist/assets/{chunk-EMLP6XTP-CK4D7Hz5.js → chunk-EMLP6XTP-B-LjAyVd.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-BmlDFIRW.js → chunk-EX3LRPZG-BChuEPvO.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-D0ksHZZ9.js → chunk-FWX5IMBZ-fBFt0u3f.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-DPkq8FCm.js → chunk-HOUHSVGY-MD0SpW5A.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-FAatv5fC.js → chunk-ICXQ74PX-DvCcw_hz.js} +1 -1
- package/dist/assets/{chunk-JG7HCLWE-DLkIi4F7.js → chunk-JG7HCLWE-B8zqBnU9.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-DawOjNE3.js → chunk-JWPE2WC7-C9efnkGb.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-Di52TorW.js → chunk-MOJQB5TN-gXbfqoqq.js} +1 -1
- package/dist/assets/{chunk-MOZMSUNE-PfyK9w1-.js → chunk-MOZMSUNE-twIwdkqC.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-C3jdH3Ty.js → chunk-OGEWGWER-DdR0_cWK.js} +1 -1
- package/dist/assets/{chunk-OSBZ3O6U-CecHo-f0.js → chunk-OSBZ3O6U-D7D58Foa.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-f3IJh3sN.js → chunk-PUDLZKDR-DPILgOVY.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-DQFeUPxZ.js → chunk-Q4XR5HBZ-C0JJx7lW.js} +1 -1
- package/dist/assets/{chunk-QBLGF6JB-BhUeG0y2.js → chunk-QBLGF6JB-Dbsf69ng.js} +1 -1
- package/dist/assets/{chunk-R7FJI6CG-C3XpZ-2u.js → chunk-R7FJI6CG-Bb8n616-.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-CAqa5klQ.js → chunk-RYQCIY6F-1HOsOrSl.js} +1 -1
- package/dist/assets/{chunk-U6XO7XAA-D_WXezeD.js → chunk-U6XO7XAA-BAFDVb1v.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-CZ70oOtp.js → chunk-V7JOEXUC-8-g68lu5.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-Cpml0inz.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-B7AHEYYk.js → chunk-VR4S4FIN-P6UGmaYd.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-Dn9To_OI.js → chunk-WYO6CB5R-6wjFTXNP.js} +2 -2
- package/dist/assets/chunk-XXDRQBXY-nCiqnCpF.js +1 -0
- package/dist/assets/{chunk-YOTPTUD7-BYEgRBk3.js → chunk-YOTPTUD7-CLYXVZAi.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-C6YtZDU0.js → chunk-ZGVPDNZ5-BRTmSAhp.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-DMuYtnHF.js → chunk-ZIRB5QZD-CH_1eoSV.js} +1 -1
- package/dist/assets/circle-alert-CDXqELuo.js +1 -0
- package/dist/assets/circle-dashed-CapXEpiV.js +1 -0
- package/dist/assets/classDiagram-OUVF2IWQ-C-DRqAaW.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-DXCcZ42U.js +1 -0
- package/dist/assets/client-B0krol7A.js +1 -0
- package/dist/assets/config-split-page-BtnkqWVp.js +1 -0
- package/dist/assets/confirm-dialog-DFt4jpN7.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-Bc2Ex5Y3.js → cose-bilkent-JH36ORCC-L7w_qScX.js} +1 -1
- package/dist/assets/{createLucideIcon-rwwpqyks.js → createLucideIcon-BTHK0Ot9.js} +1 -1
- package/dist/assets/cynefin-VYW2F7L2-2SOTgxxC.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-DVysQoGz.js → cynefinDiagram-TSTJHNR4-Bay7uDSR.js} +1 -1
- package/dist/assets/{dagre-CMhQ1cAG.js → dagre-CJ_hX8xv.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-RYyWpPJZ.js → dagre-VKFMJZFB-DDhk-2B3.js} +1 -1
- package/dist/assets/desktop-capabilities-page-CCf14WId.js +1 -0
- package/dist/assets/desktop-update-config-DVoVgfFi.js +1 -0
- package/dist/assets/{diagram-FQU43EPY-BD6KONdF.js → diagram-FQU43EPY-somFq5y8.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-CGB2ptRR.js → diagram-G47NLZAW-hzgyQsPd.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-DnkOI6cU.js → diagram-NH7WQ7WH-BkJ4gEQJ.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-DF82RZ7P.js → diagram-OA4YK3LP-CS3ZkK4w.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-Be2v7Ck9.js → diagram-WEI45ONY-BApo-JHS.js} +1 -1
- package/dist/assets/dialog-BFN_1DBH.js +5 -0
- package/dist/assets/dist-Bc9hOVNN.js +1 -0
- package/dist/assets/dist-CEhIDAnr.js +1 -0
- package/dist/assets/{dist--ta5rX12.js → dist-Cnhwure9.js} +1 -1
- package/dist/assets/{dist-aNN3iQxV.js → dist-hkVPP1th.js} +1 -1
- package/dist/assets/doc-browser-BNUxmwD6.js +1 -0
- package/dist/assets/doc-browser-context-C4yQrKrH.js +1 -0
- package/dist/assets/doc-browser-w4eGZXLu.js +1 -0
- package/dist/assets/{docx-preview-BqwAjrj3.js → docx-preview-ByCKKIVT.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-CP98OYk8.js → ebnfDiagram-CCIWWBDH-DWjfeEie.js} +1 -1
- package/dist/assets/ellipsis-BRI6ROeu.js +1 -0
- package/dist/assets/{erDiagram-Q63AITRT-ZLlx8xfs.js → erDiagram-Q63AITRT-DR7vWYHM.js} +1 -1
- package/dist/assets/es2015-MOCbM0Eu.js +41 -0
- package/dist/assets/eventmodeling-45OFAUF4-CXZNG56U.js +1 -0
- package/dist/assets/extensions-DxUBMtHW.js +1 -0
- package/dist/assets/eye-cnynUDGt.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-2065oyKr.js +1 -0
- package/dist/assets/form-actions-gQ0JEUwB.js +1 -0
- package/dist/assets/{ganttDiagram-NO4QXBWP-DXCDjHR2.js → ganttDiagram-NO4QXBWP-E3l9tuaL.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-B0Ln3ZuK.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-l2HWrTJp.js → gitGraphDiagram-IHSO6WYX-DiMvbHKf.js} +1 -1
- package/dist/assets/i18n-B9yXA8KO.js +2 -0
- package/dist/assets/i18n-provider-BYBJua91.js +1 -0
- package/dist/assets/info-DKCQHKI2-B06uqGM4.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-D-DjX-bn.js → infoDiagram-FWYZ7A6U-BZDL0NDJ.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-y_Xy128F.js → ishikawaDiagram-FXEZZL3T-BZ9WvJb2.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-DJn5xYcQ.js → journeyDiagram-5HDEW3XC-C3TZvKM8.js} +1 -1
- package/dist/assets/{jszip.min-8hyJpgpx.js → jszip.min-D_AtKL_8.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-DJVIOR21.js → kanban-definition-HUTT4EX6-9FqauDEi.js} +1 -1
- package/dist/assets/{line-Cos7PIOj.js → line-Ca49mj80.js} +1 -1
- package/dist/assets/{linear-BtDLqtzF.js → linear-DlCeG66S.js} +1 -1
- package/dist/assets/loader-circle-rWr5Yo0E.js +1 -0
- package/dist/assets/login-page-CfMSkOsg.js +1 -0
- package/dist/assets/login-page-CqrHhzaN.js +1 -0
- package/dist/assets/logo-badge-Cr03YceJ.js +1 -0
- package/dist/assets/main-8cVkMfgE.css +1 -0
- package/dist/assets/main-Bys58GxY.js +2 -0
- package/dist/assets/main-i18n-catalog.config-BSq9yiUQ.js +1 -0
- package/dist/assets/{map-BKnQyvd0.js → map-WMnNq9UV.js} +1 -1
- package/dist/assets/mcp-marketplace-page-CifiVgFD.js +10 -0
- package/dist/assets/mcp-marketplace-page-DX5VE3mU.js +1 -0
- package/dist/assets/{mermaid-parser.core-XUNZhr2W.js → mermaid-parser.core-B8xk4hpS.js} +2 -2
- package/dist/assets/{mermaid.core-ySrvolIe.js → mermaid.core-CFPiczKH.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-BypL9tei.js → mindmap-definition-LN4V7U3C-CnxA52L6.js} +1 -1
- package/dist/assets/model-config-page-C6jVNbSj.js +1 -0
- package/dist/assets/{navigation-link-C_6oj3zz.js → navigation-link-kbCLRSr_.js} +1 -1
- package/dist/assets/{ordinal-CxxVWxYU.js → ordinal-PgiFlfBJ.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-CHx-igbz.js +1 -0
- package/dist/assets/panel-app-BUUle0gP.js +1 -0
- package/dist/assets/panel-app-i18n-catalog.config-C2St67SP.js +1 -0
- package/dist/assets/panelStandalone-DMBnYyTw.js +2 -0
- package/dist/assets/panelStandalone-Y91OJkgV.css +1 -0
- package/dist/assets/{pegDiagram-2B236MQR-D-U2KBGv.js → pegDiagram-2B236MQR-A8oz7dTH.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-DOaMc-x9.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-CBi3GusJ.js → pieDiagram-ENE6RG2P-mtBnkYY0.js} +1 -1
- package/dist/assets/plus-BHnKwuPq.js +1 -0
- package/dist/assets/popover-XVDgjxcl.js +1 -0
- package/dist/assets/privacy-settings-page-BN27MBVA.js +1 -0
- package/dist/assets/projects-DV3UuJMS.js +1 -0
- package/dist/assets/provider-models-5PGHb6mP.js +1 -0
- package/dist/assets/provider-scoped-model-input-BGZMCThn.js +1 -0
- package/dist/assets/providers-config-page-D5aBwbOD.js +1 -0
- package/dist/assets/puzzle-D5Dhacmb.js +1 -0
- package/dist/assets/pwa-ClQK56Qe.js +1 -0
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-H0ZuvnZL.js → quadrantDiagram-ABIIQ3AL-DE1VybGO.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-CXsdndDk.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-DxgXdrYP.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-CR1tnyjz.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-CjjxZR2U.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-DgVGJCHN.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-D7Y2EqSd.js → railroadDiagram-RFXS5EU6-u9EMg14B.js} +1 -1
- package/dist/assets/{refresh-cw-DsT2kvXi.js → refresh-cw-Bw5BY7vp.js} +1 -1
- package/dist/assets/remote-Bl005fzu.js +1 -0
- package/dist/assets/{requirementDiagram-TGXJPOKE-BiXNX1NN.js → requirementDiagram-TGXJPOKE-BAWHAqEi.js} +1 -1
- package/dist/assets/{rotate-cw-BCAs6c3R.js → rotate-cw-BksCLAeE.js} +1 -1
- package/dist/assets/runtime-config-page-CmktQcMW.js +1 -0
- package/dist/assets/{sankeyDiagram-HTMAVEWB-qzDeLztW.js → sankeyDiagram-HTMAVEWB-aDy-jdwF.js} +1 -1
- package/dist/assets/{save-CadRMTMQ.js → save-CVi8VWzb.js} +1 -1
- package/dist/assets/{search-B6tB4fzB.js → search-DN-f7IIC.js} +1 -1
- package/dist/assets/search-config-page-BmuZTVxs.js +1 -0
- package/dist/assets/secrets-config-page-NPHpg9sb.js +3 -0
- package/dist/assets/security-config-Djptuyf2.js +1 -0
- package/dist/assets/select-CmDTqk2C.js +1 -0
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-BtRbPQtL.js → sequenceDiagram-DBY2YBRQ-DwHC4mbX.js} +1 -1
- package/dist/assets/service-apps-panel-BYGJ9_pO.js +1 -0
- package/dist/assets/settings-2-B62YtZon.js +1 -0
- package/dist/assets/{sizeCapture-X5ZJPWSS-CMYvM3SL.js → sizeCapture-X5ZJPWSS-oOMY0Fag.js} +1 -1
- package/dist/assets/skeleton-Eh64l4T2.js +1 -0
- package/dist/assets/{src-Bw-mzbQb.js → src-CLPoo5iL.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-BJ-mFeOz.js → stateDiagram-2N3HPSRC-B0Epk-VR.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-Ct4zTw8P.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-BsucVOO2.js → swimlanes-5IMT3BWC-T0w-Iuzf.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-CdmN0PBd.js +8 -0
- package/dist/assets/tabs-Bk_mG7ql.js +1 -0
- package/dist/assets/{tag-chip-BZKk0UkK.js → tag-chip-DgqKlI5D.js} +1 -1
- package/dist/assets/theme-provider-CeBY2pyu.js +1 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-Bicewlzo.js → timeline-definition-FHXFAJF6-BEonB5Np.js} +1 -1
- package/dist/assets/tooltip-CgGbBdYf.js +1 -0
- package/dist/assets/trash-2-CVOev8yc.js +1 -0
- package/dist/assets/treeView-QDETBFTQ-Dad4_Wc7.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-9_GWWZsY.js +1 -0
- package/dist/assets/use-config-b2DN67gs.js +1 -0
- package/dist/assets/use-desktop-capabilities-B3tLU1yl.js +1 -0
- package/dist/assets/use-panel-app-scroll-restoration-BekzoX6z.js +1 -0
- package/dist/assets/use-viewport-layout-CUA3jQsA.js +1 -0
- package/dist/assets/utils-UBHTdG5Q.js +8 -0
- package/dist/assets/{vennDiagram-L72KCM5P-BxOOnO9x.js → vennDiagram-L72KCM5P-BDvcOCo2.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-BXpvyee9.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-Cl7NltMv.js → wardleyDiagram-EHGQE667-jMLMgjzE.js} +1 -1
- package/dist/assets/x-C0iaOsRW.js +1 -0
- package/dist/assets/{xychartDiagram-FW5EYKEG-DiMIxQ7N.js → xychartDiagram-FW5EYKEG-pzrpclEv.js} +1 -1
- package/dist/index.html +56 -25
- package/dist/panel-standalone.html +30 -0
- package/package.json +3 -3
- package/panel-standalone.html +13 -0
- package/panel-standalone.tailwind.config.js +16 -0
- package/src/app/components/app-presenter-provider.tsx +8 -1
- package/src/app/components/theme-provider.tsx +0 -5
- package/src/app/index.tsx +18 -4
- package/src/app/presenters/app.presenter.ts +4 -4
- package/src/app/styles/panel-app-standalone.css +31 -0
- package/src/app/test/vitest-setup.ts +3 -0
- package/src/features/account/hooks/use-auth.ts +7 -57
- package/src/features/account/index.ts +3 -2
- package/src/features/apps/components/__tests__/apps-panel.test.tsx +7 -5
- package/src/features/apps/components/apps-panel.tsx +9 -3
- package/src/features/chat/features/session/utils/__tests__/chat-sidebar-session-groups.utils.test.ts +27 -2
- package/src/features/chat/features/session/utils/chat-sidebar-session-groups.utils.ts +0 -11
- package/src/features/panel-apps/components/__tests__/panel-app-list-item.test.tsx +18 -0
- package/src/features/panel-apps/components/__tests__/panel-app-open-standalone-menu-item.test.tsx +56 -0
- package/src/features/panel-apps/components/__tests__/panel-app-toolbar.test.tsx +15 -0
- package/src/features/panel-apps/components/panel-app-list-item.tsx +5 -0
- package/src/features/panel-apps/components/panel-app-open-standalone-menu-item.tsx +29 -0
- package/src/features/panel-apps/components/panel-app-runtime-surface.tsx +141 -0
- package/src/features/{service-apps/components/service-action-authorization-dialog.tsx → panel-apps/components/panel-app-service-action-authorization-dialog.tsx} +4 -4
- package/src/features/panel-apps/components/panel-app-toolbar.tsx +5 -0
- package/src/features/panel-apps/hooks/use-panel-app-client-grant.ts +2 -2
- package/src/features/panel-apps/hooks/{use-panel-app-main-runtime.ts → use-panel-app-runtime.ts} +7 -5
- package/src/features/panel-apps/hooks/use-panel-apps.ts +14 -0
- package/src/features/panel-apps/index.ts +5 -0
- package/src/features/panel-apps/managers/__tests__/panel-app-bridge.manager.test.ts +2 -2
- package/src/features/panel-apps/managers/panel-app-bridge.manager.ts +2 -2
- package/src/features/panel-apps/managers/panel-app-service-action-authorization.manager.ts +10 -0
- package/src/features/panel-apps/pages/__tests__/panel-app-main-page.test.tsx +12 -3
- package/src/features/panel-apps/pages/__tests__/panel-app-standalone-page.test.tsx +63 -0
- package/src/features/panel-apps/pages/panel-app-main-page.tsx +9 -121
- package/src/features/panel-apps/pages/panel-app-standalone-page.tsx +29 -0
- package/src/features/panel-apps/presenters/panel-app-host.presenter.ts +9 -0
- package/src/features/panel-apps/providers/panel-app-host.provider.tsx +45 -0
- package/src/features/panel-apps/routes/__tests__/panel-app-standalone.route.test.tsx +50 -0
- package/src/features/panel-apps/routes/panel-app-standalone.route.tsx +94 -0
- package/src/features/{service-apps/stores/service-action-authorization.store.ts → panel-apps/stores/panel-app-service-action-authorization.store.ts} +6 -6
- package/src/features/projects/components/project-overview.test.tsx +70 -0
- package/src/features/projects/components/project-overview.tsx +114 -56
- package/src/features/projects/components/work/project-work-item-drawer.tsx +8 -10
- package/src/features/projects/components/work/project-work-items.test.tsx +168 -4
- package/src/features/projects/components/work/project-work-items.tsx +277 -49
- package/src/features/projects/components/work/project-work-state-settings.tsx +7 -3
- package/src/features/projects/hooks/use-project-work.test.tsx +108 -6
- package/src/features/projects/hooks/use-project-work.ts +82 -9
- package/src/features/projects/pages/project-home-page.tsx +45 -6
- package/src/features/projects/pages/projects-page.test.tsx +56 -0
- package/src/features/projects/utils/project-artifact-view.utils.test.ts +30 -18
- package/src/features/projects/utils/project-artifact-view.utils.ts +29 -12
- package/src/features/projects/utils/project-work-state-label.utils.test.ts +28 -0
- package/src/features/projects/utils/project-work-state-label.utils.ts +20 -0
- package/src/features/service-apps/index.ts +3 -3
- package/src/main.tsx +3 -0
- package/src/shared/hooks/use-auth-status.ts +49 -0
- package/src/shared/hooks/use-projects.ts +15 -1
- package/src/shared/lib/api/projects/project.utils.ts +4 -0
- package/src/shared/lib/i18n/configs/main-i18n-catalog.config.ts +78 -0
- package/src/shared/lib/i18n/configs/panel-app-i18n-catalog.config.ts +12 -0
- package/src/shared/lib/i18n/index.ts +30 -82
- package/src/shared/lib/i18n/locales/en-US/doc-browser.json +0 -55
- package/src/shared/lib/i18n/locales/en-US/panel-app.json +59 -0
- package/src/shared/lib/i18n/locales/en-US/projects.json +16 -0
- package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +0 -55
- package/src/shared/lib/i18n/locales/zh-CN/panel-app.json +59 -0
- package/src/shared/lib/i18n/locales/zh-CN/projects.json +16 -0
- package/vite.config.ts +36 -1
- package/dist/assets/api-BqVIq0lF.js +0 -13
- package/dist/assets/appearance-settings-page-CTWn1eAT.js +0 -1
- package/dist/assets/architecture-TIHT7OUA-DO2x53FK.js +0 -1
- package/dist/assets/channel-nBvMaVyP.js +0 -1
- package/dist/assets/channels-list-page-Bzn-pzyJ.js +0 -8
- package/dist/assets/chunk-2Q5K7J3B-CJgqFDS4.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-BGvh3yIx.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-DaBxG5gs.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-P6N03G2R.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-B1_uLvMv.js +0 -1
- package/dist/assets/config-split-page-CnRbXXlh.js +0 -1
- package/dist/assets/confirm-dialog-B_Hbcra2.js +0 -5
- package/dist/assets/cynefin-VYW2F7L2-B-H8Qp-n.js +0 -1
- package/dist/assets/desktop-capabilities-page-C2ayYQTr.js +0 -1
- package/dist/assets/desktop-update-config-C13czpyL.js +0 -1
- package/dist/assets/dist-BsF3hfOi.js +0 -1
- package/dist/assets/doc-browser-D8dIOo9E.js +0 -1
- package/dist/assets/doc-browser-DcuOOtpP.js +0 -1
- package/dist/assets/doc-browser-context-Dhsit2Ma.js +0 -1
- package/dist/assets/eventmodeling-45OFAUF4-YVtShyFA.js +0 -1
- package/dist/assets/extensions-CD6xvKF_.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-BeKXabVO.js +0 -1
- package/dist/assets/form-actions-CC4Wz_lL.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-jTSiBj-p.js +0 -1
- package/dist/assets/index-BTsbdtv6.js +0 -109
- package/dist/assets/index-Bcfy2kTh.css +0 -1
- package/dist/assets/info-DKCQHKI2-BIporNWb.js +0 -1
- package/dist/assets/loader-circle-B6aFbB-8.js +0 -1
- package/dist/assets/mcp-marketplace-page-BtUAypA7.js +0 -1
- package/dist/assets/mcp-marketplace-page-r2MmD9xO.js +0 -10
- package/dist/assets/model-config-page-DboxoT-I.js +0 -1
- package/dist/assets/packet-7NZHBO7P-CuFMADV0.js +0 -1
- package/dist/assets/pie-RZYD4A2V-XUeIXhM9.js +0 -1
- package/dist/assets/plus-DRsq9Kvs.js +0 -1
- package/dist/assets/privacy-settings-page-C2sDBqhb.js +0 -1
- package/dist/assets/projects-BcPcx-uD.js +0 -1
- package/dist/assets/providers-config-page-CmUFl9RF.js +0 -1
- package/dist/assets/radar-I7S5WNFK-D-NNGh1k.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-C67_uDaM.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-BZ8Yflnd.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-B7zO7RoK.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-R63PTgLz.js +0 -1
- package/dist/assets/react-BjO9I4WZ.js +0 -8
- package/dist/assets/remote-Ci6x91ES.js +0 -1
- package/dist/assets/runtime-config-page-cQKNeAjL.js +0 -1
- package/dist/assets/search-config-page-C8lOIkxn.js +0 -1
- package/dist/assets/secrets-config-page-8clzAag2.js +0 -3
- package/dist/assets/security-config-DPbM6IVT.js +0 -1
- package/dist/assets/select-CO9S_C2C.js +0 -41
- package/dist/assets/skeleton-IHILNhIW.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-BE-HqxOK.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-Dr1H9LJH.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-npJ5dbqS.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-pYrBx6oa.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-CmSRKLR8.js +0 -1
- package/dist/assets/x-BuvHIb1d.js +0 -1
- package/src/features/service-apps/managers/service-action-authorization.manager.ts +0 -10
- /package/dist/assets/{array-BQVzeGRt.js → array-BHDgItFN.js} +0 -0
- /package/dist/assets/{chunk-DseTPa7n.js → chunk-DF37yw5_.js} +0 -0
- /package/dist/assets/{chunk-KEIR6QF5-f9psyCXK.js → chunk-KEIR6QF5-DstBw0Hk.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-D1mAU_Po.js → chunk-Y2CYZVJY-CA3ymQuH.js} +0 -0
- /package/dist/assets/{config-hints-nV5HPOvq.js → config-hints-CBPHrfYk.js} +0 -0
- /package/dist/assets/{cytoscape.esm-0uDtdD0l.js → cytoscape.esm-C7xr90o_.js} +0 -0
- /package/dist/assets/{defaultLocale-DSWXGgt0.js → defaultLocale-BG1oDVag.js} +0 -0
- /package/dist/assets/{graphlib-CQ6QV4yP.js → graphlib-CNMGfuTb.js} +0 -0
- /package/dist/assets/{host-capabilities-Tk038i04.js → host-capabilities-B107nwS3.js} +0 -0
- /package/dist/assets/{init-Y6h9jGtZ.js → init-wQIZuRSH.js} +0 -0
- /package/dist/assets/{katex-ARhY9PS1.js → katex-J8JuvgNl.js} +0 -0
- /package/dist/assets/{middleware-DXsbf9xI.js → middleware-0o3JF3tS.js} +0 -0
- /package/dist/assets/{path-10BjdyLh.js → path-N-C4MRP0.js} +0 -0
- /package/dist/assets/{preload-helper-D4M6sveU.js → preload-helper-ca-nBW7U.js} +0 -0
- /package/dist/assets/{rough.esm-DxgC_14r.js → rough.esm-BeWA068d.js} +0 -0
- /package/dist/assets/{xlsx-DrDuDNAa.js → xlsx-CwUXNtD3.js} +0 -0
|
@@ -1,69 +1,19 @@
|
|
|
1
|
-
import { useMutation,
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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 {
|
|
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
|
-
<
|
|
61
|
+
<Suspense fallback={null}>
|
|
62
|
+
<ServiceAppsPanel onManagePackage={managePackage} />
|
|
63
|
+
</Suspense>
|
|
58
64
|
)}
|
|
59
65
|
</div>
|
|
60
66
|
</div>
|
package/src/features/chat/features/session/utils/__tests__/chat-sidebar-session-groups.utils.test.ts
CHANGED
|
@@ -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
|
});
|
package/src/features/panel-apps/components/__tests__/panel-app-open-standalone-menu-item.test.tsx
ADDED
|
@@ -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 {
|
|
12
|
+
import { usePanelAppServiceActionAuthorizationStore } from '@/features/panel-apps/stores/panel-app-service-action-authorization.store';
|
|
13
13
|
|
|
14
|
-
export function
|
|
15
|
-
const pending =
|
|
16
|
-
const resolveAuthorization =
|
|
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 {
|
|
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 =
|
|
8
|
+
const presenter = usePanelAppHostPresenter();
|
|
9
9
|
const { isPending, mutateAsync: grantPanelAppClient } = useGrantPanelAppClient();
|
|
10
10
|
const pendingGrantsRef = useRef(new Map<string, Promise<boolean>>());
|
|
11
11
|
|
package/src/features/panel-apps/hooks/{use-panel-app-main-runtime.ts → use-panel-app-runtime.ts}
RENAMED
|
@@ -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
|
|
15
|
+
export type PanelAppRuntimeState = "allowed" | "checking" | "denied" | "error" | "idle";
|
|
15
16
|
|
|
16
|
-
export function
|
|
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-
|
|
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:
|
|
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-
|
|
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,
|