@nextclaw/ui 0.19.2 → 0.19.4
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 +20 -1
- package/dist/assets/{abnfDiagram-VRR7QNED-DvTjgVMf.js → abnfDiagram-VRR7QNED-DrbfiNNF.js} +1 -1
- package/dist/assets/{aiden0z-pptx-renderer.es-C1nfBAXR.js → aiden0z-pptx-renderer.es-DdLb2IVc.js} +1 -1
- package/dist/assets/{api-BH6Oslx4.js → api-CUSlBpt_.js} +3 -3
- package/dist/assets/{appearance-settings-page-zhgfcGgW.js → appearance-settings-page-cTuZdROP.js} +1 -1
- package/dist/assets/{arc-BvhODBXv.js → arc-BXlMc9B0.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-Bq0i9WiE.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-BKO9RgNS.js → architectureDiagram-ZJ3FMSHR-DXAJxxO0.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-DHpDXy7D.js → blockDiagram-677ZJIJ3-i4Kz7zU0.js} +1 -1
- package/dist/assets/{book-open-DGTS6oEO.js → book-open-BJ-xAIp9.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-BG_iQnDr.js → c4Diagram-LMCZKHZV-BDc0TkPd.js} +1 -1
- package/dist/assets/channel-iCaZQ87u.js +1 -0
- package/dist/assets/{channels-list-page-3D5lhZoT.js → channels-list-page-nRHOasWA.js} +2 -2
- package/dist/assets/chunk-2Q5K7J3B-DFQtlnJS.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-DR9M0LLx.js → chunk-32BRIVSS-DuReei0Z.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-698iC3BB.js → chunk-52WLFC77-D8APq0tm.js} +1 -1
- package/dist/assets/{chunk-5FCAYU7R-DikTj9Ey.js → chunk-5FCAYU7R-BsPrNXNS.js} +1 -1
- package/dist/assets/{chunk-5HE753X5-ko0o7_q0.js → chunk-5HE753X5-BRtkOPoJ.js} +1 -1
- package/dist/assets/{chunk-5JV3BV7I-CEHufhgo.js → chunk-5JV3BV7I-ChPc8e8U.js} +1 -1
- package/dist/assets/{chunk-5TONJI2A-CGgno1cu.js → chunk-5TONJI2A-CzTjlJGb.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-DkiB4cUQ.js → chunk-5VM5RSS4-xsv_22jR.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-DzptcytQ.js → chunk-7BUUIJ7U-CwECujme.js} +1 -1
- package/dist/assets/{chunk-BIQX33UG-DMRSQJvT.js → chunk-BIQX33UG-DQAm173p.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-Bw1BwwuY.js → chunk-C7G6YPKG-BkpajeQb.js} +1 -1
- package/dist/assets/{chunk-CQNSW5MT-C0z6eHBk.js → chunk-CQNSW5MT-ND65pWRA.js} +1 -1
- package/dist/assets/{chunk-CYSBUYHQ-ByPyAouO.js → chunk-CYSBUYHQ-vMu6ijxG.js} +1 -1
- package/dist/assets/{chunk-EMLP6XTP-CJlAXWZg.js → chunk-EMLP6XTP-CEaeW3gH.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-Dqq4zKJu.js → chunk-EX3LRPZG-a4ER-HDr.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-B0SNoCmi.js → chunk-FWX5IMBZ-C_8fQssn.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-DG_GJih_.js → chunk-HOUHSVGY-CEvw-PEd.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-Drxk_6bE.js → chunk-ICXQ74PX-BEtF0fGY.js} +1 -1
- package/dist/assets/{chunk-JG7HCLWE-DdLFPpnd.js → chunk-JG7HCLWE-DGRrVp8-.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-B8M4G76F.js → chunk-JWPE2WC7-DRqpp_nM.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-XP6FJHY_.js → chunk-MOJQB5TN-BDEriOXs.js} +1 -1
- package/dist/assets/{chunk-MOZMSUNE-C_6x18Qw.js → chunk-MOZMSUNE-JWRNzdnw.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-N25BzCmG.js → chunk-OGEWGWER-DS2VTgCx.js} +1 -1
- package/dist/assets/{chunk-OSBZ3O6U-ASDEm7y0.js → chunk-OSBZ3O6U-3LiYTBUB.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-CTlvAcn7.js → chunk-PUDLZKDR-o9M2s_SO.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-Da9BWfB6.js → chunk-Q4XR5HBZ-DTB7Ma2N.js} +1 -1
- package/dist/assets/{chunk-QBLGF6JB-Bi6RpTJO.js → chunk-QBLGF6JB-DpkxZJL5.js} +1 -1
- package/dist/assets/{chunk-R7FJI6CG-DkMsSPvK.js → chunk-R7FJI6CG-CRejkHJU.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-DZp0eU-j.js → chunk-RYQCIY6F-B1boBjLt.js} +1 -1
- package/dist/assets/{chunk-U6XO7XAA-vfinDSrj.js → chunk-U6XO7XAA-DgKa97bj.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-C9Nksccs.js → chunk-V7JOEXUC-DE56eh0N.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-CF9A-TeE.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-Xv6zfwXs.js → chunk-VR4S4FIN-BzomPZq2.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-mOJNzbWl.js → chunk-WYO6CB5R-C6gy8rSd.js} +2 -2
- package/dist/assets/chunk-XXDRQBXY-BRxdfVCU.js +1 -0
- package/dist/assets/{chunk-YOTPTUD7-1-aKSu4o.js → chunk-YOTPTUD7-BK98yfl9.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-OJ8veMpK.js → chunk-ZGVPDNZ5-DFXAhwUT.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-SR_Nq_PP.js → chunk-ZIRB5QZD-Bbu6BiNC.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-Bo28fPi-.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-BOVN9wUz.js +1 -0
- package/dist/assets/{config-split-page-B55XD_ZY.js → config-split-page-DO1Oyb-r.js} +1 -1
- package/dist/assets/{confirm-dialog-BCCreI_f.js → confirm-dialog-CCae9Fr4.js} +1 -1
- package/dist/assets/{cose-bilkent-JH36ORCC-NjVgz2Bw.js → cose-bilkent-JH36ORCC-BV8KR4uF.js} +1 -1
- package/dist/assets/cynefin-VYW2F7L2-B7rF3JRp.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-B_17LDqD.js → cynefinDiagram-TSTJHNR4-Ckd6nU9t.js} +1 -1
- package/dist/assets/{dagre-CMe101gk.js → dagre-D_T-FW5i.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-qo8nLb3B.js → dagre-VKFMJZFB-CyDaQpD4.js} +1 -1
- package/dist/assets/desktop-update-config-XSV-DjJW.js +1 -0
- package/dist/assets/{diagram-FQU43EPY-Ba3XIklC.js → diagram-FQU43EPY-CghnwS0H.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-CG45TcUx.js → diagram-G47NLZAW-DK4DJ3Kx.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-2F2HrwV-.js → diagram-NH7WQ7WH-CUgDkZCJ.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-CXfWH9NZ.js → diagram-OA4YK3LP-vO2gyH6n.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-CH_4yepc.js → diagram-WEI45ONY-DbSBRDSr.js} +1 -1
- package/dist/assets/{dist-IRWcJpfm.js → dist-1N9UpL3c.js} +1 -1
- package/dist/assets/{dist-BYSUQaO2.js → dist-C-2H76Cv.js} +1 -1
- package/dist/assets/doc-browser-BHFCZIoL.js +1 -0
- package/dist/assets/{doc-browser-D8rNrWHk.js → doc-browser-CRlpqMwH.js} +1 -1
- package/dist/assets/{doc-browser-context-DjTbIbQc.js → doc-browser-context-C0Bns1J6.js} +1 -1
- package/dist/assets/{docx-preview-CoM4JK7_.js → docx-preview-DfxIm9IB.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-BwiG4Ea1.js → ebnfDiagram-CCIWWBDH-W7CAcK7r.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-BML3hpnQ.js → erDiagram-Q63AITRT-LA0JWL8-.js} +1 -1
- package/dist/assets/eventmodeling-45OFAUF4-DzQLXa3s.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-C81eexJZ.js +1 -0
- package/dist/assets/{form-actions-C8hazgNP.js → form-actions-CMxhPact.js} +1 -1
- package/dist/assets/{ganttDiagram-NO4QXBWP-80enfWbD.js → ganttDiagram-NO4QXBWP-_PiTPavJ.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-Dt3ZqpFD.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-CVLqXr-b.js → gitGraphDiagram-IHSO6WYX-DsRB1ZMU.js} +1 -1
- package/dist/assets/index-DdYOaKm7.js +109 -0
- package/dist/assets/index-DxCGKhAw.css +1 -0
- package/dist/assets/info-DKCQHKI2-CCCE7dXC.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-Dyvs2t0i.js → infoDiagram-FWYZ7A6U-wIRraYx5.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-sSnxDKfh.js → ishikawaDiagram-FXEZZL3T-CNzsrcrh.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-D22V71Mf.js → journeyDiagram-5HDEW3XC-Dy9huHxy.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-D3ds0p-g.js → kanban-definition-HUTT4EX6-BOCIN365.js} +1 -1
- package/dist/assets/{line-CbyFs065.js → line-BxsizOTs.js} +1 -1
- package/dist/assets/{linear-4DKtnZBS.js → linear-C_YHf92I.js} +1 -1
- package/dist/assets/loader-circle-B-UdXjl4.js +1 -0
- package/dist/assets/{map-CcZzEoz6.js → map-CobcjgZ8.js} +1 -1
- package/dist/assets/mcp-marketplace-page-BUIGtSda.js +1 -0
- package/dist/assets/mcp-marketplace-page-CStb8ml2.js +9 -0
- package/dist/assets/{mermaid-parser.core-DPmMOjXD.js → mermaid-parser.core-D7lu2RbA.js} +2 -2
- package/dist/assets/{mermaid.core-BSf-ddRa.js → mermaid.core-CbfW2Rk8.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-BUTwWPyx.js → mindmap-definition-LN4V7U3C-DUjGXlIC.js} +1 -1
- package/dist/assets/model-config-page-BkfUYm95.js +1 -0
- package/dist/assets/{navigation-link-kGAcL2N2.js → navigation-link-v3FaWcIr.js} +1 -1
- package/dist/assets/{ordinal-BgLYtOZE.js → ordinal-CjoUCHto.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-D19yoxFV.js +1 -0
- package/dist/assets/{pegDiagram-2B236MQR-BEu_ZBjc.js → pegDiagram-2B236MQR-BQY2DgiP.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-hMaJbLrn.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-CAwAwuBd.js → pieDiagram-ENE6RG2P-D18owe4D.js} +1 -1
- package/dist/assets/plus-Dw9QFnKr.js +1 -0
- package/dist/assets/{privacy-settings-page-v9LTFvJe.js → privacy-settings-page-CYM1Dxwo.js} +1 -1
- package/dist/assets/providers-config-page-fxL4I4bz.js +1 -0
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-CwE6F-_2.js → quadrantDiagram-ABIIQ3AL-B8F7YoTA.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-C8BkvScA.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-CozZOitC.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-BqIoFXFi.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-CD2e3dng.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-DoKlRUOF.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-xgLekU3B.js → railroadDiagram-RFXS5EU6-RU8GpxN5.js} +1 -1
- package/dist/assets/{react-Dwvp5yeX.js → react-Dlz_IxoP.js} +1 -1
- package/dist/assets/{refresh-cw-C_oj_h_s.js → refresh-cw-CK4I5UFv.js} +1 -1
- package/dist/assets/remote-B0pPgtC6.js +1 -0
- package/dist/assets/{requirementDiagram-TGXJPOKE-CyVUzEX5.js → requirementDiagram-TGXJPOKE-ubPOmmNi.js} +1 -1
- package/dist/assets/rotate-cw-Z48dmh13.js +1 -0
- package/dist/assets/runtime-config-page-C7vksFVD.js +1 -0
- package/dist/assets/{sankeyDiagram-HTMAVEWB-JK6bFmYB.js → sankeyDiagram-HTMAVEWB-8L_hXJWW.js} +1 -1
- package/dist/assets/{save-BZE6H02N.js → save-Bo37cIFb.js} +1 -1
- package/dist/assets/{search-C7Tj40kC.js → search-CZiEm7YD.js} +1 -1
- package/dist/assets/search-config-page-DKdEf7m9.js +1 -0
- package/dist/assets/{secrets-config-page-B__VLAEQ.js → secrets-config-page-COlMqSfL.js} +2 -2
- package/dist/assets/security-config-CitLihXA.js +1 -0
- package/dist/assets/{select-fZ5tifar.js → select-BACzapV3.js} +1 -1
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-BR5IokXV.js → sequenceDiagram-DBY2YBRQ-Dom6Qor5.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-SxG_YnMA.js → sizeCapture-X5ZJPWSS-cZcFSpLJ.js} +1 -1
- package/dist/assets/skeleton-B2PCAZJG.js +1 -0
- package/dist/assets/{src-vgz8E_-O.js → src-BE9E1xcR.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-DD4OoYhn.js → stateDiagram-2N3HPSRC-CHrpxmGO.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-b1pZQlDD.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-BWkFeyCT.js → swimlanes-5IMT3BWC-D6nJS2xQ.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-CowxgWVn.js +8 -0
- package/dist/assets/{tag-chip-CwYZcRoe.js → tag-chip-BnamTQVX.js} +1 -1
- package/dist/assets/{timeline-definition-FHXFAJF6-VTRPy6KA.js → timeline-definition-FHXFAJF6-DJNn-HQO.js} +1 -1
- package/dist/assets/treeView-QDETBFTQ-BQlYkJbz.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-DzTOd1bd.js +1 -0
- package/dist/assets/{vennDiagram-L72KCM5P-Bvk42Pek.js → vennDiagram-L72KCM5P-CCEzHoXt.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-D80jQc0y.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-DOFjx2s3.js → wardleyDiagram-EHGQE667-BhyVxVXt.js} +1 -1
- package/dist/assets/x-BzYEzkLA.js +1 -0
- package/dist/assets/{xychartDiagram-FW5EYKEG-DY5yRTUc.js → xychartDiagram-FW5EYKEG-CacW_246.js} +1 -1
- package/dist/index.html +70 -22
- package/index.html +49 -1
- package/package.json +8 -8
- package/src/app/index.tsx +1 -3
- package/src/app/managers/__tests__/viewport-layout.manager.test.ts +12 -0
- package/src/app/managers/viewport-layout.manager.ts +12 -0
- package/src/app/stores/viewport-layout.store.ts +23 -11
- package/src/features/apps/components/__tests__/app-marketplace-catalog.test.tsx +161 -0
- package/src/features/apps/components/app-marketplace-catalog.tsx +36 -7
- package/src/features/apps/components/app-marketplace-detail.tsx +29 -6
- package/src/features/apps/components/app-marketplace-dialog.tsx +71 -55
- package/src/features/apps/components/app-marketplace-operation.tsx +128 -16
- package/src/features/apps/components/app-packages-panel.tsx +1 -0
- package/src/features/apps/utils/app-marketplace-platform.utils.test.ts +59 -0
- package/src/features/apps/utils/app-marketplace-platform.utils.ts +33 -0
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +6 -0
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +6 -2
- package/src/features/chat/features/conversation/components/__tests__/session-queued-input-rows.test.tsx +46 -0
- package/src/features/chat/features/conversation/components/session-conversation-area.tsx +15 -2
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +5 -3
- package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +59 -5
- package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-controller.test.tsx +35 -1
- package/src/features/chat/features/conversation/hooks/__tests__/use-session-run-queue.test.tsx +25 -19
- package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +148 -134
- package/src/features/chat/features/conversation/hooks/use-session-pending-input-actions.ts +135 -0
- package/src/features/chat/features/conversation/hooks/use-session-run-queue.ts +19 -4
- package/src/features/chat/features/conversation/utils/__tests__/session-queued-input.utils.test.ts +52 -2
- package/src/features/chat/features/conversation/utils/session-queued-input.utils.ts +46 -5
- package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +1 -0
- package/src/features/chat/features/ncp/hooks/__tests__/use-hydrated-ncp-agent.test.tsx +102 -0
- package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-session-conversation.test.tsx +117 -1
- package/src/features/chat/features/ncp/hooks/use-ncp-session-conversation.ts +2 -2
- package/src/features/chat/features/ncp/hooks/use-ncp-session-message-history.ts +31 -81
- package/src/features/chat/features/ncp/hooks/use-ncp-session-seed-loader.ts +134 -0
- package/src/features/chat/features/session/utils/ncp-session-adapter.utils.ts +1 -6
- package/src/features/panel-apps/components/__tests__/panel-app-list-item.test.tsx +8 -0
- package/src/features/panel-apps/components/__tests__/panel-app-main-sidebar-nav.test.tsx +99 -13
- package/src/features/panel-apps/components/panel-app-main-sidebar-menu-item.tsx +4 -0
- package/src/features/panel-apps/components/panel-app-main-sidebar-nav.tsx +166 -31
- package/src/shared/lib/api/utils/ncp-attachments.utils.ts +8 -1
- package/src/shared/lib/api/utils/ncp-session.utils.ts +1 -0
- package/src/shared/lib/i18n/locales/en-US/chat.json +3 -0
- package/src/shared/lib/i18n/locales/en-US/doc-browser.json +11 -1
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +3 -0
- package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +11 -1
- package/src/vite-env.d.ts +9 -0
- package/dist/assets/architecture-TIHT7OUA-Bjp9jf0h.js +0 -1
- package/dist/assets/channel-5T3pdR-s.js +0 -1
- package/dist/assets/chat-page-BXu3hnOK.js +0 -1
- package/dist/assets/chunk-2Q5K7J3B-DTZ3tGfE.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-HLGIHQ6k.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-Dl0m6Ni-.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-DcDnzGNX.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-BKXKMzKM.js +0 -1
- package/dist/assets/cynefin-VYW2F7L2-BWg7U2UD.js +0 -1
- package/dist/assets/desktop-update-config-Blol-Umu.js +0 -1
- package/dist/assets/doc-browser-BExPq1Hk.js +0 -1
- package/dist/assets/eventmodeling-45OFAUF4-SB-J4tpq.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-BQ_u-eLM.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-DPxNwsFd.js +0 -1
- package/dist/assets/index-Btj8yN4T.css +0 -1
- package/dist/assets/index-CHcGqqBe.js +0 -109
- package/dist/assets/info-DKCQHKI2-DNlNGH90.js +0 -1
- package/dist/assets/loader-circle-C75DUmmm.js +0 -1
- package/dist/assets/mcp-marketplace-page-CIMRYgOY.js +0 -9
- package/dist/assets/mcp-marketplace-page-D2NlhG1k.js +0 -1
- package/dist/assets/model-config-page-ChR-ENjp.js +0 -1
- package/dist/assets/packet-7NZHBO7P-BpeiqkBZ.js +0 -1
- package/dist/assets/pie-RZYD4A2V-Cy1yxsPd.js +0 -1
- package/dist/assets/plus-TzSIMKWW.js +0 -1
- package/dist/assets/provider-scoped-model-input-DiSpKSk0.js +0 -1
- package/dist/assets/providers-config-page-BvXa03cp.js +0 -1
- package/dist/assets/radar-I7S5WNFK-CEcPKCj8.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-CW38eNDs.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-ByrylcXf.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-CNB6GwP-.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-x6hnqlBG.js +0 -1
- package/dist/assets/remote-BgYduCQR.js +0 -1
- package/dist/assets/rotate-cw-BT8HxlcB.js +0 -1
- package/dist/assets/runtime-config-page-BuYof2Ty.js +0 -1
- package/dist/assets/search-config-page-CQTJOsOf.js +0 -1
- package/dist/assets/security-config-CtJqaPVL.js +0 -1
- package/dist/assets/settings-2-BHGgNlOH.js +0 -1
- package/dist/assets/skeleton-CJLc1CWn.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-ZC6dFORv.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-CRkh51Im.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-Bw0DSCH7.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-DFWBFcfh.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-CoWturk0.js +0 -1
- package/dist/assets/x-BMl7cucN.js +0 -1
- /package/dist/assets/{array-NADKd9aU.js → array-COEOjKUv.js} +0 -0
- /package/dist/assets/{chunk-KEIR6QF5-BuyuzJJL.js → chunk-KEIR6QF5-D7oHAcry.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-D_B2ZRNt.js → chunk-Y2CYZVJY-08IUpgTP.js} +0 -0
- /package/dist/assets/{config-hints-BcfVUMij.js → config-hints-BoE41XDI.js} +0 -0
- /package/dist/assets/{cytoscape.esm-BANTlgza.js → cytoscape.esm-HifWufkp.js} +0 -0
- /package/dist/assets/{defaultLocale-C4_L0aEs.js → defaultLocale-CA-_SsC1.js} +0 -0
- /package/dist/assets/{dist-DAPEIJbz.js → dist-C60rvfy8.js} +0 -0
- /package/dist/assets/{graphlib-ChqXg0dI.js → graphlib-CGYCNsoJ.js} +0 -0
- /package/dist/assets/{host-capabilities-D9C4CBK5.js → host-capabilities-DPNRAjIj.js} +0 -0
- /package/dist/assets/{init-D8wZg9xq.js → init-C3plFVsG.js} +0 -0
- /package/dist/assets/{jszip.min-CkbBfwAQ.js → jszip.min-CeYs17Gn.js} +0 -0
- /package/dist/assets/{katex-TZJFa0J_.js → katex-DRThweSG.js} +0 -0
- /package/dist/assets/{middleware-B3k-TSmZ.js → middleware-D05fK5Sb.js} +0 -0
- /package/dist/assets/{path-DodfxcX7.js → path-BKtKxQ6Y.js} +0 -0
- /package/dist/assets/{rough.esm-CUaa1Rbe.js → rough.esm-DurL7-u7.js} +0 -0
- /package/dist/assets/{xlsx-CxByi7bR.js → xlsx-Sg8fZ6nH.js} +0 -0
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
-
import type { NcpMessage
|
|
3
|
-
import type { NcpConversationSeed } from "@nextclaw/ncp-react";
|
|
2
|
+
import type { NcpMessage } from "@nextclaw/ncp";
|
|
4
3
|
import {
|
|
5
4
|
fetchNcpSessionMessageDetail,
|
|
6
5
|
fetchNcpSessionMessages,
|
|
7
6
|
type SessionContextWindowView,
|
|
8
7
|
} from "@/shared/lib/api";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
contextWindow?: SessionContextWindowView | null;
|
|
14
|
-
deferredToolPayloads: Record<string, { cursor: string }>;
|
|
15
|
-
total: number;
|
|
16
|
-
pageInfo: NcpSessionMessagePageInfo;
|
|
17
|
-
};
|
|
8
|
+
import {
|
|
9
|
+
useNcpSessionSeedLoader,
|
|
10
|
+
type NcpConversationSeedWithContextWindow,
|
|
11
|
+
} from "@/features/chat/features/ncp/hooks/use-ncp-session-seed-loader";
|
|
18
12
|
|
|
19
13
|
export type SessionMessageToolPayloadState = "summary" | "loading" | "ready" | "error";
|
|
20
14
|
|
|
@@ -44,48 +38,6 @@ const EMPTY_SESSION_HISTORY_STATE: SessionHistoryState = {
|
|
|
44
38
|
messageDetailStates: {},
|
|
45
39
|
};
|
|
46
40
|
|
|
47
|
-
function isMissingNcpSessionError(error: unknown): boolean {
|
|
48
|
-
return (
|
|
49
|
-
error instanceof Error && error.message.includes("ncp session not found:")
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export async function fetchNcpSessionConversationSeed(
|
|
54
|
-
sessionId: string,
|
|
55
|
-
signal: AbortSignal,
|
|
56
|
-
messageLimit = DEFAULT_NCP_SESSION_MESSAGE_LIMIT,
|
|
57
|
-
): Promise<NcpConversationSeedWithContextWindow> {
|
|
58
|
-
signal.throwIfAborted();
|
|
59
|
-
try {
|
|
60
|
-
const response = await fetchNcpSessionMessages(sessionId, {
|
|
61
|
-
limit: messageLimit,
|
|
62
|
-
toolPayload: "summary",
|
|
63
|
-
signal,
|
|
64
|
-
});
|
|
65
|
-
signal.throwIfAborted();
|
|
66
|
-
return {
|
|
67
|
-
messages: response.messages,
|
|
68
|
-
status: response.status ?? "idle",
|
|
69
|
-
contextWindow: response.contextWindow ?? null,
|
|
70
|
-
deferredToolPayloads: response.deferredToolPayloads ?? {},
|
|
71
|
-
total: response.total,
|
|
72
|
-
pageInfo: response.pageInfo,
|
|
73
|
-
};
|
|
74
|
-
} catch (error) {
|
|
75
|
-
signal.throwIfAborted();
|
|
76
|
-
if (!isMissingNcpSessionError(error)) {
|
|
77
|
-
throw error;
|
|
78
|
-
}
|
|
79
|
-
return {
|
|
80
|
-
messages: [],
|
|
81
|
-
status: "idle",
|
|
82
|
-
total: 0,
|
|
83
|
-
deferredToolPayloads: {},
|
|
84
|
-
pageInfo: { startCursor: null, hasPreviousPage: false },
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
41
|
type UpdateSessionHistoryState = (
|
|
90
42
|
sessionId: string,
|
|
91
43
|
update: (current: SessionHistoryState) => SessionHistoryState,
|
|
@@ -194,35 +146,33 @@ export function useNcpSessionMessageHistory(params: {
|
|
|
194
146
|
sessionId,
|
|
195
147
|
updateHistoryState,
|
|
196
148
|
});
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
return { messages: seed.messages, status: seed.status };
|
|
221
|
-
},
|
|
222
|
-
[hydrationRetryVersion, messageLimit, updateHistoryState],
|
|
223
|
-
);
|
|
149
|
+
const onSeedLoaded = useCallback((
|
|
150
|
+
targetSessionId: string,
|
|
151
|
+
seed: NcpConversationSeedWithContextWindow,
|
|
152
|
+
) => {
|
|
153
|
+
updateHistoryState(targetSessionId, (current) => ({
|
|
154
|
+
...current,
|
|
155
|
+
contextWindow: seed.contextWindow ?? null,
|
|
156
|
+
deferredToolPayloads: seed.deferredToolPayloads,
|
|
157
|
+
messageDetails: {},
|
|
158
|
+
messageDetailStates: Object.fromEntries(
|
|
159
|
+
Object.keys(seed.deferredToolPayloads).map((messageId) => [messageId, "summary"]),
|
|
160
|
+
),
|
|
161
|
+
total: seed.total,
|
|
162
|
+
cursor: seed.pageInfo.startCursor,
|
|
163
|
+
hasPreviousPage: seed.pageInfo.hasPreviousPage,
|
|
164
|
+
error: null,
|
|
165
|
+
}));
|
|
166
|
+
}, [updateHistoryState]);
|
|
167
|
+
const loadSeed = useNcpSessionSeedLoader({
|
|
168
|
+
hydrationRetryVersion,
|
|
169
|
+
messageLimit,
|
|
170
|
+
onSeedLoaded,
|
|
171
|
+
});
|
|
224
172
|
const loadPreviousMessages = useCallback(
|
|
225
|
-
async (
|
|
173
|
+
async (
|
|
174
|
+
prependHistory: (messages: ReadonlyArray<NcpMessage>) => void,
|
|
175
|
+
) => {
|
|
226
176
|
const history = historyStateRef.current;
|
|
227
177
|
if (
|
|
228
178
|
!sessionId ||
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { useCallback, useRef } from "react";
|
|
2
|
+
import type { NcpSessionMessagePageInfo } from "@nextclaw/ncp";
|
|
3
|
+
import type { NcpConversationSeed } from "@nextclaw/ncp-react";
|
|
4
|
+
import {
|
|
5
|
+
fetchNcpSessionMessages,
|
|
6
|
+
type NcpSessionMessagesView,
|
|
7
|
+
type SessionContextWindowView,
|
|
8
|
+
} from "@/shared/lib/api";
|
|
9
|
+
|
|
10
|
+
export const DEFAULT_NCP_SESSION_MESSAGE_LIMIT = 20;
|
|
11
|
+
|
|
12
|
+
export type NcpConversationSeedWithContextWindow = NcpConversationSeed & {
|
|
13
|
+
contextWindow?: SessionContextWindowView | null;
|
|
14
|
+
deferredToolPayloads: Record<string, { cursor: string }>;
|
|
15
|
+
total: number;
|
|
16
|
+
pageInfo: NcpSessionMessagePageInfo;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function isMissingNcpSessionError(error: unknown): boolean {
|
|
20
|
+
return error instanceof Error && error.message.includes("ncp session not found:");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
24
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function waitForPrefetch<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {
|
|
28
|
+
signal.throwIfAborted();
|
|
29
|
+
return await new Promise<T>((resolve, reject) => {
|
|
30
|
+
const abort = () => reject(new DOMException("Aborted", "AbortError"));
|
|
31
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
32
|
+
void promise.then(resolve, reject).finally(() => {
|
|
33
|
+
signal.removeEventListener("abort", abort);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function takeInitialSessionMessagesPrefetch(params: {
|
|
39
|
+
sessionId: string;
|
|
40
|
+
messageLimit: number;
|
|
41
|
+
signal: AbortSignal;
|
|
42
|
+
}): Promise<NcpSessionMessagesView | null> {
|
|
43
|
+
const { messageLimit, sessionId, signal } = params;
|
|
44
|
+
const prefetch = window.__NEXTCLAW_INITIAL_SESSION_MESSAGES_PREFETCH__;
|
|
45
|
+
if (
|
|
46
|
+
!prefetch ||
|
|
47
|
+
prefetch.consumed ||
|
|
48
|
+
prefetch.sessionId !== sessionId ||
|
|
49
|
+
prefetch.limit !== messageLimit
|
|
50
|
+
) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
prefetch.consumed = true;
|
|
54
|
+
const result = await waitForPrefetch(prefetch.promise, signal);
|
|
55
|
+
signal.throwIfAborted();
|
|
56
|
+
if (!result?.responseOk || !isRecord(result.payload)) return null;
|
|
57
|
+
const { payload } = result;
|
|
58
|
+
if (payload.ok !== true || !isRecord(payload.data)) return null;
|
|
59
|
+
const { data } = payload;
|
|
60
|
+
if (
|
|
61
|
+
data.sessionId !== sessionId ||
|
|
62
|
+
!Array.isArray(data.messages) ||
|
|
63
|
+
!isRecord(data.pageInfo)
|
|
64
|
+
) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return data as NcpSessionMessagesView;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function fetchNcpSessionConversationSeed(
|
|
71
|
+
sessionId: string,
|
|
72
|
+
signal: AbortSignal,
|
|
73
|
+
messageLimit = DEFAULT_NCP_SESSION_MESSAGE_LIMIT,
|
|
74
|
+
payloadMode: "compact" | "standard" = "compact",
|
|
75
|
+
): Promise<NcpConversationSeedWithContextWindow> {
|
|
76
|
+
signal.throwIfAborted();
|
|
77
|
+
try {
|
|
78
|
+
const prefetchedResponse = payloadMode === "compact"
|
|
79
|
+
? await takeInitialSessionMessagesPrefetch({ sessionId, messageLimit, signal })
|
|
80
|
+
: null;
|
|
81
|
+
const response = prefetchedResponse ?? await fetchNcpSessionMessages(sessionId, {
|
|
82
|
+
limit: messageLimit,
|
|
83
|
+
toolPayload: "summary",
|
|
84
|
+
initialPayload: payloadMode === "compact" ? "compact" : undefined,
|
|
85
|
+
signal,
|
|
86
|
+
});
|
|
87
|
+
signal.throwIfAborted();
|
|
88
|
+
return {
|
|
89
|
+
messages: response.messages,
|
|
90
|
+
status: response.status ?? "idle",
|
|
91
|
+
contextWindow: response.contextWindow ?? null,
|
|
92
|
+
deferredToolPayloads: response.deferredToolPayloads ?? {},
|
|
93
|
+
total: response.total,
|
|
94
|
+
pageInfo: response.pageInfo,
|
|
95
|
+
};
|
|
96
|
+
} catch (error) {
|
|
97
|
+
signal.throwIfAborted();
|
|
98
|
+
if (!isMissingNcpSessionError(error)) throw error;
|
|
99
|
+
return {
|
|
100
|
+
messages: [],
|
|
101
|
+
status: "idle",
|
|
102
|
+
total: 0,
|
|
103
|
+
deferredToolPayloads: {},
|
|
104
|
+
pageInfo: { startCursor: null, hasPreviousPage: false },
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function useNcpSessionSeedLoader(params: {
|
|
110
|
+
hydrationRetryVersion: number;
|
|
111
|
+
messageLimit: number;
|
|
112
|
+
onSeedLoaded: (
|
|
113
|
+
sessionId: string,
|
|
114
|
+
seed: NcpConversationSeedWithContextWindow,
|
|
115
|
+
) => void;
|
|
116
|
+
}) {
|
|
117
|
+
const { hydrationRetryVersion, messageLimit, onSeedLoaded } = params;
|
|
118
|
+
const hydratedSessionsRef = useRef(new Set<string>());
|
|
119
|
+
return useCallback(async (sessionId: string, signal: AbortSignal) => {
|
|
120
|
+
void hydrationRetryVersion;
|
|
121
|
+
const payloadMode = hydratedSessionsRef.current.has(sessionId) ? "standard" : "compact";
|
|
122
|
+
const seed = await fetchNcpSessionConversationSeed(
|
|
123
|
+
sessionId,
|
|
124
|
+
signal,
|
|
125
|
+
messageLimit,
|
|
126
|
+
payloadMode,
|
|
127
|
+
);
|
|
128
|
+
if (!signal.aborted) {
|
|
129
|
+
hydratedSessionsRef.current.add(sessionId);
|
|
130
|
+
onSeedLoaded(sessionId, seed);
|
|
131
|
+
}
|
|
132
|
+
return { messages: seed.messages, status: seed.status };
|
|
133
|
+
}, [hydrationRetryVersion, messageLimit, onSeedLoaded]);
|
|
134
|
+
}
|
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
SessionEntryView,
|
|
8
8
|
ThinkingLevel
|
|
9
9
|
} from '@/shared/lib/api';
|
|
10
|
-
import {
|
|
10
|
+
import { buildNcpAssetContentUrl } from '@/shared/lib/api';
|
|
11
11
|
import {
|
|
12
12
|
getSessionProjectName,
|
|
13
13
|
normalizeSessionProjectRootValue,
|
|
@@ -29,11 +29,6 @@ const SESSION_ACTIVITY_PREVIEW_STATUS_KIND_SET = new Set<NonNullable<SessionActi
|
|
|
29
29
|
'run-interrupted'
|
|
30
30
|
]);
|
|
31
31
|
|
|
32
|
-
function buildNcpAssetContentUrl(assetUri: string): string {
|
|
33
|
-
const query = new URLSearchParams({ uri: assetUri });
|
|
34
|
-
return `${API_BASE}/api/ncp/assets/content?${query.toString()}`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
32
|
function readOptionalString(value: unknown): string | null {
|
|
38
33
|
if (typeof value !== 'string') {
|
|
39
34
|
return null;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { render, screen } from '@testing-library/react';
|
|
2
2
|
import userEvent from '@testing-library/user-event';
|
|
3
3
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { viewportLayoutManager } from '@/app/managers/viewport-layout.manager';
|
|
5
|
+
import { useViewportLayoutStore } from '@/app/stores/viewport-layout.store';
|
|
4
6
|
import { PanelAppListItem } from '@/features/panel-apps/components/panel-app-list-item';
|
|
5
7
|
|
|
6
8
|
const mainSidebarMutation = vi.hoisted(() => ({
|
|
@@ -32,6 +34,8 @@ const baseEntry = {
|
|
|
32
34
|
|
|
33
35
|
describe('PanelAppListItem', () => {
|
|
34
36
|
beforeEach(() => {
|
|
37
|
+
window.localStorage.clear();
|
|
38
|
+
viewportLayoutManager.resetForTests();
|
|
35
39
|
mainSidebarMutation.isPending = false;
|
|
36
40
|
mainSidebarMutation.mutate.mockReset();
|
|
37
41
|
});
|
|
@@ -79,6 +83,7 @@ describe('PanelAppListItem', () => {
|
|
|
79
83
|
|
|
80
84
|
it('keeps main-sidebar placement in the low-frequency more-actions menu', async () => {
|
|
81
85
|
const user = userEvent.setup();
|
|
86
|
+
viewportLayoutManager.setMainSidebarAppGroupCollapsed(true);
|
|
82
87
|
const { rerender } = render(
|
|
83
88
|
<PanelAppListItem
|
|
84
89
|
deletePending={false}
|
|
@@ -97,6 +102,9 @@ describe('PanelAppListItem', () => {
|
|
|
97
102
|
id: 'demo',
|
|
98
103
|
preferences: { mainSidebar: true },
|
|
99
104
|
});
|
|
105
|
+
expect(
|
|
106
|
+
useViewportLayoutStore.getState().isMainSidebarAppGroupCollapsed,
|
|
107
|
+
).toBe(false);
|
|
100
108
|
|
|
101
109
|
rerender(
|
|
102
110
|
<PanelAppListItem
|
|
@@ -2,6 +2,8 @@ import { render, screen } from "@testing-library/react";
|
|
|
2
2
|
import userEvent from "@testing-library/user-event";
|
|
3
3
|
import { MemoryRouter } from "react-router-dom";
|
|
4
4
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { viewportLayoutManager } from "@/app/managers/viewport-layout.manager";
|
|
6
|
+
import { useViewportLayoutStore } from "@/app/stores/viewport-layout.store";
|
|
5
7
|
import {
|
|
6
8
|
getMainSidebarPanelApps,
|
|
7
9
|
PanelAppMainSidebarNav,
|
|
@@ -21,7 +23,9 @@ vi.mock("@/features/panel-apps/hooks/use-panel-apps", () => ({
|
|
|
21
23
|
}),
|
|
22
24
|
}));
|
|
23
25
|
|
|
24
|
-
function createEntry(
|
|
26
|
+
function createEntry(
|
|
27
|
+
overrides: Partial<PanelAppEntryView> = {},
|
|
28
|
+
): PanelAppEntryView {
|
|
25
29
|
return {
|
|
26
30
|
appId: "demo",
|
|
27
31
|
clientDeclared: false,
|
|
@@ -43,6 +47,8 @@ function createEntry(overrides: Partial<PanelAppEntryView> = {}): PanelAppEntryV
|
|
|
43
47
|
|
|
44
48
|
describe("PanelAppMainSidebarNav", () => {
|
|
45
49
|
beforeEach(() => {
|
|
50
|
+
window.localStorage.clear();
|
|
51
|
+
viewportLayoutManager.resetForTests();
|
|
46
52
|
mocks.entries = [];
|
|
47
53
|
mocks.mutate.mockReset();
|
|
48
54
|
});
|
|
@@ -50,19 +56,32 @@ describe("PanelAppMainSidebarNav", () => {
|
|
|
50
56
|
it("projects only manually added apps in persisted order", () => {
|
|
51
57
|
const entries = [
|
|
52
58
|
createEntry({ appId: "hidden", title: "Hidden" }),
|
|
53
|
-
createEntry({
|
|
54
|
-
|
|
59
|
+
createEntry({
|
|
60
|
+
appId: "second",
|
|
61
|
+
mainSidebar: true,
|
|
62
|
+
mainSidebarOrder: 1,
|
|
63
|
+
title: "Second",
|
|
64
|
+
}),
|
|
65
|
+
createEntry({
|
|
66
|
+
appId: "first",
|
|
67
|
+
mainSidebar: true,
|
|
68
|
+
mainSidebarOrder: 0,
|
|
69
|
+
title: "First",
|
|
70
|
+
}),
|
|
55
71
|
];
|
|
56
72
|
|
|
57
|
-
expect(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
]);
|
|
73
|
+
expect(
|
|
74
|
+
getMainSidebarPanelApps(entries).map((entry) => entry.appId),
|
|
75
|
+
).toEqual(["first", "second"]);
|
|
61
76
|
});
|
|
62
77
|
|
|
63
78
|
it("renders stable app routes and hides unbound apps", () => {
|
|
64
79
|
mocks.entries = [
|
|
65
|
-
createEntry({
|
|
80
|
+
createEntry({
|
|
81
|
+
appId: "publisher.todo",
|
|
82
|
+
mainSidebar: true,
|
|
83
|
+
title: "Todo",
|
|
84
|
+
}),
|
|
66
85
|
createEntry({ appId: "hidden", title: "Hidden" }),
|
|
67
86
|
];
|
|
68
87
|
|
|
@@ -76,12 +95,62 @@ describe("PanelAppMainSidebarNav", () => {
|
|
|
76
95
|
expect(link.getAttribute("href")).toBe("/apps/panel/publisher.todo");
|
|
77
96
|
expect(link.getAttribute("aria-current")).toBe("page");
|
|
78
97
|
expect(screen.queryByText("Hidden")).toBeNull();
|
|
98
|
+
const groupButton = screen.getByRole("button", { name: "Collapse apps" });
|
|
99
|
+
expect(groupButton.getAttribute("aria-expanded")).toBe("true");
|
|
100
|
+
expect(groupButton.className).toContain("text-[13px]");
|
|
101
|
+
expect(groupButton.className).toContain("font-medium");
|
|
102
|
+
expect(groupButton.className).not.toContain("text-[11px]");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("collapses the ordered app group and persists the device layout preference", async () => {
|
|
106
|
+
const user = userEvent.setup();
|
|
107
|
+
mocks.entries = [
|
|
108
|
+
createEntry({
|
|
109
|
+
appId: "first",
|
|
110
|
+
mainSidebar: true,
|
|
111
|
+
mainSidebarOrder: 0,
|
|
112
|
+
title: "First",
|
|
113
|
+
}),
|
|
114
|
+
createEntry({
|
|
115
|
+
appId: "second",
|
|
116
|
+
mainSidebar: true,
|
|
117
|
+
mainSidebarOrder: 1,
|
|
118
|
+
title: "Second",
|
|
119
|
+
}),
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
render(
|
|
123
|
+
<MemoryRouter>
|
|
124
|
+
<PanelAppMainSidebarNav isCollapsed={false} />
|
|
125
|
+
</MemoryRouter>,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
await user.click(screen.getByRole("button", { name: "Collapse apps" }));
|
|
129
|
+
|
|
130
|
+
expect(screen.queryByRole("link", { name: "First" })).toBeNull();
|
|
131
|
+
expect(screen.queryByRole("link", { name: "Second" })).toBeNull();
|
|
132
|
+
expect(
|
|
133
|
+
screen
|
|
134
|
+
.getByRole("button", { name: "Expand apps" })
|
|
135
|
+
.getAttribute("aria-expanded"),
|
|
136
|
+
).toBe("false");
|
|
137
|
+
expect(
|
|
138
|
+
useViewportLayoutStore.getState().isMainSidebarAppGroupCollapsed,
|
|
139
|
+
).toBe(true);
|
|
140
|
+
const persisted = JSON.parse(
|
|
141
|
+
window.localStorage.getItem("nextclaw.app.viewport-layout") ?? "{}",
|
|
142
|
+
) as { state?: { isMainSidebarAppGroupCollapsed?: boolean } };
|
|
143
|
+
expect(persisted.state?.isMainSidebarAppGroupCollapsed).toBe(true);
|
|
79
144
|
});
|
|
80
145
|
|
|
81
146
|
it("removes an expanded entry from its hover actions without nesting the button in the link", async () => {
|
|
82
147
|
const user = userEvent.setup();
|
|
83
148
|
mocks.entries = [
|
|
84
|
-
createEntry({
|
|
149
|
+
createEntry({
|
|
150
|
+
appId: "publisher.todo",
|
|
151
|
+
mainSidebar: true,
|
|
152
|
+
title: "Todo",
|
|
153
|
+
}),
|
|
85
154
|
];
|
|
86
155
|
|
|
87
156
|
render(
|
|
@@ -98,7 +167,9 @@ describe("PanelAppMainSidebarNav", () => {
|
|
|
98
167
|
expect(menuButton.className).toContain("group-hover/panel-app:opacity-100");
|
|
99
168
|
|
|
100
169
|
await user.click(menuButton);
|
|
101
|
-
await user.click(
|
|
170
|
+
await user.click(
|
|
171
|
+
screen.getByRole("button", { name: "Remove from main sidebar" }),
|
|
172
|
+
);
|
|
102
173
|
|
|
103
174
|
expect(mocks.mutate).toHaveBeenCalledWith({
|
|
104
175
|
id: "demo",
|
|
@@ -107,9 +178,19 @@ describe("PanelAppMainSidebarNav", () => {
|
|
|
107
178
|
expect(link.getAttribute("aria-current")).toBe("page");
|
|
108
179
|
});
|
|
109
180
|
|
|
110
|
-
it("
|
|
181
|
+
it("aggregates collapsed-rail apps behind one navigation menu", async () => {
|
|
182
|
+
const user = userEvent.setup();
|
|
111
183
|
mocks.entries = [
|
|
112
|
-
createEntry({
|
|
184
|
+
createEntry({
|
|
185
|
+
appId: "publisher.todo",
|
|
186
|
+
mainSidebar: true,
|
|
187
|
+
title: "Todo",
|
|
188
|
+
}),
|
|
189
|
+
createEntry({
|
|
190
|
+
appId: "publisher.notes",
|
|
191
|
+
mainSidebar: true,
|
|
192
|
+
title: "Notes",
|
|
193
|
+
}),
|
|
113
194
|
];
|
|
114
195
|
|
|
115
196
|
render(
|
|
@@ -118,8 +199,13 @@ describe("PanelAppMainSidebarNav", () => {
|
|
|
118
199
|
</MemoryRouter>,
|
|
119
200
|
);
|
|
120
201
|
|
|
202
|
+
expect(screen.queryByRole("link", { name: "Todo" })).toBeNull();
|
|
203
|
+
expect(
|
|
204
|
+
screen.queryByRole("button", { name: "More panel app actions: Todo" }),
|
|
205
|
+
).toBeNull();
|
|
206
|
+
await user.click(screen.getByRole("button", { name: "Apps" }));
|
|
121
207
|
expect(screen.getByRole("link", { name: "Todo" })).toBeTruthy();
|
|
122
|
-
expect(screen.
|
|
208
|
+
expect(screen.getByRole("link", { name: "Notes" })).toBeTruthy();
|
|
123
209
|
});
|
|
124
210
|
|
|
125
211
|
it("renders no section when no app was manually added", () => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PanelLeft, PanelLeftDashed } from 'lucide-react';
|
|
2
|
+
import { viewportLayoutManager } from '@/app/managers/viewport-layout.manager';
|
|
2
3
|
import { useUpdatePanelAppPreferences } from '@/features/panel-apps/hooks/use-panel-apps';
|
|
3
4
|
import type { PanelAppEntryView } from '@/shared/lib/api';
|
|
4
5
|
import { t } from '@/shared/lib/i18n';
|
|
@@ -24,6 +25,9 @@ export function PanelAppMainSidebarMenuItem({
|
|
|
24
25
|
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 disabled:cursor-not-allowed disabled:opacity-50"
|
|
25
26
|
onClick={() => {
|
|
26
27
|
onSelect?.();
|
|
28
|
+
if (!entry.mainSidebar) {
|
|
29
|
+
viewportLayoutManager.setMainSidebarAppGroupCollapsed(false);
|
|
30
|
+
}
|
|
27
31
|
updatePreferences.mutate({
|
|
28
32
|
id: entry.id,
|
|
29
33
|
preferences: { mainSidebar: !entry.mainSidebar },
|