@nextclaw/ui 0.26.0 → 0.26.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 +40 -0
- package/dist/.vite/manifest.json +1143 -1133
- package/dist/assets/{abnfDiagram-VRR7QNED-Bjrmb5-o.js → abnfDiagram-VRR7QNED-Dcw10Yt1.js} +1 -1
- package/dist/assets/{account-panel-C1S3xtUB.js → account-panel-ZM2qzKF4.js} +1 -1
- package/dist/assets/{aiden0z-pptx-renderer.es-DO4DCX3e.js → aiden0z-pptx-renderer.es--oNqetPA.js} +1 -1
- package/dist/assets/api-Cjq-o1VN.js +20 -0
- package/dist/assets/app-presenter-provider-C02YPoMr.js +124 -0
- package/dist/assets/{appearance-settings-page-BljTr6nB.js → appearance-settings-page-B4zouKzg.js} +1 -1
- package/dist/assets/{arc-g4XaP3S4.js → arc-DBRedCax.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-CvnC-LeA.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-CAP7YDux.js → architectureDiagram-ZJ3FMSHR-Dufhtuv-.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-DhaP0zUG.js → blockDiagram-677ZJIJ3-BUk0vtJ7.js} +1 -1
- package/dist/assets/{book-open-vxpV2eSM.js → book-open-AteA89HX.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-DHCQJJkD.js → c4Diagram-LMCZKHZV-CxDcVE9p.js} +1 -1
- package/dist/assets/{card-D9NYhSdf.js → card-BLXvBstA.js} +1 -1
- package/dist/assets/channel-CpMstUPF.js +1 -0
- package/dist/assets/{channels-list-page-BiHA1zZd.js → channels-list-page-fj8kMo-T.js} +1 -1
- package/dist/assets/chunk-2Q5K7J3B-Djp3VF0s.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-BcQlxl4v.js → chunk-32BRIVSS-DSF3KElA.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-ClPpG-2S.js → chunk-52WLFC77-Costxzr3.js} +1 -1
- package/dist/assets/{chunk-5FCAYU7R-B_qmYOdX.js → chunk-5FCAYU7R-rhqzGGZo.js} +1 -1
- package/dist/assets/{chunk-5HE753X5-DTO-V56q.js → chunk-5HE753X5-BsEsmIao.js} +1 -1
- package/dist/assets/{chunk-5JV3BV7I-CU1SOaaG.js → chunk-5JV3BV7I-Dqw_DCoN.js} +1 -1
- package/dist/assets/{chunk-5TONJI2A-CzSDkWNa.js → chunk-5TONJI2A-Cft82fp8.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-ChkfqIRE.js → chunk-5VM5RSS4-DqNHn9Dl.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-Du3Ozi62.js → chunk-7BUUIJ7U-A5SBEMYY.js} +1 -1
- package/dist/assets/{chunk-BIQX33UG-C-HVafHB.js → chunk-BIQX33UG-1Ng3mTrH.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-BSjZ86D0.js → chunk-C7G6YPKG-DRJEy8ZI.js} +1 -1
- package/dist/assets/{chunk-CQNSW5MT-1D1W2lF6.js → chunk-CQNSW5MT-Bydv_J3J.js} +1 -1
- package/dist/assets/{chunk-CYSBUYHQ-ISpyj_lK.js → chunk-CYSBUYHQ-HkMIg12u.js} +1 -1
- package/dist/assets/{chunk-EMLP6XTP-Cp8iUBt2.js → chunk-EMLP6XTP-C5ndDvm3.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-BN5RzF5j.js → chunk-EX3LRPZG-DzeloZRo.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-DecJDW4r.js → chunk-FWX5IMBZ-n_2_CLTQ.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-BE_XNgGk.js → chunk-HOUHSVGY-kx_slvu3.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-BFOKMkWV.js → chunk-ICXQ74PX-sQLMURqL.js} +1 -1
- package/dist/assets/{chunk-JG7HCLWE-DL-pl8VB.js → chunk-JG7HCLWE-CMUn5Elc.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-B-bcwfmh.js → chunk-JWPE2WC7-Cra3s-Uk.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-BC0taFro.js → chunk-MOJQB5TN-umcrg5Bi.js} +1 -1
- package/dist/assets/{chunk-MOZMSUNE-RrhfU6MO.js → chunk-MOZMSUNE-BnljD1ig.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-TuI7SR7i.js → chunk-OGEWGWER-BXx5pQjU.js} +1 -1
- package/dist/assets/{chunk-OSBZ3O6U-C5jMBKlU.js → chunk-OSBZ3O6U-D-1qfdWu.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-C5lMBn0K.js → chunk-PUDLZKDR-DLzX78LC.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-B-kzUbwT.js → chunk-Q4XR5HBZ-DTK-rtW6.js} +1 -1
- package/dist/assets/{chunk-QBLGF6JB-CRb_WAEj.js → chunk-QBLGF6JB-CsFeIGfr.js} +1 -1
- package/dist/assets/{chunk-R7FJI6CG-De6Y7ozO.js → chunk-R7FJI6CG-4xNYUeng.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-Igv92q8k.js → chunk-RYQCIY6F-DJiHiTE5.js} +1 -1
- package/dist/assets/{chunk-U6XO7XAA-bCjRshkT.js → chunk-U6XO7XAA-BVYkauHz.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-0J1s_Kgq.js → chunk-V7JOEXUC-BsazE8cS.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-BrbiIC1Q.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-DX6lXnNx.js → chunk-VR4S4FIN-7RoZQffO.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-DLqMXfFC.js → chunk-WYO6CB5R-DEuS6N1R.js} +1 -1
- package/dist/assets/chunk-XXDRQBXY-Cx9N40wF.js +1 -0
- package/dist/assets/{chunk-YOTPTUD7-CY4obsV0.js → chunk-YOTPTUD7-9KBrosZL.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-BleImZKe.js → chunk-ZGVPDNZ5-IYgN9f5A.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-C1TfdjpX.js → chunk-ZIRB5QZD-BUo0-zcp.js} +1 -1
- package/dist/assets/{circle-dashed-CEEssYIw.js → circle-dashed-LSYZTzM7.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-DFN1v3PQ.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-DRvglADa.js +1 -0
- package/dist/assets/{client-C6YQx7A-.js → client-DudCRJw4.js} +1 -1
- package/dist/assets/{config-split-page-DKPelvjR.js → config-split-page-G7Kt2BnV.js} +1 -1
- package/dist/assets/confirm-dialog-DShT64F6.js +1 -0
- package/dist/assets/context-menu-rd7b_kVD.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-CVgUHXkj.js → cose-bilkent-JH36ORCC-DhqbC1fR.js} +1 -1
- package/dist/assets/{createLucideIcon-CF8U9dh7.js → createLucideIcon-D7hvIHV-.js} +1 -1
- package/dist/assets/cynefin-VYW2F7L2-DXUGnpJH.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-cdfImbfI.js → cynefinDiagram-TSTJHNR4-C-TBRi5V.js} +1 -1
- package/dist/assets/{dagre-CHNN9L9I.js → dagre-CrgsRasE.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-PscaENwr.js → dagre-VKFMJZFB-BmafJymp.js} +1 -1
- package/dist/assets/{desktop-capabilities-page-BENHdKfk.js → desktop-capabilities-page-CzqzFZUY.js} +1 -1
- package/dist/assets/desktop-update-config-CgeQ0Ffo.js +1 -0
- package/dist/assets/{diagram-FQU43EPY-CH_wye41.js → diagram-FQU43EPY-BoOMwa6D.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-Dtjpmi6D.js → diagram-G47NLZAW-Le7N6Uym.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-UdjLHyaz.js → diagram-NH7WQ7WH-Fbpj3-MO.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-DYsToEaL.js → diagram-OA4YK3LP-D3QuGGuu.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-CA7kuIer.js → diagram-WEI45ONY-Cxu1uiN6.js} +1 -1
- package/dist/assets/dialog-C7glmAQJ.js +5 -0
- package/dist/assets/{doc-browser-context-CPLWVFLd.js → doc-browser-context-BlhBAOLH.js} +1 -1
- package/dist/assets/doc-browser-dBiR9Qi0.js +1 -0
- package/dist/assets/{docx-preview-D--EsUWi.js → docx-preview-CkU2psnd.js} +1 -1
- package/dist/assets/download-BYgECE0n.js +1 -0
- package/dist/assets/{ebnfDiagram-CCIWWBDH-BrjaoOuq.js → ebnfDiagram-CCIWWBDH-CCAjuQM6.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-nZQa2kCM.js → erDiagram-Q63AITRT-BuzUAq-d.js} +1 -1
- package/dist/assets/es2015-CsjAAQ6X.js +41 -0
- package/dist/assets/eventmodeling-45OFAUF4-ZBfVS3ZC.js +1 -0
- package/dist/assets/{extensions-CsWT7x3v.js → extensions-qYL-NpL3.js} +1 -1
- package/dist/assets/{eye-DJtw5KJ5.js → eye-BBuTzJ53.js} +1 -1
- package/dist/assets/flowDiagram-23GEKE2U-CqdsKk6x.js +1 -0
- package/dist/assets/{form-actions-DDQk0END.js → form-actions-CLGWO52v.js} +1 -1
- package/dist/assets/{ganttDiagram-NO4QXBWP-CyFZHIHN.js → ganttDiagram-NO4QXBWP-cJmWVY8F.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-fHYFd9Es.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-Dfpq3z2M.js → gitGraphDiagram-IHSO6WYX-F58o-vtP.js} +1 -1
- package/dist/assets/{i18n-BjPkAKMQ.js → i18n-qBGEbcW6.js} +2 -2
- package/dist/assets/info-DKCQHKI2-CSaOL_bb.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-Diiz0k1E.js → infoDiagram-FWYZ7A6U-Gt59b83C.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-B3R3SN4M.js → ishikawaDiagram-FXEZZL3T-1u4IAj1I.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-DFOLKiNv.js → journeyDiagram-5HDEW3XC-CCQsfV-5.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-BMXpDp3g.js → kanban-definition-HUTT4EX6-vlB6O_Zn.js} +1 -1
- package/dist/assets/{keyboard-shortcuts-settings-page-hqTP7akj.js → keyboard-shortcuts-settings-page-B-wK_6zG.js} +1 -1
- package/dist/assets/{line-64_FhCoJ.js → line-D_bHubTL.js} +1 -1
- package/dist/assets/{linear-aF1fg7bK.js → linear-ChlwuS5y.js} +1 -1
- package/dist/assets/loader-circle-BA7EMkih.js +1 -0
- package/dist/assets/{login-page-BUwshAq4.js → login-page-Cd84lpVV.js} +1 -1
- package/dist/assets/login-page-VdMyNkFf.js +1 -0
- package/dist/assets/main-CR0SrTBf.js +2 -0
- package/dist/assets/main-DXH6EdXI.css +1 -0
- package/dist/assets/main-i18n-catalog.config-Btp_OowF.js +1 -0
- package/dist/assets/{map-BC3Amra3.js → map-oGHTsIu8.js} +1 -1
- package/dist/assets/mcp-marketplace-page-jacRwiI-.js +1 -0
- package/dist/assets/{mermaid-parser.core-DdMcZwnE.js → mermaid-parser.core-CuRe1ZG4.js} +2 -2
- package/dist/assets/{mermaid.core-BHdiEBbI.js → mermaid.core-u4YCFKRf.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-CtHVaZyV.js → mindmap-definition-LN4V7U3C-DeJAQYTu.js} +1 -1
- package/dist/assets/{model-config-page-BSsHOhV7.js → model-config-page-D0DQlSDa.js} +1 -1
- package/dist/assets/{navigation-link-D-fxdv0i.js → navigation-link-32iM1-e6.js} +1 -1
- package/dist/assets/{ordinal-6b3jw4cz.js → ordinal-C6JFfkKN.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-D-YFTczs.js +1 -0
- package/dist/assets/panel-app-CC0bVSu4.js +1 -0
- package/dist/assets/panel-app-i18n-catalog.config-LUSBp5Ce.js +1 -0
- package/dist/assets/{panelStandalone-BeI0Ndsx.js → panelStandalone-C9EKaApN.js} +2 -2
- package/dist/assets/{pegDiagram-2B236MQR-BtbG3Bgu.js → pegDiagram-2B236MQR-nVMkxShH.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-VEnYu9s5.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-FmLl2hzN.js → pieDiagram-ENE6RG2P-8aUH44QZ.js} +1 -1
- package/dist/assets/{privacy-settings-page-pW_1naDz.js → privacy-settings-page-Bxxx12OO.js} +1 -1
- package/dist/assets/projects-D56yAPNT.js +1 -0
- package/dist/assets/provider-models-C3frdXeW.js +1 -0
- package/dist/assets/{provider-scoped-model-input-CVbtT8L9.js → provider-scoped-model-input-CYetrPYZ.js} +1 -1
- package/dist/assets/providers-config-page-DESB1h8g.js +1 -0
- package/dist/assets/{puzzle-kKiVft9-.js → puzzle-CWHfFyYN.js} +1 -1
- package/dist/assets/pwa-CiGUjpcd.js +1 -0
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-7-OzMNpF.js → quadrantDiagram-ABIIQ3AL-EY8hpFv8.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-BFNIekC1.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-lVqJ3Hak.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-DYaefdFC.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-CTAk6lVq.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-Cob294tg.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-B_UVtLJO.js → railroadDiagram-RFXS5EU6-CNhcIeji.js} +1 -1
- package/dist/assets/{refresh-cw-BeG0y6yZ.js → refresh-cw-y3L6PyLt.js} +1 -1
- package/dist/assets/remote-DiGFV8nP.js +1 -0
- package/dist/assets/{requirementDiagram-TGXJPOKE-D8TO2YeZ.js → requirementDiagram-TGXJPOKE-D8Dcs-Rt.js} +1 -1
- package/dist/assets/{rotate-cw-Ci2dcTO5.js → rotate-cw-CNE9qSHi.js} +1 -1
- package/dist/assets/{runtime-config-page-DCXN0nkS.js → runtime-config-page-5o98T-TD.js} +1 -1
- package/dist/assets/{sankeyDiagram-HTMAVEWB-CUzIcq0B.js → sankeyDiagram-HTMAVEWB-HTrb6aa-.js} +1 -1
- package/dist/assets/{save-Cr895abt.js → save-B0p5a0ET.js} +1 -1
- package/dist/assets/{search-config-page-CNQd481d.js → search-config-page-CpGcnIzi.js} +1 -1
- package/dist/assets/{secrets-config-page--q7M58L8.js → secrets-config-page-C4VTiW3r.js} +1 -1
- package/dist/assets/security-config-C5-RQVpS.js +1 -0
- package/dist/assets/select-CctTN205.js +1 -0
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-kqJzXbwu.js → sequenceDiagram-DBY2YBRQ-6f_4X16Y.js} +1 -1
- package/dist/assets/service-apps-panel-CKE5HKNY.js +1 -0
- package/dist/assets/{settings-2-IodCcaXd.js → settings-2-EPflrNk6.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-D9ISogq1.js → sizeCapture-X5ZJPWSS-Ck9rsuwL.js} +1 -1
- package/dist/assets/{src-Bc0PoUJ1.js → src-C8AUg09O.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-CqH5xc9W.js → stateDiagram-2N3HPSRC-Cm33MLHu.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-BrNv-raG.js +1 -0
- package/dist/assets/{status-dot-DUYSKRCU.js → status-dot-CensgJZC.js} +1 -1
- package/dist/assets/{swimlanes-5IMT3BWC-mwejV-rW.js → swimlanes-5IMT3BWC-B107vmvM.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-ntcxaPXp.js +8 -0
- package/dist/assets/{tag-chip-CQU51ST3.js → tag-chip-Bjzb4-qW.js} +1 -1
- package/dist/assets/{theme-provider-D-zZkXxS.js → theme-provider-hlle7Skk.js} +1 -1
- package/dist/assets/{timeline-definition-FHXFAJF6-CuikIDlX.js → timeline-definition-FHXFAJF6-CJEoAj33.js} +1 -1
- package/dist/assets/{trash-2-BDdqDh6E.js → trash-2-C5KH5Rw9.js} +1 -1
- package/dist/assets/treeView-QDETBFTQ-DbFmr-gw.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-C8aY96pi.js +1 -0
- package/dist/assets/{use-config-Bxx7DdaL.js → use-config-CPl_F79t.js} +1 -1
- package/dist/assets/use-desktop-capabilities-CEg9-DrQ.js +1 -0
- package/dist/assets/{use-viewport-layout-CDcca0YL.js → use-viewport-layout-CPZUmTPi.js} +1 -1
- package/dist/assets/{vennDiagram-L72KCM5P-BD0P0qHh.js → vennDiagram-L72KCM5P-DzsUHk5I.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-D8d6DbbJ.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-C6ma3t5D.js → wardleyDiagram-EHGQE667-1NfFs5ua.js} +1 -1
- package/dist/assets/x--xxUvHKW.js +1 -0
- package/dist/assets/{xychartDiagram-FW5EYKEG-D7E40NBk.js → xychartDiagram-FW5EYKEG-Ci8AI3Qo.js} +1 -1
- package/dist/index.html +37 -36
- package/dist/panel-standalone.html +11 -11
- package/package.json +8 -8
- package/src/app/components/layout/__tests__/app-layout.test.tsx +0 -1
- package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +36 -16
- package/src/app/components/layout/sidebar-items.tsx +27 -18
- package/src/app/components/layout/sidebar-rail.styles.ts +11 -2
- package/src/app/components/layout/sidebar.tsx +3 -2
- package/src/app/configs/app-navigation.config.ts +39 -86
- package/src/features/agents/components/agent-details-dialog.tsx +3 -3
- package/src/features/agents/components/agents-page.tsx +5 -4
- package/src/features/chat/components/layout/__tests__/chat-page-shell.test.tsx +0 -2
- package/src/features/chat/components/layout/chat-page-shell.tsx +0 -2
- package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +0 -1
- package/src/features/chat/features/conversation/components/chat-voice-input-panel.tsx +3 -2
- package/src/features/chat/features/conversation/hooks/__tests__/use-chat-voice-input.test.tsx +4 -0
- package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +32 -47
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +6 -10
- package/src/features/chat/features/message/utils/__tests__/chat-message-process-summary.utils.test.ts +52 -6
- package/src/features/chat/features/message/utils/chat-message-process-summary.utils.ts +22 -37
- package/src/features/chat/features/session/components/__tests__/chat-sidebar-project-groups.test.tsx +1 -1
- package/src/features/chat/features/session/components/__tests__/chat-sidebar-session-item.test.tsx +2 -1
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +4 -2
- package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +9 -6
- package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +2 -2
- package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +17 -17
- package/src/features/chat/features/session/components/session-header/chat-session-header-menu-item.tsx +4 -4
- package/src/features/chat/features/session/components/session-header/chat-session-more-actions-menu.tsx +13 -6
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +1 -1
- package/src/features/chat/managers/chat-voice-input.manager.ts +5 -3
- package/src/features/chat/utils/chat-voice-permissions.utils.test.ts +12 -1
- package/src/features/chat/utils/chat-voice-permissions.utils.ts +6 -1
- package/src/features/cron/components/cron-job-row.tsx +11 -9
- package/src/features/inbox/components/inbox-reader-dialog.tsx +4 -2
- package/src/features/inbox/pages/inbox-page.tsx +10 -5
- package/src/features/marketplace/components/mcp/mcp-marketplace-card.tsx +1 -1
- package/src/features/panel-apps/components/__tests__/panel-app-list-item.test.tsx +6 -4
- package/src/features/panel-apps/components/__tests__/panel-app-toolbar.test.tsx +6 -4
- package/src/features/panel-apps/components/panel-app-list-item.tsx +1 -1
- package/src/features/panel-apps/components/panel-app-toolbar.tsx +7 -7
- package/src/features/projects/components/project-skills.tsx +2 -2
- package/src/features/right-panel-resources/components/__tests__/page-resource-sidebar-nav.test.tsx +27 -2
- package/src/features/right-panel-resources/components/page-resource-actions-menu.tsx +4 -22
- package/src/features/right-panel-resources/components/page-resource-sidebar-nav.tsx +10 -13
- package/src/features/right-panel-resources/hooks/use-page-resource-actions.ts +56 -3
- package/src/features/right-panel-resources/index.ts +0 -1
- package/src/features/service-apps/components/service-app-list-item.tsx +3 -2
- package/src/features/system-status/components/__tests__/desktop-update-config.test.tsx +40 -0
- package/src/features/system-status/components/desktop-update-config.tsx +19 -1
- package/src/platforms/desktop/components/__tests__/desktop-app-shell.test.tsx +0 -1
- package/src/platforms/desktop/components/desktop-app-shell.tsx +0 -2
- package/src/platforms/mobile/components/mobile-app-shell.tsx +0 -2
- package/src/platforms/mobile/components/mobile-settings-shell.tsx +8 -3
- package/src/shared/components/ui/context-menu/__tests__/context-menu.test.tsx +83 -1
- package/src/shared/components/ui/context-menu/context-menu-items.tsx +173 -0
- package/src/shared/components/ui/context-menu/context-menu.tsx +93 -114
- package/src/shared/components/ui/dialog.tsx +4 -0
- package/src/shared/components/ui/overlays/sheet.tsx +4 -0
- package/src/shared/components/ui/popover.tsx +10 -4
- package/src/shared/lib/i18n/locales/en-US/chat.json +8 -1
- package/src/shared/lib/i18n/locales/en-US/core.json +3 -1
- package/src/shared/lib/i18n/locales/en-US/desktop-update.json +1 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +8 -1
- package/src/shared/lib/i18n/locales/zh-CN/core.json +11 -9
- package/src/shared/lib/i18n/locales/zh-CN/desktop-update.json +1 -0
- package/src/shared/lib/transport/__tests__/browser-realtime-recovery.service.test.ts +27 -2
- package/src/shared/lib/transport/__tests__/local-transport.service.test.ts +20 -0
- package/src/shared/lib/transport/__tests__/remote.transport.test.ts +26 -0
- package/src/shared/lib/transport/browser-realtime-recovery.service.ts +32 -5
- package/src/shared/lib/transport/local-transport.service.ts +1 -6
- package/src/shared/lib/transport/remote-transport.service.ts +22 -1
- package/dist/assets/api-D9e9cHtW.js +0 -20
- package/dist/assets/app-presenter-provider-J9IgTbc9.js +0 -124
- package/dist/assets/architecture-TIHT7OUA-BWywYH_m.js +0 -1
- package/dist/assets/channel-1nKIAEXr.js +0 -1
- package/dist/assets/chunk-2Q5K7J3B-CAwv72v4.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-DnaryNw2.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-BToo1uqb.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-D_TusZGx.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-B1NFZTmS.js +0 -1
- package/dist/assets/confirm-dialog-BCGeh61X.js +0 -1
- package/dist/assets/cynefin-VYW2F7L2-CJZSs5s_.js +0 -1
- package/dist/assets/desktop-update-config-BJMTQMRS.js +0 -1
- package/dist/assets/dialog-DQXou6pg.js +0 -5
- package/dist/assets/dist-CiC9Fd9J.js +0 -1
- package/dist/assets/doc-browser-CCYS_csH.js +0 -1
- package/dist/assets/es2015-DHRpDU-q.js +0 -41
- package/dist/assets/eventmodeling-45OFAUF4-rc7kUq4V.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-DAjaeGO8.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-Ce0gf6ps.js +0 -1
- package/dist/assets/info-DKCQHKI2-Cp-Tr78m.js +0 -1
- package/dist/assets/loader-circle-B-4WwzBj.js +0 -1
- package/dist/assets/login-page-CdlI6B8e.js +0 -1
- package/dist/assets/main-BVYdyT60.css +0 -1
- package/dist/assets/main-DYEALeoQ.js +0 -2
- package/dist/assets/main-i18n-catalog.config-1o2hjZ0m.js +0 -1
- package/dist/assets/mcp-marketplace-page-CRRQT6SP.js +0 -1
- package/dist/assets/packet-7NZHBO7P-BOJuCraS.js +0 -1
- package/dist/assets/panel-app-2EACRB8p.js +0 -1
- package/dist/assets/panel-app-i18n-catalog.config-kQO7QAwH.js +0 -1
- package/dist/assets/pie-RZYD4A2V-D-FEO81x.js +0 -1
- package/dist/assets/projects-k6SLda_A.js +0 -1
- package/dist/assets/provider-models-mVzuEQBS.js +0 -1
- package/dist/assets/providers-config-page-rBlVrHkb.js +0 -1
- package/dist/assets/pwa-BgGM4kkY.js +0 -1
- package/dist/assets/radar-I7S5WNFK-Bq3eK1vK.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-C3uZ1esg.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-D3iZd1KT.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-Dl0FWqZu.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-B51SbzGp.js +0 -1
- package/dist/assets/remote-wYWqir2w.js +0 -1
- package/dist/assets/security-config-CJb2pK2O.js +0 -1
- package/dist/assets/select-Bq-UmfCK.js +0 -1
- package/dist/assets/service-apps-panel-iLLEByRF.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-CcOGfDdx.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-BMI2k8RZ.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-C0_07QI1.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-Djpx6ccG.js +0 -1
- package/dist/assets/use-desktop-capabilities-BTgdFgJy.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-DZVFxu81.js +0 -1
- package/dist/assets/x-LUUwl8rK.js +0 -1
- package/src/features/right-panel-resources/components/current-page-actions.tsx +0 -36
- /package/dist/assets/{array-B0sEvCP9.js → array-BV9OtnO8.js} +0 -0
- /package/dist/assets/{chunk-KEIR6QF5-BeO7fxDQ.js → chunk-KEIR6QF5-Cx-8EJ4_.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-JQfgEV36.js → chunk-Y2CYZVJY-Dy1ufvjf.js} +0 -0
- /package/dist/assets/{config-hints-D3OuwoEY.js → config-hints-DbmiyTKg.js} +0 -0
- /package/dist/assets/{cytoscape.esm-CzJ9uXgi.js → cytoscape.esm-CSCjuT4Z.js} +0 -0
- /package/dist/assets/{defaultLocale-USmzX3VG.js → defaultLocale-DWTiNsbT.js} +0 -0
- /package/dist/assets/{dist-BYF6XVna.js → dist-BVCSkfWY.js} +0 -0
- /package/dist/assets/{graphlib-DEFMkHdW.js → graphlib-B1yb1Wl8.js} +0 -0
- /package/dist/assets/{host-capabilities-C0MmWd3M.js → host-capabilities-DuIFVsvM.js} +0 -0
- /package/dist/assets/{init-04ErALoz.js → init-BF6GH5oe.js} +0 -0
- /package/dist/assets/{jszip.min-BnQ5NRy2.js → jszip.min-D12teKzP.js} +0 -0
- /package/dist/assets/{middleware-CAXxl-af.js → middleware-B--6mAUM.js} +0 -0
- /package/dist/assets/{navigation-history-CyawyVz0.js → navigation-history-CzErJuPG.js} +0 -0
- /package/dist/assets/{path-CzxQ9n2G.js → path-C56XkznJ.js} +0 -0
- /package/dist/assets/{rough.esm-pT9fdsW3.js → rough.esm-CGfeEbtE.js} +0 -0
- /package/dist/assets/{xlsx-BRpCSiE4.js → xlsx-sds5nUpL.js} +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { afterEach, expect, it, vi } from 'vitest';
|
|
2
2
|
import { checkMicrophoneAccess, classifyMicrophoneError, voicePermissionInstructionKeys } from './chat-voice-permissions.utils';
|
|
3
|
+
import { setLanguage, t } from '@/shared/lib/i18n';
|
|
3
4
|
|
|
4
5
|
afterEach(() => vi.unstubAllGlobals());
|
|
5
6
|
|
|
@@ -20,8 +21,11 @@ it('rechecks access and immediately releases every captured track', async () =>
|
|
|
20
21
|
expect(stop).toHaveBeenCalledTimes(2);
|
|
21
22
|
});
|
|
22
23
|
|
|
23
|
-
it('
|
|
24
|
+
it('distinguishes insecure HTTP from an unsupported media API and an actual denial', async () => {
|
|
25
|
+
vi.stubGlobal('isSecureContext', false);
|
|
24
26
|
vi.stubGlobal('navigator', {});
|
|
27
|
+
expect(await checkMicrophoneAccess()).toBe('insecure-context');
|
|
28
|
+
vi.stubGlobal('isSecureContext', true);
|
|
25
29
|
expect(await checkMicrophoneAccess()).toBe('unsupported');
|
|
26
30
|
vi.stubGlobal('navigator', { mediaDevices: { getUserMedia: vi.fn().mockRejectedValue(new DOMException('', 'NotAllowedError')) } });
|
|
27
31
|
expect(await checkMicrophoneAccess()).toBe('permission');
|
|
@@ -34,3 +38,10 @@ it.each([
|
|
|
34
38
|
expect(voicePermissionInstructionKeys(ua)).toEqual(['chatInputVoicePermissionBrowser', `chatInputVoicePermission${platform}`]);
|
|
35
39
|
expect(voicePermissionInstructionKeys(`${ua} Electron`)[0]).toBe('chatInputVoicePermissionDesktop');
|
|
36
40
|
});
|
|
41
|
+
|
|
42
|
+
it('explains the VPS HTTPS recovery path in both supported languages', () => {
|
|
43
|
+
setLanguage('zh');
|
|
44
|
+
expect(t('chatInputVoiceInsecureContext')).toContain('VPS 配置 HTTPS');
|
|
45
|
+
setLanguage('en');
|
|
46
|
+
expect(t('chatInputVoiceInsecureContext')).toContain('Configure HTTPS for a VPS');
|
|
47
|
+
});
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
export type MicrophoneError = 'permission' | 'no-device' | 'device-busy' | 'unsupported' | 'failed';
|
|
1
|
+
export type MicrophoneError = 'insecure-context' | 'permission' | 'no-device' | 'device-busy' | 'unsupported' | 'failed';
|
|
2
|
+
|
|
3
|
+
export function isMicrophoneSecureContext(): boolean {
|
|
4
|
+
return globalThis.isSecureContext !== false;
|
|
5
|
+
}
|
|
2
6
|
|
|
3
7
|
export function classifyMicrophoneError(error: unknown): MicrophoneError {
|
|
4
8
|
const name = error instanceof DOMException || error instanceof Error ? error.name : '';
|
|
@@ -11,6 +15,7 @@ export function classifyMicrophoneError(error: unknown): MicrophoneError {
|
|
|
11
15
|
|
|
12
16
|
/** Check on explicit start/retry; release every track even if the panel was closed. */
|
|
13
17
|
export async function checkMicrophoneAccess(): Promise<MicrophoneError | null> {
|
|
18
|
+
if (!isMicrophoneSecureContext()) return 'insecure-context';
|
|
14
19
|
if (!navigator.mediaDevices?.getUserMedia) return 'unsupported';
|
|
15
20
|
try {
|
|
16
21
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
@@ -159,8 +159,14 @@ export function CronJobRow({
|
|
|
159
159
|
</button>
|
|
160
160
|
|
|
161
161
|
<TooltipProvider delayDuration={250}>
|
|
162
|
-
<div className="relative flex shrink-0 items-center">
|
|
163
|
-
<
|
|
162
|
+
<div className="relative flex shrink-0 items-center gap-1">
|
|
163
|
+
<Switch
|
|
164
|
+
checked={job.enabled}
|
|
165
|
+
onCheckedChange={(checked) => onToggle(job, checked)}
|
|
166
|
+
aria-label={job.enabled ? t("cronDisable") : t("cronEnable")}
|
|
167
|
+
/>
|
|
168
|
+
|
|
169
|
+
<div className="flex items-center gap-0.5 opacity-100 transition-opacity duration-150 [@media(hover:hover)]:pointer-events-none [@media(hover:hover)]:opacity-0 [@media(hover:hover)]:group-focus-within:pointer-events-auto [@media(hover:hover)]:group-focus-within:opacity-100 [@media(hover:hover)]:group-hover:pointer-events-auto [@media(hover:hover)]:group-hover:opacity-100">
|
|
164
170
|
<Tooltip>
|
|
165
171
|
<TooltipTrigger asChild>
|
|
166
172
|
<Button
|
|
@@ -192,8 +198,7 @@ export function CronJobRow({
|
|
|
192
198
|
</TooltipTrigger>
|
|
193
199
|
<TooltipContent>{t("cronMoreActions")}</TooltipContent>
|
|
194
200
|
</Tooltip>
|
|
195
|
-
<PopoverContent align="end" sideOffset={4}
|
|
196
|
-
<PageResourceActionItems page={pageResourceFromSystemObject("cron-job", job.id, jobLabel)} onSelect={() => setMenuOpen(false)} />
|
|
201
|
+
<PopoverContent align="end" sideOffset={4} variant="menu">
|
|
197
202
|
<div className="my-1 h-px bg-border" />
|
|
198
203
|
<button
|
|
199
204
|
type="button"
|
|
@@ -217,14 +222,11 @@ export function CronJobRow({
|
|
|
217
222
|
<Trash2 className="h-3.5 w-3.5" />
|
|
218
223
|
{t("delete")}
|
|
219
224
|
</button>
|
|
225
|
+
<div className="my-1 h-px bg-border" />
|
|
226
|
+
<PageResourceActionItems page={pageResourceFromSystemObject("cron-job", job.id, jobLabel)} onSelect={() => setMenuOpen(false)} />
|
|
220
227
|
</PopoverContent>
|
|
221
228
|
</Popover>
|
|
222
229
|
</div>
|
|
223
|
-
<Switch
|
|
224
|
-
checked={job.enabled}
|
|
225
|
-
onCheckedChange={(checked) => onToggle(job, checked)}
|
|
226
|
-
aria-label={job.enabled ? t("cronDisable") : t("cronEnable")}
|
|
227
|
-
/>
|
|
228
230
|
</div>
|
|
229
231
|
</TooltipProvider>
|
|
230
232
|
</div>
|
|
@@ -153,8 +153,10 @@ export function InboxReaderDialog() {
|
|
|
153
153
|
{formatDateTime(activeDelivery.createdAt)}
|
|
154
154
|
</time>
|
|
155
155
|
</div>
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
<div className="flex shrink-0 items-center gap-1">
|
|
157
|
+
{positionControls}
|
|
158
|
+
<PageResourceActionsMenu page={pageResourceFromSystemObject("inbox-delivery", activeDelivery.id, activeDelivery.title)} />
|
|
159
|
+
</div>
|
|
158
160
|
</div>
|
|
159
161
|
<DialogDescription className="sr-only">
|
|
160
162
|
{activeDelivery.summary ?? t("inboxNoSummary")}
|
|
@@ -115,14 +115,17 @@ function InboxListPane({
|
|
|
115
115
|
{filteredDeliveries.length > 0 ? (
|
|
116
116
|
<ul className="space-y-0.5">
|
|
117
117
|
{filteredDeliveries.map((delivery) => (
|
|
118
|
-
<li key={delivery.id}
|
|
118
|
+
<li key={delivery.id} className={cn(
|
|
119
|
+
"group/page-row relative rounded-lg hover:bg-[var(--interaction-hover)] focus-within:bg-[var(--interaction-hover)] has-[[data-context-menu-open]]:bg-[var(--interaction-hover)]",
|
|
120
|
+
activeDeliveryId === delivery.id && "bg-[var(--interaction-selection)]",
|
|
121
|
+
)}>
|
|
119
122
|
<Link
|
|
120
123
|
to={`/inbox/${encodeURIComponent(delivery.id)}`}
|
|
121
124
|
className={cn(
|
|
122
|
-
"block rounded-lg px-2.5 py-2 text-[13px] transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border",
|
|
125
|
+
"block rounded-lg px-2.5 py-2 pr-10 text-[13px] transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border",
|
|
123
126
|
activeDeliveryId === delivery.id
|
|
124
|
-
? "
|
|
125
|
-
: "text-foreground/80 hover:
|
|
127
|
+
? "text-foreground"
|
|
128
|
+
: "text-foreground/80 hover:text-foreground",
|
|
126
129
|
)}
|
|
127
130
|
>
|
|
128
131
|
<h2 className={cn(
|
|
@@ -131,7 +134,6 @@ function InboxListPane({
|
|
|
131
134
|
)}>
|
|
132
135
|
{delivery.title}
|
|
133
136
|
</h2>
|
|
134
|
-
<PageResourceActionsMenu page={pageResourceFromSystemObject("inbox-delivery", delivery.id, delivery.title)} />
|
|
135
137
|
<div className="mt-0.5 flex items-center gap-2 text-[11px] leading-4 text-muted-foreground/65">
|
|
136
138
|
<p className="min-w-0 flex-1 truncate">
|
|
137
139
|
{delivery.summary ?? t("inboxNoSummary")}
|
|
@@ -148,6 +150,9 @@ function InboxListPane({
|
|
|
148
150
|
)}
|
|
149
151
|
</div>
|
|
150
152
|
</Link>
|
|
153
|
+
<span className="absolute right-1 top-1.5">
|
|
154
|
+
<PageResourceActionsMenu revealOnHover page={pageResourceFromSystemObject("inbox-delivery", delivery.id, delivery.title)} />
|
|
155
|
+
</span>
|
|
151
156
|
</li>
|
|
152
157
|
))}
|
|
153
158
|
</ul>
|
|
@@ -60,7 +60,6 @@ export function McpMarketplaceCard(props: {
|
|
|
60
60
|
</div>
|
|
61
61
|
|
|
62
62
|
<div className="flex shrink-0 flex-col gap-2">
|
|
63
|
-
{record?.id && <PageResourceActionsMenu page={pageResourceFromSystemObject("mcp-server", record.id, name)} />}
|
|
64
63
|
{!installed && item && onInstall ? (
|
|
65
64
|
<Button
|
|
66
65
|
type="button"
|
|
@@ -124,6 +123,7 @@ export function McpMarketplaceCard(props: {
|
|
|
124
123
|
) : null}
|
|
125
124
|
</>
|
|
126
125
|
) : null}
|
|
126
|
+
{record?.id && <PageResourceActionsMenu page={pageResourceFromSystemObject("mcp-server", record.id, name)} />}
|
|
127
127
|
</div>
|
|
128
128
|
</div>
|
|
129
129
|
</article>
|
|
@@ -98,9 +98,10 @@ describe('PanelAppListItem', () => {
|
|
|
98
98
|
/>,
|
|
99
99
|
);
|
|
100
100
|
|
|
101
|
-
expect(screen.queryByRole('
|
|
101
|
+
expect(screen.queryByRole('menuitem', { name: 'Pin to left sidebar' })).toBeNull();
|
|
102
102
|
await user.click(screen.getByRole('button', { name: 'More panel app actions' }));
|
|
103
|
-
await user.click(screen.getByRole('
|
|
103
|
+
await user.click(screen.getByRole('menuitem', { name: 'Layout and position' }));
|
|
104
|
+
await user.click(screen.getByRole('menuitem', { name: 'Pin to left sidebar' }));
|
|
104
105
|
expect(mainSidebarMutation.mutate).toHaveBeenCalledWith({
|
|
105
106
|
id: 'demo',
|
|
106
107
|
preferences: { mainSidebar: true },
|
|
@@ -120,9 +121,10 @@ describe('PanelAppListItem', () => {
|
|
|
120
121
|
onToggleFavorite={vi.fn()}
|
|
121
122
|
/>,
|
|
122
123
|
);
|
|
123
|
-
expect(screen.queryByRole('
|
|
124
|
+
expect(screen.queryByRole('menuitem', { name: 'Unpin from left sidebar' })).toBeNull();
|
|
124
125
|
await user.click(screen.getByRole('button', { name: 'More panel app actions' }));
|
|
125
|
-
await user.click(screen.getByRole('
|
|
126
|
+
await user.click(screen.getByRole('menuitem', { name: 'Layout and position' }));
|
|
127
|
+
await user.click(screen.getByRole('menuitem', { name: 'Unpin from left sidebar' }));
|
|
126
128
|
expect(mainSidebarMutation.mutate).toHaveBeenLastCalledWith({
|
|
127
129
|
id: 'demo',
|
|
128
130
|
preferences: { mainSidebar: false },
|
|
@@ -51,9 +51,10 @@ describe('PanelAppToolbar', () => {
|
|
|
51
51
|
expect(screen.getByText('墨爪助手')).toBeTruthy();
|
|
52
52
|
expect(screen.queryByRole('button', { name: 'Apps' })).toBeNull();
|
|
53
53
|
|
|
54
|
-
expect(screen.queryByRole('
|
|
54
|
+
expect(screen.queryByRole('menuitem', { name: 'Pin to left sidebar' })).toBeNull();
|
|
55
55
|
await user.click(screen.getByRole('button', { name: 'More panel app actions' }));
|
|
56
|
-
|
|
56
|
+
await user.click(screen.getByRole('menuitem', { name: 'Layout and position' }));
|
|
57
|
+
const addButton = screen.getByRole('menuitem', { name: 'Pin to left sidebar' });
|
|
57
58
|
expect(addButton.getAttribute('aria-pressed')).toBe('false');
|
|
58
59
|
await user.click(addButton);
|
|
59
60
|
|
|
@@ -61,7 +62,7 @@ describe('PanelAppToolbar', () => {
|
|
|
61
62
|
id: 'ink-assistant',
|
|
62
63
|
preferences: { mainSidebar: true },
|
|
63
64
|
});
|
|
64
|
-
expect(screen.queryByRole('
|
|
65
|
+
expect(screen.queryByRole('menuitem', { name: 'Pin to left sidebar' })).toBeNull();
|
|
65
66
|
});
|
|
66
67
|
|
|
67
68
|
it('uses the same menu item to remove an app already in the main sidebar', async () => {
|
|
@@ -76,7 +77,8 @@ describe('PanelAppToolbar', () => {
|
|
|
76
77
|
);
|
|
77
78
|
|
|
78
79
|
await user.click(screen.getByRole('button', { name: 'More panel app actions' }));
|
|
79
|
-
|
|
80
|
+
await user.click(screen.getByRole('menuitem', { name: 'Layout and position' }));
|
|
81
|
+
const removeButton = screen.getByRole('menuitem', { name: 'Unpin from left sidebar' });
|
|
80
82
|
expect(removeButton.getAttribute('aria-pressed')).toBe('true');
|
|
81
83
|
await user.click(removeButton);
|
|
82
84
|
|
|
@@ -76,7 +76,7 @@ export function PanelAppListItem({
|
|
|
76
76
|
<MoreVertical className="h-4 w-4" />
|
|
77
77
|
</button>
|
|
78
78
|
</PopoverTrigger>
|
|
79
|
-
<PopoverContent align="end"
|
|
79
|
+
<PopoverContent align="end" variant="menu">
|
|
80
80
|
<PanelAppOpenStandaloneMenuItem
|
|
81
81
|
entry={entry}
|
|
82
82
|
onSelect={() => setIsMenuOpen(false)}
|
|
@@ -30,6 +30,12 @@ export function PanelAppToolbar({
|
|
|
30
30
|
>
|
|
31
31
|
{appTitle}
|
|
32
32
|
</span>
|
|
33
|
+
<IconActionButton
|
|
34
|
+
icon={<RefreshCw className="h-3.5 w-3.5" />}
|
|
35
|
+
label={t('panelAppsRefreshCurrent')}
|
|
36
|
+
onClick={onRefresh}
|
|
37
|
+
size="sm"
|
|
38
|
+
/>
|
|
33
39
|
{entry ? (
|
|
34
40
|
<Popover open={isMenuOpen} onOpenChange={setIsMenuOpen}>
|
|
35
41
|
<PopoverTrigger asChild>
|
|
@@ -39,7 +45,7 @@ export function PanelAppToolbar({
|
|
|
39
45
|
size="sm"
|
|
40
46
|
/>
|
|
41
47
|
</PopoverTrigger>
|
|
42
|
-
<PopoverContent align="end"
|
|
48
|
+
<PopoverContent align="end" variant="menu">
|
|
43
49
|
<PanelAppOpenStandaloneMenuItem
|
|
44
50
|
entry={entry}
|
|
45
51
|
onSelect={() => setIsMenuOpen(false)}
|
|
@@ -51,12 +57,6 @@ export function PanelAppToolbar({
|
|
|
51
57
|
</PopoverContent>
|
|
52
58
|
</Popover>
|
|
53
59
|
) : null}
|
|
54
|
-
<IconActionButton
|
|
55
|
-
icon={<RefreshCw className="h-3.5 w-3.5" />}
|
|
56
|
-
label={t('panelAppsRefreshCurrent')}
|
|
57
|
-
onClick={onRefresh}
|
|
58
|
-
size="sm"
|
|
59
|
-
/>
|
|
60
60
|
</div>
|
|
61
61
|
);
|
|
62
62
|
}
|
|
@@ -35,10 +35,10 @@ export function ProjectSkills({
|
|
|
35
35
|
{skills.length ? (
|
|
36
36
|
<div className="grid min-w-0 gap-3 md:grid-cols-2">
|
|
37
37
|
{skills.map((skill) => (
|
|
38
|
-
<div key={skill.ref} className="relative group/page-row">
|
|
38
|
+
<div key={skill.ref} className="relative group/page-row rounded-xl border border-border/60 transition-colors hover:border-border hover:bg-[var(--interaction-hover)] focus-within:bg-[var(--interaction-hover)] has-[[data-context-menu-open]]:bg-[var(--interaction-hover)]">
|
|
39
39
|
<button
|
|
40
40
|
type="button"
|
|
41
|
-
className="w-full min-w-0 rounded-xl
|
|
41
|
+
className="w-full min-w-0 rounded-xl p-3 text-left focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
|
|
42
42
|
onClick={() => onOpen(skill)}
|
|
43
43
|
>
|
|
44
44
|
<h3 className="pr-7 text-sm font-medium">{skill.name}</h3>
|
package/src/features/right-panel-resources/components/__tests__/page-resource-sidebar-nav.test.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import { PageResourceSidebarNav } from "@/features/right-panel-resources/compone
|
|
|
8
8
|
import { usePageNavigationStore } from "@/features/right-panel-resources/stores/page-navigation.store";
|
|
9
9
|
import { AppPresenterProvider } from "@/app/components/app-presenter-provider";
|
|
10
10
|
import type { PanelAppEntryView } from "@/shared/lib/api";
|
|
11
|
+
import { SidebarNavLinkItem } from "@/app/components/layout/sidebar-items";
|
|
11
12
|
|
|
12
13
|
const mocks = vi.hoisted(() => ({
|
|
13
14
|
entries: [] as PanelAppEntryView[],
|
|
@@ -123,10 +124,10 @@ describe("shared left pages", () => {
|
|
|
123
124
|
expect(link.contains(menu)).toBe(false);
|
|
124
125
|
expect(menu.querySelector(".lucide-ellipsis-vertical")).not.toBeNull();
|
|
125
126
|
expect(menu.parentElement?.className).toContain(
|
|
126
|
-
"group-hover/
|
|
127
|
+
"group-hover/sidebar-item:opacity-100",
|
|
127
128
|
);
|
|
128
129
|
expect(menu.parentElement?.className).toContain(
|
|
129
|
-
"group-focus-within/
|
|
130
|
+
"group-focus-within/sidebar-item:opacity-100",
|
|
130
131
|
);
|
|
131
132
|
expect(menu.parentElement?.className).toContain(
|
|
132
133
|
"data-[context-menu-open]:opacity-100",
|
|
@@ -136,6 +137,8 @@ describe("shared left pages", () => {
|
|
|
136
137
|
expect(menu.parentElement?.hasAttribute("data-context-menu-open")).toBe(
|
|
137
138
|
true,
|
|
138
139
|
);
|
|
140
|
+
expect(screen.queryByRole("menuitem", { name: "Unpin from left sidebar" })).toBeNull();
|
|
141
|
+
await userEvent.click(screen.getByRole("menuitem", { name: "Layout and position" }));
|
|
139
142
|
await userEvent.click(
|
|
140
143
|
screen.getByRole("menuitem", { name: "Unpin from left sidebar" }),
|
|
141
144
|
);
|
|
@@ -155,4 +158,26 @@ describe("shared left pages", () => {
|
|
|
155
158
|
it("omits an empty group", () => {
|
|
156
159
|
expect(renderNav().container.firstChild).toBeNull();
|
|
157
160
|
});
|
|
161
|
+
it("shares one whole-row surface with primary navigation and keeps actions inside that surface", () => {
|
|
162
|
+
mocks.entries = [createEntry({ mainSidebar: true })];
|
|
163
|
+
render(
|
|
164
|
+
<MemoryRouter><AppPresenterProvider>
|
|
165
|
+
<SidebarNavLinkItem to="/inbox" label="Inbox" density="compact" />
|
|
166
|
+
<PageResourceSidebarNav isCollapsed={false} />
|
|
167
|
+
</AppPresenterProvider></MemoryRouter>,
|
|
168
|
+
);
|
|
169
|
+
const primary = screen.getByRole("link", { name: "Inbox" });
|
|
170
|
+
const page = screen.getByRole("link", { name: "Demo" });
|
|
171
|
+
expect(page.parentElement?.className).toBe(primary.parentElement?.className);
|
|
172
|
+
expect(page.parentElement?.contains(screen.getByRole("button", { name: "Page actions" }))).toBe(true);
|
|
173
|
+
expect(page.className).toContain("pr-9");
|
|
174
|
+
});
|
|
175
|
+
it("distinguishes resources sharing a pathname by their query identity", () => {
|
|
176
|
+
render(<MemoryRouter initialEntries={["/resource?uri=one"]}>
|
|
177
|
+
<SidebarNavLinkItem to="/resource?uri=one" label="One" />
|
|
178
|
+
<SidebarNavLinkItem to="/resource?uri=two" label="Two" />
|
|
179
|
+
</MemoryRouter>);
|
|
180
|
+
expect(screen.getByRole("link", { name: "One" }).getAttribute("aria-current")).toBe("page");
|
|
181
|
+
expect(screen.getByRole("link", { name: "Two" }).hasAttribute("aria-current")).toBe(false);
|
|
182
|
+
});
|
|
158
183
|
});
|
|
@@ -2,6 +2,7 @@ import { MoreVertical } from "lucide-react";
|
|
|
2
2
|
import {
|
|
3
3
|
ContextMenu,
|
|
4
4
|
ContextMenuTrigger,
|
|
5
|
+
ContextMenuItems,
|
|
5
6
|
} from "@/shared/components/ui/context-menu/context-menu";
|
|
6
7
|
import { IconActionButton } from "@/shared/components/ui/actions/icon-action-button";
|
|
7
8
|
import { usePageResourceActions } from "@/features/right-panel-resources/hooks/use-page-resource-actions";
|
|
@@ -21,9 +22,9 @@ export function PageResourceActionsMenu({
|
|
|
21
22
|
<ContextMenu groups={actions(page)} label={t("pageActions")}>
|
|
22
23
|
<span
|
|
23
24
|
className={cn(
|
|
24
|
-
"inline-flex",
|
|
25
|
+
"inline-flex shrink-0",
|
|
25
26
|
revealOnHover &&
|
|
26
|
-
"pointer-events-none opacity-0 transition-opacity group-hover/
|
|
27
|
+
"pointer-events-none opacity-0 transition-opacity group-hover/sidebar-item:pointer-events-auto group-hover/sidebar-item:opacity-100 group-focus-within/sidebar-item:pointer-events-auto group-focus-within/sidebar-item:opacity-100 data-[context-menu-open]:pointer-events-auto data-[context-menu-open]:opacity-100 [@media(hover:none)]:pointer-events-auto [@media(hover:none)]:opacity-100",
|
|
27
28
|
)}
|
|
28
29
|
>
|
|
29
30
|
<ContextMenuTrigger>
|
|
@@ -47,25 +48,6 @@ export function PageResourceActionItems({
|
|
|
47
48
|
}) {
|
|
48
49
|
const actions = usePageResourceActions();
|
|
49
50
|
return (
|
|
50
|
-
|
|
51
|
-
{actions(page)
|
|
52
|
-
.flatMap((group) => group.items)
|
|
53
|
-
.map((item) => (
|
|
54
|
-
<button
|
|
55
|
-
key={item.key}
|
|
56
|
-
type="button"
|
|
57
|
-
disabled={item.disabled}
|
|
58
|
-
aria-pressed={item.pressed}
|
|
59
|
-
className="flex w-full items-center gap-2 rounded-lg px-2.5 py-2 text-left text-sm text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50"
|
|
60
|
-
onClick={() => {
|
|
61
|
-
onSelect?.();
|
|
62
|
-
item.onSelect?.();
|
|
63
|
-
}}
|
|
64
|
-
>
|
|
65
|
-
{item.icon}
|
|
66
|
-
{item.label}
|
|
67
|
-
</button>
|
|
68
|
-
))}
|
|
69
|
-
</>
|
|
51
|
+
<ContextMenuItems groups={actions(page)} onClose={() => onSelect?.()} />
|
|
70
52
|
);
|
|
71
53
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
import { ChevronDown, PanelsTopLeft } from "lucide-react";
|
|
3
|
-
import {
|
|
3
|
+
import { SidebarNavLinkItem } from "@/app/components/layout/sidebar-items";
|
|
4
|
+
import { SIDEBAR_RAIL_CONTROL_CLASS, SIDEBAR_RAIL_SURFACE_CLASS } from "@/app/components/layout/sidebar-rail.styles";
|
|
4
5
|
import { usePanelApps } from "@/features/panel-apps";
|
|
5
6
|
import { createPanelAppRightPanelResourceTarget } from "@/features/right-panel-resources/utils/right-panel-resource-uri.utils";
|
|
6
7
|
import {
|
|
@@ -34,22 +35,18 @@ function PageResourceSidebarItems({
|
|
|
34
35
|
{pages.map((page) => (
|
|
35
36
|
<li
|
|
36
37
|
key={page.uri}
|
|
37
|
-
className="group/page-row flex items-center gap-1 rounded-lg hover:bg-muted/60"
|
|
38
38
|
>
|
|
39
|
-
<
|
|
39
|
+
<SidebarNavLinkItem
|
|
40
40
|
to={pageResourceMainPath(page)}
|
|
41
|
-
|
|
41
|
+
label={page.title}
|
|
42
|
+
density="compact"
|
|
43
|
+
iconNode={<PageResourceIcon uri={page.uri} icon={page.target.dockIcon} />}
|
|
44
|
+
actions={<PageResourceActionsMenu page={page} revealOnHover />}
|
|
45
|
+
onNavigate={() => {
|
|
42
46
|
app.pageResourceManager.remember(page);
|
|
43
47
|
onNavigate?.();
|
|
44
48
|
}}
|
|
45
|
-
|
|
46
|
-
`flex min-w-0 flex-1 items-center gap-2 rounded-lg px-2.5 py-1.5 text-[13px] ${isActive ? "bg-primary/10 font-medium text-primary" : "text-muted-foreground hover:text-foreground"}`
|
|
47
|
-
}
|
|
48
|
-
>
|
|
49
|
-
<PageResourceIcon uri={page.uri} icon={page.target.dockIcon} />
|
|
50
|
-
<span className="truncate">{page.title}</span>
|
|
51
|
-
</NavLink>
|
|
52
|
-
<PageResourceActionsMenu page={page} revealOnHover />
|
|
49
|
+
/>
|
|
53
50
|
</li>
|
|
54
51
|
))}
|
|
55
52
|
</ul>
|
|
@@ -85,7 +82,7 @@ export function PageResourceSidebarNav({
|
|
|
85
82
|
<button
|
|
86
83
|
type="button"
|
|
87
84
|
aria-label={t("pageSidebar")}
|
|
88
|
-
className=
|
|
85
|
+
className={`mx-auto my-1 flex items-center justify-center ${SIDEBAR_RAIL_CONTROL_CLASS} ${SIDEBAR_RAIL_SURFACE_CLASS}`}
|
|
89
86
|
>
|
|
90
87
|
<PanelsTopLeft className="h-4 w-4" />
|
|
91
88
|
</button>
|
|
@@ -14,9 +14,21 @@ import {
|
|
|
14
14
|
} from "@/features/right-panel-resources/utils/right-panel-resource-uri.utils";
|
|
15
15
|
import { pageResourceTab } from "@/features/right-panel-resources/managers/page-resource.manager";
|
|
16
16
|
import type { PageResource } from "@/features/right-panel-resources/types/page-resource.types";
|
|
17
|
-
import type {
|
|
17
|
+
import type {
|
|
18
|
+
ContextMenuGroup,
|
|
19
|
+
ContextMenuItem,
|
|
20
|
+
} from "@/shared/components/ui/context-menu/context-menu";
|
|
18
21
|
import { t } from "@/shared/lib/i18n";
|
|
19
22
|
import { toast } from "sonner";
|
|
23
|
+
import { createElement } from "react";
|
|
24
|
+
import {
|
|
25
|
+
LayoutPanelLeft,
|
|
26
|
+
Link,
|
|
27
|
+
MessageSquarePlus,
|
|
28
|
+
PanelLeft,
|
|
29
|
+
PanelsTopLeft,
|
|
30
|
+
Pin,
|
|
31
|
+
} from "lucide-react";
|
|
20
32
|
|
|
21
33
|
export function usePageResourceActions() {
|
|
22
34
|
const app = useAppPresenter();
|
|
@@ -47,7 +59,12 @@ export function usePageResourceActions() {
|
|
|
47
59
|
const items = [
|
|
48
60
|
{
|
|
49
61
|
key: "open-main",
|
|
50
|
-
|
|
62
|
+
icon: createElement(PanelsTopLeft, { className: "h-4 w-4" }),
|
|
63
|
+
label: t(
|
|
64
|
+
page.target.kind === "workspace"
|
|
65
|
+
? "workbenchMaximize"
|
|
66
|
+
: "workbenchOpenMain",
|
|
67
|
+
),
|
|
51
68
|
onSelect: () => open("main"),
|
|
52
69
|
},
|
|
53
70
|
...(page.target.kind === "route"
|
|
@@ -55,17 +72,20 @@ export function usePageResourceActions() {
|
|
|
55
72
|
: [
|
|
56
73
|
{
|
|
57
74
|
key: "open-sidebar",
|
|
75
|
+
icon: createElement(PanelLeft, { className: "h-4 w-4" }),
|
|
58
76
|
label: t("workbenchDock"),
|
|
59
77
|
onSelect: () => open("sidebar"),
|
|
60
78
|
},
|
|
61
79
|
{
|
|
62
80
|
key: "open-floating",
|
|
81
|
+
icon: createElement(PanelsTopLeft, { className: "h-4 w-4" }),
|
|
63
82
|
label: t("workbenchFloatView"),
|
|
64
83
|
onSelect: () => open("floating"),
|
|
65
84
|
},
|
|
66
85
|
]),
|
|
67
86
|
{
|
|
68
87
|
key: "pin-left",
|
|
88
|
+
icon: createElement(Pin, { className: "h-4 w-4" }),
|
|
69
89
|
pressed: pinned,
|
|
70
90
|
label: t(pinned ? "pageUnpinLeft" : "pagePinLeft"),
|
|
71
91
|
disabled: Boolean(entry && updatePreferences.isPending),
|
|
@@ -85,6 +105,7 @@ export function usePageResourceActions() {
|
|
|
85
105
|
? [
|
|
86
106
|
{
|
|
87
107
|
key: "add-to-chat",
|
|
108
|
+
icon: createElement(MessageSquarePlus, { className: "h-4 w-4" }),
|
|
88
109
|
label: t("docBrowserAddToChat"),
|
|
89
110
|
restoreFocus: false,
|
|
90
111
|
onSelect: () =>
|
|
@@ -94,6 +115,7 @@ export function usePageResourceActions() {
|
|
|
94
115
|
: []),
|
|
95
116
|
{
|
|
96
117
|
key: "copy-uri",
|
|
118
|
+
icon: createElement(Link, { className: "h-4 w-4" }),
|
|
97
119
|
label: t("pageCopyUri"),
|
|
98
120
|
onSelect: () => {
|
|
99
121
|
void navigator.clipboard
|
|
@@ -103,7 +125,6 @@ export function usePageResourceActions() {
|
|
|
103
125
|
},
|
|
104
126
|
];
|
|
105
127
|
return [
|
|
106
|
-
{ key: "page", items },
|
|
107
128
|
...(viewer
|
|
108
129
|
? [
|
|
109
130
|
{
|
|
@@ -132,6 +153,38 @@ export function usePageResourceActions() {
|
|
|
132
153
|
},
|
|
133
154
|
]
|
|
134
155
|
: []),
|
|
156
|
+
...groupPageResourceActions(items),
|
|
135
157
|
];
|
|
136
158
|
};
|
|
137
159
|
}
|
|
160
|
+
|
|
161
|
+
function groupPageResourceActions(
|
|
162
|
+
items: ContextMenuItem[],
|
|
163
|
+
): ContextMenuGroup[] {
|
|
164
|
+
return [
|
|
165
|
+
{
|
|
166
|
+
key: "page-reference",
|
|
167
|
+
items: items.filter(
|
|
168
|
+
(item) => item.key === "add-to-chat" || item.key === "copy-uri",
|
|
169
|
+
),
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
key: "page-layout",
|
|
173
|
+
items: [
|
|
174
|
+
{
|
|
175
|
+
key: "layout",
|
|
176
|
+
label: t("pageLayoutActions"),
|
|
177
|
+
icon: createElement(LayoutPanelLeft, { className: "h-4 w-4" }),
|
|
178
|
+
children: [
|
|
179
|
+
{
|
|
180
|
+
key: "placement",
|
|
181
|
+
items: items.filter(
|
|
182
|
+
(item) => item.key !== "add-to-chat" && item.key !== "copy-uri",
|
|
183
|
+
),
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
},
|
|
189
|
+
];
|
|
190
|
+
}
|
|
@@ -26,7 +26,6 @@ export type {
|
|
|
26
26
|
|
|
27
27
|
export { PageResourceIcon } from './components/page-resource-icon';
|
|
28
28
|
export { PageResourceActionsMenu, PageResourceActionItems } from './components/page-resource-actions-menu';
|
|
29
|
-
export { CurrentPageActions } from './components/current-page-actions';
|
|
30
29
|
export { PageResourceSidebarNav } from './components/page-resource-sidebar-nav';
|
|
31
30
|
export { SYSTEM_OBJECT_RESOURCE_RENDERERS } from './components/system-object-resource';
|
|
32
31
|
export { WORKSPACE_FILE_PANEL_RENDERERS } from './components/workspace-file-resource';
|
|
@@ -167,8 +167,7 @@ export function ServiceAppListItem({
|
|
|
167
167
|
{t("serviceAppsMoreActions")}
|
|
168
168
|
</TooltipContent>
|
|
169
169
|
</Tooltip>
|
|
170
|
-
<PopoverContent align="end"
|
|
171
|
-
<PageResourceActionItems page={pageResourceFromSystemObject("service-app", app.id, app.title)} onSelect={() => setIsMenuOpen(false)} />
|
|
170
|
+
<PopoverContent align="end" variant="menu">
|
|
172
171
|
<div className="my-1 h-px bg-border" />
|
|
173
172
|
<ServiceAppMenuItem
|
|
174
173
|
disabled={!canDisconnectRuntime}
|
|
@@ -197,6 +196,8 @@ export function ServiceAppListItem({
|
|
|
197
196
|
onClick={openDeleteDialog}
|
|
198
197
|
/>
|
|
199
198
|
)}
|
|
199
|
+
<div className="my-1 h-px bg-border" />
|
|
200
|
+
<PageResourceActionItems page={pageResourceFromSystemObject("service-app", app.id, app.title)} onSelect={() => setIsMenuOpen(false)} />
|
|
200
201
|
</PopoverContent>
|
|
201
202
|
</Popover>
|
|
202
203
|
</div>
|
|
@@ -181,6 +181,46 @@ describe('DesktopUpdateConfig', () => {
|
|
|
181
181
|
expect(screen.getByText('fetch failed: getaddrinfo ENOTFOUND updates.nextclaw.io')).toBeTruthy();
|
|
182
182
|
});
|
|
183
183
|
|
|
184
|
+
it('offers a manual Portable Edition download when in-app updates are blocked', () => {
|
|
185
|
+
useRuntimeUpdateStore.setState((state) => ({
|
|
186
|
+
...state,
|
|
187
|
+
snapshot: state.snapshot
|
|
188
|
+
? {
|
|
189
|
+
...state.snapshot,
|
|
190
|
+
status: 'blocked',
|
|
191
|
+
installationKind: 'desktop-bundle',
|
|
192
|
+
blockReason: 'unsupported-installation',
|
|
193
|
+
errorMessage: 'Portable Edition does not support in-app updates yet. Download a newer Portable Edition and keep the data directory.'
|
|
194
|
+
}
|
|
195
|
+
: null
|
|
196
|
+
}));
|
|
197
|
+
|
|
198
|
+
renderDesktopUpdateConfig();
|
|
199
|
+
|
|
200
|
+
const downloadLink = screen.getByRole('link', { name: '下载最新 Portable Edition' });
|
|
201
|
+
expect(downloadLink.getAttribute('href')).toBe('https://github.com/Peiiii/nextclaw/releases');
|
|
202
|
+
expect(downloadLink.getAttribute('target')).toBe('_blank');
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('does not offer a Portable Edition download for non-desktop update blocks', () => {
|
|
206
|
+
useRuntimeUpdateStore.setState((state) => ({
|
|
207
|
+
...state,
|
|
208
|
+
snapshot: state.snapshot
|
|
209
|
+
? {
|
|
210
|
+
...state.snapshot,
|
|
211
|
+
status: 'blocked',
|
|
212
|
+
installationKind: 'npm-runtime-bundle',
|
|
213
|
+
blockReason: 'unsupported-installation',
|
|
214
|
+
errorMessage: 'This runtime does not support updates.'
|
|
215
|
+
}
|
|
216
|
+
: null
|
|
217
|
+
}));
|
|
218
|
+
|
|
219
|
+
renderDesktopUpdateConfig();
|
|
220
|
+
|
|
221
|
+
expect(screen.queryByRole('link', { name: '下载最新 Portable Edition' })).toBeNull();
|
|
222
|
+
});
|
|
223
|
+
|
|
184
224
|
it('loads structured release notes from the docs JSON endpoint', async () => {
|
|
185
225
|
const fetchMock = vi.fn(async () => new Response(JSON.stringify({
|
|
186
226
|
schemaVersion: 1,
|