@nextclaw/ui 0.26.4 → 0.27.0
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 +63 -0
- package/dist/.vite/manifest.json +1271 -1227
- package/dist/assets/{abnfDiagram-VRR7QNED-Dcw10Yt1.js → abnfDiagram-VRR7QNED-DmeCRAkd.js} +1 -1
- package/dist/assets/account-panel-BYxGT4m4.js +1 -0
- package/dist/assets/{aiden0z-pptx-renderer.es--oNqetPA.js → aiden0z-pptx-renderer.es-ChX5DHqP.js} +1 -1
- package/dist/assets/api-CG22BskB.js +20 -0
- package/dist/assets/app-presenter-provider-CJFjhVYI.js +28 -0
- package/dist/assets/app-presenter-provider-D3BuuOyZ.css +1 -0
- package/dist/assets/appearance-settings-page-BcXr0vHp.js +1 -0
- package/dist/assets/{arc-DBRedCax.js → arc-Cu6Ols44.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-CLjV_xu4.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-Dufhtuv-.js → architectureDiagram-ZJ3FMSHR-DrNB0eLE.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-BUk0vtJ7.js → blockDiagram-677ZJIJ3-08rHt6DJ.js} +1 -1
- package/dist/assets/{book-open-CmRdT3N1.js → book-open-ClbJmmxP.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-CxDcVE9p.js → c4Diagram-LMCZKHZV-CCVgRG-u.js} +1 -1
- package/dist/assets/{card-CdRBL1E0.js → card-BdC01NFF.js} +1 -1
- package/dist/assets/channel-BgpbPyEH.js +1 -0
- package/dist/assets/channels-list-page-BrIvJlop.js +8 -0
- package/dist/assets/chunk-2Q5K7J3B-DjhMPqAC.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-DSF3KElA.js → chunk-32BRIVSS-BeCaI-JN.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-Costxzr3.js → chunk-52WLFC77-ZXIcYPYs.js} +1 -1
- package/dist/assets/{chunk-5FCAYU7R-rhqzGGZo.js → chunk-5FCAYU7R-DDwTPcy8.js} +1 -1
- package/dist/assets/{chunk-5HE753X5-BsEsmIao.js → chunk-5HE753X5-WygrMYPL.js} +1 -1
- package/dist/assets/{chunk-5JV3BV7I-Dqw_DCoN.js → chunk-5JV3BV7I-o8T3KZgk.js} +1 -1
- package/dist/assets/{chunk-5TONJI2A-Cft82fp8.js → chunk-5TONJI2A-BKFbUT7J.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-DqNHn9Dl.js → chunk-5VM5RSS4-DYxCRV86.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-A5SBEMYY.js → chunk-7BUUIJ7U-CvSeJlKZ.js} +1 -1
- package/dist/assets/{chunk-BIQX33UG-1Ng3mTrH.js → chunk-BIQX33UG-BhH3RHCY.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-DRJEy8ZI.js → chunk-C7G6YPKG-BTL0-xL3.js} +1 -1
- package/dist/assets/{chunk-CQNSW5MT-Bydv_J3J.js → chunk-CQNSW5MT-DWAU4QaD.js} +1 -1
- package/dist/assets/{chunk-CYSBUYHQ-HkMIg12u.js → chunk-CYSBUYHQ-B7ZBMXTx.js} +1 -1
- package/dist/assets/{chunk-EMLP6XTP-C5ndDvm3.js → chunk-EMLP6XTP-D92HvnHE.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-DzeloZRo.js → chunk-EX3LRPZG-DfOGKwW8.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-n_2_CLTQ.js → chunk-FWX5IMBZ-DUuJUrXJ.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-kx_slvu3.js → chunk-HOUHSVGY-i3MDyUY5.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-sQLMURqL.js → chunk-ICXQ74PX-F_pmNX6t.js} +1 -1
- package/dist/assets/{chunk-JG7HCLWE-CMUn5Elc.js → chunk-JG7HCLWE-DygOelrU.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-Cra3s-Uk.js → chunk-JWPE2WC7-BpiZMeRl.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-umcrg5Bi.js → chunk-MOJQB5TN-CV10sB1I.js} +1 -1
- package/dist/assets/{chunk-MOZMSUNE-BnljD1ig.js → chunk-MOZMSUNE-Cf1WZNm0.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-BXx5pQjU.js → chunk-OGEWGWER-DuSw54VR.js} +1 -1
- package/dist/assets/{chunk-OSBZ3O6U-D-1qfdWu.js → chunk-OSBZ3O6U-_rt_XKSZ.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-DLzX78LC.js → chunk-PUDLZKDR-BFPaAGNW.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-DTK-rtW6.js → chunk-Q4XR5HBZ-GE0v_E5y.js} +1 -1
- package/dist/assets/{chunk-QBLGF6JB-CsFeIGfr.js → chunk-QBLGF6JB-BK_FpnlJ.js} +1 -1
- package/dist/assets/{chunk-R7FJI6CG-4xNYUeng.js → chunk-R7FJI6CG-CpYh6rGo.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-DJiHiTE5.js → chunk-RYQCIY6F-htnxL_Cl.js} +1 -1
- package/dist/assets/{chunk-U6XO7XAA-BVYkauHz.js → chunk-U6XO7XAA-wDbE4BZ7.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-BsazE8cS.js → chunk-V7JOEXUC-DDRSVFTB.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-GYimZYx9.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-7RoZQffO.js → chunk-VR4S4FIN-COdhHR1o.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-DEuS6N1R.js → chunk-WYO6CB5R-DPDGhyF6.js} +3 -3
- package/dist/assets/chunk-XXDRQBXY-KKCf0HV5.js +1 -0
- package/dist/assets/{chunk-YOTPTUD7-9KBrosZL.js → chunk-YOTPTUD7-D8ir9Nx5.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-IYgN9f5A.js → chunk-ZGVPDNZ5-BuNKD836.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-BUo0-zcp.js → chunk-ZIRB5QZD-DyHzq8jH.js} +1 -1
- package/dist/assets/{circle-dashed-HOgt3gIJ.js → circle-dashed-nDaMRmP-.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-iRMPRR8M.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-BguFy_wj.js +1 -0
- package/dist/assets/{client-DKKbdJ6Q.js → client-DlFB5dW5.js} +1 -1
- package/dist/assets/config-split-page-C06fU9OQ.js +1 -0
- package/dist/assets/confirm-dialog-DpcmlXhd.js +1 -0
- package/dist/assets/{app-presenter-provider-jNGlmBLe.css → context-menu-DEcVZfaU.css} +1 -1
- package/dist/assets/context-menu-DKIEaY7f.js +211 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-DhqbC1fR.js → cose-bilkent-JH36ORCC-B1I1_P6a.js} +1 -1
- package/dist/assets/{createLucideIcon-DE0sB9Nu.js → createLucideIcon-Lnt-4LMC.js} +1 -1
- package/dist/assets/cynefin-VYW2F7L2-CtbjXuCW.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-C-TBRi5V.js → cynefinDiagram-TSTJHNR4-DcOnhnCo.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-BmafJymp.js → dagre-VKFMJZFB-hAX89lg3.js} +1 -1
- package/dist/assets/{dagre-CrgsRasE.js → dagre-nSYhf9yY.js} +1 -1
- package/dist/assets/{desktop-capabilities-page-B9-B9k1A.js → desktop-capabilities-page-DPORyZAu.js} +1 -1
- package/dist/assets/desktop-update-config-BMTeWZmn.js +1 -0
- package/dist/assets/{diagram-FQU43EPY-BoOMwa6D.js → diagram-FQU43EPY-C1mRMD2k.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-Le7N6Uym.js → diagram-G47NLZAW-D2XBn5al.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-Fbpj3-MO.js → diagram-NH7WQ7WH-3LmRsmkC.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-D3QuGGuu.js → diagram-OA4YK3LP-CFWn-osC.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-Cxu1uiN6.js → diagram-WEI45ONY-BqNRbUvU.js} +1 -1
- package/dist/assets/dialog-BNXSPMX_.js +1 -0
- package/dist/assets/dist-Cuiqqp1O.js +41 -0
- package/dist/assets/doc-browser-CDEapjmj.js +1 -0
- package/dist/assets/{doc-browser-context-ClLgMbxd.js → doc-browser-context-0QDWYorh.js} +1 -1
- package/dist/assets/{docx-preview-CkU2psnd.js → docx-preview-CunAATyC.js} +1 -1
- package/dist/assets/{download-CKqS1Ksj.js → download-f_sPcoLZ.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-CCAjuQM6.js → ebnfDiagram-CCIWWBDH-CYb8IwqD.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-BuzUAq-d.js → erDiagram-Q63AITRT-H47mUoeK.js} +1 -1
- package/dist/assets/eventmodeling-45OFAUF4-Djd6id_u.js +1 -0
- package/dist/assets/extensions-B-0xQz3L.js +1 -0
- package/dist/assets/external-link-CbVlnlNy.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-DUrsM_ZL.js +1 -0
- package/dist/assets/{form-actions-CCoxz33Q.js → form-actions-BoTqELHB.js} +1 -1
- package/dist/assets/{ganttDiagram-NO4QXBWP-cJmWVY8F.js → ganttDiagram-NO4QXBWP-hSX45zfV.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-CU6P_2Cm.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-F58o-vtP.js → gitGraphDiagram-IHSO6WYX-Br0UW2qg.js} +1 -1
- package/dist/assets/{i18n-OGmF0Ws_.js → i18n-B0V5NkFj.js} +2 -2
- package/dist/assets/inbox-Bna8iUy0.js +1 -0
- package/dist/assets/info-DKCQHKI2-Bj2P_7RC.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-Gt59b83C.js → infoDiagram-FWYZ7A6U-DQmP_67w.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-1u4IAj1I.js → ishikawaDiagram-FXEZZL3T-BHAV2oes.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-CCQsfV-5.js → journeyDiagram-5HDEW3XC-CFHax4_d.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-vlB6O_Zn.js → kanban-definition-HUTT4EX6-B4ZA9rp5.js} +1 -1
- package/dist/assets/katex-BprZ-Wwb.js +1 -0
- package/dist/assets/{keyboard-shortcuts-settings-page-D8rosOVh.js → keyboard-shortcuts-settings-page-BluWKrSo.js} +1 -1
- package/dist/assets/{line-D_bHubTL.js → line-BboM0HLF.js} +1 -1
- package/dist/assets/{linear-ChlwuS5y.js → linear-4K_M1oYM.js} +1 -1
- package/dist/assets/login-page-BMHW0Hh0.js +1 -0
- package/dist/assets/{login-page-BT3GV3Sb.js → login-page-JNr5JCEw.js} +1 -1
- package/dist/assets/main-BCX_Untx.css +1 -0
- package/dist/assets/main-C5kbmGUV.js +2 -0
- package/dist/assets/main-i18n-catalog.config-DO4wNT7T.js +1 -0
- package/dist/assets/{map-oGHTsIu8.js → map-26GpO1wn.js} +1 -1
- package/dist/assets/mcp-marketplace-page-CV-PHKTN.js +1 -0
- package/dist/assets/{mermaid-parser.core-CuRe1ZG4.js → mermaid-parser.core-BTJFnvRC.js} +2 -2
- package/dist/assets/{mermaid.core-u4YCFKRf.js → mermaid.core-B7ufoXgq.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-DeJAQYTu.js → mindmap-definition-LN4V7U3C-BHyru6KE.js} +1 -1
- package/dist/assets/model-config-page-C-wbM6Fe.js +1 -0
- package/dist/assets/{navigation-link-DC-Pku0Y.js → navigation-link-DFLSVIut.js} +2 -2
- package/dist/assets/{ordinal-C6JFfkKN.js → ordinal-BqFe2ePF.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-ti5ge2jr.js +1 -0
- package/dist/assets/panel-app-CSQmm_7E.js +1 -0
- package/dist/assets/panel-app-i18n-catalog.config-Bo52dPuF.js +1 -0
- package/dist/assets/panelStandalone-PuuMF65O.js +2 -0
- package/dist/assets/panelStandalone-XRlWxbRS.css +1 -0
- package/dist/assets/{pegDiagram-2B236MQR-nVMkxShH.js → pegDiagram-2B236MQR-PVTatU5j.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-Bnep8TyV.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-8aUH44QZ.js → pieDiagram-ENE6RG2P-CGc-QCc7.js} +1 -1
- package/dist/assets/plus-CywSlIbG.js +1 -0
- package/dist/assets/privacy-settings-page-CPdEiouE.js +1 -0
- package/dist/assets/projects-D_cd_t4G.js +1 -0
- package/dist/assets/provider-models-XRArsply.js +1 -0
- package/dist/assets/provider-scoped-model-input-C8JI-hus.js +1 -0
- package/dist/assets/providers-config-page-fyMlVgvq.js +1 -0
- package/dist/assets/puzzle-Bk3ud1KI.js +1 -0
- package/dist/assets/pwa-Cx6Fnox4.js +1 -0
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-EY8hpFv8.js → quadrantDiagram-ABIIQ3AL-DGL36riv.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-BYg-icAP.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-_CHO-Fi1.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-hbQDevHe.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-v4RZkOfi.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-bC9BqkI5.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-CNhcIeji.js → railroadDiagram-RFXS5EU6-CyNwvhSb.js} +1 -1
- package/dist/assets/{refresh-cw-BG8VfcdA.js → refresh-cw-Ca2napNx.js} +1 -1
- package/dist/assets/remote-D5MBQNZE.js +1 -0
- package/dist/assets/{requirementDiagram-TGXJPOKE-D8Dcs-Rt.js → requirementDiagram-TGXJPOKE-C31NMKJ0.js} +1 -1
- package/dist/assets/{rotate-cw-DPEegUU2.js → rotate-cw-DXg7sNUE.js} +1 -1
- package/dist/assets/runtime-config-page--ivCxBT4.js +1 -0
- package/dist/assets/{sankeyDiagram-HTMAVEWB-HTrb6aa-.js → sankeyDiagram-HTMAVEWB-CwrQ_7PA.js} +1 -1
- package/dist/assets/{save-CPlctBjT.js → save-DNigywZ9.js} +1 -1
- package/dist/assets/search-U9C0oTQJ.js +1 -0
- package/dist/assets/search-config-page-Bdx_RR1q.js +1 -0
- package/dist/assets/secrets-config-page-CvMIcsfJ.js +3 -0
- package/dist/assets/security-config-CQmMqQ8v.js +1 -0
- package/dist/assets/select-DxwDeKUR.js +1 -0
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-6f_4X16Y.js → sequenceDiagram-DBY2YBRQ-EFD482_y.js} +1 -1
- package/dist/assets/service-apps-panel-CiYO1Be4.js +1 -0
- package/dist/assets/{settings-2-CrGx9_De.js → settings-2-BrBUdRoY.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-Ck9rsuwL.js → sizeCapture-X5ZJPWSS-TDvULTE1.js} +1 -1
- package/dist/assets/{src-C8AUg09O.js → src-CI2AvEMj.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-Cm33MLHu.js → stateDiagram-2N3HPSRC-JdPsIYHo.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-4_aAQfB_.js +1 -0
- package/dist/assets/{status-dot-Cb8ewlUr.js → status-dot-BbGsrkIX.js} +1 -1
- package/dist/assets/{swimlanes-5IMT3BWC-B107vmvM.js → swimlanes-5IMT3BWC-BnxpKeK_.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-wCqfwsw-.js +8 -0
- package/dist/assets/tag-chip-BDbxcf6P.js +1 -0
- package/dist/assets/theme-provider-D98XGa-c.js +1 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-CJEoAj33.js → timeline-definition-FHXFAJF6-2IL22-uC.js} +1 -1
- package/dist/assets/trash-2-DwSkRfeB.js +1 -0
- package/dist/assets/treeView-QDETBFTQ-BAyOb14Z.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-DgPDM0zS.js +1 -0
- package/dist/assets/{use-config-BM5jC65L.js → use-config-D3cNzk2k.js} +1 -1
- package/dist/assets/{use-desktop-capabilities-ezKJwKqg.js → use-desktop-capabilities-D7odgaTB.js} +1 -1
- package/dist/assets/use-viewport-layout-BANU5E1t.js +1 -0
- package/dist/assets/{vennDiagram-L72KCM5P-DzsUHk5I.js → vennDiagram-L72KCM5P-Cjf6n5Va.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-eCElh8z5.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-1NfFs5ua.js → wardleyDiagram-EHGQE667-yv4qKbBO.js} +1 -1
- package/dist/assets/x-BqGj6_Vq.js +1 -0
- package/dist/assets/{xychartDiagram-FW5EYKEG-Ci8AI3Qo.js → xychartDiagram-FW5EYKEG-Bmp8Ck8X.js} +1 -1
- package/dist/index.html +43 -106
- package/dist/panel-standalone.html +18 -12
- package/index.html +15 -66
- package/package.json +5 -5
- package/src/app/configs/__tests__/app-navigation.config.test.ts +4 -2
- package/src/app/configs/app-navigation.config.ts +7 -2
- package/src/app/styles/design-system.css +85 -1
- package/src/app/styles/island-theme.css +8 -6
- package/src/features/agents/components/agent-details-dialog.tsx +5 -3
- package/src/features/app-data/components/app-retained-data-section.tsx +2 -2
- package/src/features/apps/components/__tests__/app-marketplace-catalog.test.tsx +2 -2
- package/src/features/apps/components/__tests__/app-packages-panel.test.tsx +94 -23
- package/src/features/apps/components/__tests__/apps-panel.test.tsx +5 -3
- package/src/features/apps/components/app-document-access-section.tsx +17 -14
- package/src/features/apps/components/app-marketplace-catalog.tsx +66 -39
- package/src/features/apps/components/app-marketplace-cover.tsx +5 -2
- package/src/features/apps/components/app-marketplace-detail.tsx +9 -6
- package/src/features/apps/components/app-marketplace-operation.tsx +8 -3
- package/src/features/apps/components/app-marketplace-panel.tsx +168 -0
- package/src/features/apps/components/app-package-card.tsx +224 -147
- package/src/features/apps/components/app-package-details-dialog.tsx +103 -0
- package/src/features/apps/components/app-packages-panel.tsx +159 -144
- package/src/features/apps/components/apps-panel.tsx +40 -11
- package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +1 -1
- package/src/features/chat/components/conversation/chat-conversation-header.tsx +1 -1
- package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +2 -2
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +9 -7
- package/src/features/chat/features/conversation/components/floating-session-conversation.tsx +2 -3
- package/src/features/chat/features/conversation/components/session-conversation-area.tsx +1 -0
- package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-input-state.test.tsx +33 -0
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +0 -2
- package/src/features/chat/features/message/utils/__tests__/chat-message-process-summary.utils.test.ts +4 -6
- package/src/features/chat/features/message/utils/chat-message-execution-summary.utils.ts +3 -0
- package/src/features/chat/features/message/utils/chat-message-process-summary.utils.ts +2 -10
- package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +2 -0
- package/src/features/chat/features/message/utils/chat-message-trigger-details.utils.ts +3 -0
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +2 -1
- package/src/features/chat/features/session/components/session-header/chat-session-metadata-dialog.tsx +1 -1
- package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +2 -2
- package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +31 -6
- package/src/features/chat/features/welcome/components/chat-conversation-welcome.tsx +13 -1
- package/src/features/chat/features/welcome/components/chat-welcome-agent-picker.tsx +1 -1
- package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +1 -1
- package/src/features/chat/features/welcome/components/chat-welcome-prompt-suggestions.tsx +56 -13
- package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +3 -3
- package/src/features/chat/features/welcome/components/chat-welcome.tsx +14 -4
- package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-continuation.utils.test.ts +40 -0
- package/src/features/chat/features/welcome/utils/chat-welcome-continuation.utils.ts +21 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +1 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +5 -9
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +6 -4
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +27 -27
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +1 -1
- package/src/features/chat/features/workspace/components/overview/chat-session-continuous-attention.tsx +11 -11
- package/src/features/chat/features/workspace/components/overview/chat-session-token-usage.tsx +15 -15
- package/src/features/chat/features/workspace/components/project-files/workspace-directory-tree.tsx +2 -2
- package/src/features/chat/features/workspace/components/project-files/workspace-new-folder-tree-item.tsx +1 -1
- package/src/features/chat/features/workspace/components/project-files/workspace-project-files-toolbar.tsx +2 -2
- package/src/features/chat/features/workspace/components/session-cron-job-content.tsx +7 -4
- package/src/features/cron/components/cron-job-row.tsx +5 -4
- package/src/features/desktop-capabilities/components/desktop-authorization-dialog.tsx +5 -5
- package/src/features/inbox/components/inbox-reader-dialog.test.tsx +46 -6
- package/src/features/inbox/components/inbox-reader-dialog.tsx +38 -29
- package/src/features/inbox/managers/inbox.manager.test.ts +28 -0
- package/src/features/inbox/managers/inbox.manager.ts +18 -4
- package/src/features/inbox/pages/inbox-page.test.ts +16 -5
- package/src/features/inbox/pages/inbox-page.tsx +37 -29
- package/src/features/panel-apps/components/panel-app-list-item.tsx +4 -3
- package/src/features/panel-apps/components/panel-app-service-action-authorization-dialog.tsx +2 -2
- package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +5 -24
- package/src/features/projects/components/work/project-work-items.tsx +1 -1
- package/src/features/projects/pages/project-home-page.tsx +4 -2
- package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +3 -3
- package/src/features/pwa/managers/pwa-shell-theme.manager.ts +8 -3
- package/src/features/right-panel-resources/components/__tests__/page-resource-icon.test.tsx +13 -2
- package/src/features/right-panel-resources/components/page-resource-icon.tsx +15 -7
- package/src/features/right-panel-resources/configs/right-panel-resource-routes.config.ts +1 -1
- package/src/features/right-panel-resources/index.ts +3 -0
- package/src/features/right-panel-resources/utils/__tests__/right-panel-resource-route-resolver.utils.test.ts +5 -0
- package/src/features/right-panel-resources/utils/right-panel-resource-uri.utils.ts +3 -2
- package/src/features/service-apps/components/service-action-row.tsx +4 -3
- package/src/features/service-apps/components/service-app-delete-dialog.tsx +2 -2
- package/src/features/service-apps/components/service-app-list-item.tsx +5 -4
- package/src/features/settings/components/config/provider-model-suggestions-panel.tsx +1 -1
- package/src/features/settings/pages/providers-config-page.tsx +3 -2
- package/src/index.css +42 -8
- package/src/platforms/mobile/components/__tests__/mobile-app-shell.test.tsx +9 -0
- package/src/platforms/mobile/components/mobile-app-shell.tsx +4 -2
- package/src/platforms/mobile/components/mobile-topbar.tsx +2 -2
- package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +2 -2
- package/src/shared/components/path-picker/server-path-picker-dialog.tsx +5 -3
- package/src/shared/components/ui/__tests__/dialog.test.tsx +37 -1
- package/src/shared/components/ui/actions/action-feedback.ts +1 -8
- package/src/shared/components/ui/actions/icon-action-button.tsx +1 -1
- package/src/shared/components/ui/confirm-dialog.tsx +1 -2
- package/src/shared/components/ui/context-menu/context-menu-items.tsx +2 -2
- package/src/shared/components/ui/dialog.tsx +29 -7
- package/src/shared/components/ui/popover.tsx +14 -3
- package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +5 -5
- package/src/shared/components/ui/tooltip.tsx +2 -1
- package/src/shared/components/workbench/__tests__/workbench-surface.test.tsx +21 -0
- package/src/shared/components/workbench/workbench-surface-toolbar.tsx +4 -0
- package/src/shared/components/workbench/workbench-surface.tsx +5 -2
- package/src/shared/lib/i18n/locales/en-US/chat.json +14 -9
- package/src/shared/lib/i18n/locales/en-US/core.json +5 -1
- package/src/shared/lib/i18n/locales/en-US/doc-browser.json +10 -5
- package/src/shared/lib/i18n/locales/en-US/inbox.json +1 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +14 -9
- package/src/shared/lib/i18n/locales/zh-CN/core.json +5 -1
- package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +11 -6
- package/src/shared/lib/i18n/locales/zh-CN/inbox.json +1 -0
- package/src/shared/lib/theme/index.test.ts +28 -1
- package/src/shared/lib/theme/index.ts +14 -3
- package/dist/assets/account-panel-DVi_jhkG.js +0 -1
- package/dist/assets/api-BZvNpFOS.js +0 -20
- package/dist/assets/app-presenter-provider-BcYL-VNe.js +0 -124
- package/dist/assets/appearance-settings-page-AZNBzLmT.js +0 -1
- package/dist/assets/architecture-TIHT7OUA-CvnC-LeA.js +0 -1
- package/dist/assets/channel-CpMstUPF.js +0 -1
- package/dist/assets/channels-list-page-eZN74FN3.js +0 -8
- package/dist/assets/chunk-2Q5K7J3B-Djp3VF0s.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-BrbiIC1Q.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-Cx9N40wF.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-DFN1v3PQ.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-DRvglADa.js +0 -1
- package/dist/assets/config-split-page-BA3V6b3Q.js +0 -1
- package/dist/assets/confirm-dialog-8vqYZ0wy.js +0 -1
- package/dist/assets/context-menu-DHVVdHzN.js +0 -1
- package/dist/assets/cynefin-VYW2F7L2-DXUGnpJH.js +0 -1
- package/dist/assets/desktop-update-config-Cfr3IRUe.js +0 -1
- package/dist/assets/dialog-BUfWO8hr.js +0 -5
- package/dist/assets/doc-browser-w8q1j0jL.js +0 -1
- package/dist/assets/es2015-BiB05Sav.js +0 -41
- package/dist/assets/eventmodeling-45OFAUF4-ZBfVS3ZC.js +0 -1
- package/dist/assets/extensions-vPD4dGqt.js +0 -1
- package/dist/assets/eye-bKzylu3p.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-CqdsKk6x.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-fHYFd9Es.js +0 -1
- package/dist/assets/info-DKCQHKI2-CSaOL_bb.js +0 -1
- package/dist/assets/katex-B4FQSo9k.js +0 -1
- package/dist/assets/loader-circle-Clq1Gtb1.js +0 -1
- package/dist/assets/login-page-DKId3By8.js +0 -1
- package/dist/assets/main-bEWCGDHr.js +0 -2
- package/dist/assets/main-i18n-catalog.config-Bpu5GcwF.js +0 -1
- package/dist/assets/main-kqMRTwOs.css +0 -1
- package/dist/assets/mcp-marketplace-page-CZIP6j3L.js +0 -1
- package/dist/assets/model-config-page-D21a-BO0.js +0 -1
- package/dist/assets/packet-7NZHBO7P-D-YFTczs.js +0 -1
- package/dist/assets/panel-app-BYfQu_TS.js +0 -1
- package/dist/assets/panel-app-i18n-catalog.config-D44qmtfk.js +0 -1
- package/dist/assets/panelStandalone-BRg7B1EI.css +0 -1
- package/dist/assets/panelStandalone-CX8X2hjh.js +0 -2
- package/dist/assets/pie-RZYD4A2V-VEnYu9s5.js +0 -1
- package/dist/assets/privacy-settings-page-e0LFHZJm.js +0 -1
- package/dist/assets/projects-Rki7Fmth.js +0 -1
- package/dist/assets/provider-models-DFQgF4hS.js +0 -1
- package/dist/assets/provider-scoped-model-input-DaONL0j_.js +0 -1
- package/dist/assets/providers-config-page-CEOhQlMe.js +0 -1
- package/dist/assets/puzzle-D_TiFXOv.js +0 -1
- package/dist/assets/pwa-C9ac_1dg.js +0 -1
- package/dist/assets/radar-I7S5WNFK-BFNIekC1.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-lVqJ3Hak.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-DYaefdFC.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-CTAk6lVq.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-Cob294tg.js +0 -1
- package/dist/assets/remote-DkSx5x4R.js +0 -1
- package/dist/assets/runtime-config-page-DDT1dVLt.js +0 -1
- package/dist/assets/search-config-page-CDwmd6eX.js +0 -1
- package/dist/assets/secrets-config-page-1OvgmwPv.js +0 -3
- package/dist/assets/security-config-Pv4CM-kw.js +0 -1
- package/dist/assets/select-Y9IEbx9x.js +0 -1
- package/dist/assets/service-apps-panel-DPrLeF3N.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-BrNv-raG.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-ntcxaPXp.js +0 -8
- package/dist/assets/tag-chip-D-6aPuuh.js +0 -1
- package/dist/assets/theme-provider-BjF1Eowc.js +0 -1
- package/dist/assets/trash-2-DER2EJKK.js +0 -1
- package/dist/assets/treeView-QDETBFTQ-DbFmr-gw.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-C8aY96pi.js +0 -1
- package/dist/assets/use-viewport-layout-vmbQUNT6.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-D8d6DbbJ.js +0 -1
- package/dist/assets/x-DSz9cGhy.js +0 -1
- package/src/features/apps/components/app-marketplace-dialog.tsx +0 -168
- /package/dist/assets/{array-BV9OtnO8.js → array-DstOKG9P.js} +0 -0
- /package/dist/assets/{chunk-KEIR6QF5-Cx-8EJ4_.js → chunk-KEIR6QF5-0TA8nwgf.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-Dy1ufvjf.js → chunk-Y2CYZVJY-rfGCG6pM.js} +0 -0
- /package/dist/assets/{config-hints-DbmiyTKg.js → config-hints-BfGoD7-o.js} +0 -0
- /package/dist/assets/{cytoscape.esm-CSCjuT4Z.js → cytoscape.esm-DdIcNEda.js} +0 -0
- /package/dist/assets/{defaultLocale-DWTiNsbT.js → defaultLocale-CzXix2iJ.js} +0 -0
- /package/dist/assets/{dist-BVCSkfWY.js → dist-D5dwMwKA.js} +0 -0
- /package/dist/assets/{graphlib-B1yb1Wl8.js → graphlib-BKOe0eFe.js} +0 -0
- /package/dist/assets/{host-capabilities-DuIFVsvM.js → host-capabilities-CnSVTaot.js} +0 -0
- /package/dist/assets/{init-BF6GH5oe.js → init-OCFb3zgY.js} +0 -0
- /package/dist/assets/{jszip.min-D12teKzP.js → jszip.min-B2uhSxvV.js} +0 -0
- /package/dist/assets/{katex-CsAM73R9.js → katex-dBrYsE7B.js} +0 -0
- /package/dist/assets/{middleware-B--6mAUM.js → middleware-CAXxl-af.js} +0 -0
- /package/dist/assets/{path-C56XkznJ.js → path-T5eoIRSJ.js} +0 -0
- /package/dist/assets/{preload-helper-ca-nBW7U.js → preload-helper-DWTEM3RW.js} +0 -0
- /package/dist/assets/{rough.esm-CGfeEbtE.js → rough.esm-DmGXmZEB.js} +0 -0
- /package/dist/assets/{xlsx-sds5nUpL.js → xlsx-CoYacou7.js} +0 -0
package/src/features/chat/features/conversation/components/floating-session-conversation.tsx
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { PageResourceActionsMenu } from '@/features/right-panel-resources';
|
|
2
2
|
import { pageResourceFromTarget } from '@/features/right-panel-resources';
|
|
3
3
|
import { buildSessionPanelUrl } from '@/features/chat/features/session/utils/chat-session-route.utils';
|
|
4
|
-
import { MessageSquare } from 'lucide-react';
|
|
5
4
|
import { useNavigate } from 'react-router-dom';
|
|
6
5
|
import { getAppPresenter } from '@/app/presenters/app.presenter';
|
|
7
6
|
import { sessionSurfaceManager } from '@/features/chat/managers/session-surface.manager';
|
|
@@ -17,8 +16,8 @@ export function FloatingSessionConversation() {
|
|
|
17
16
|
const presenter = getAppPresenter();
|
|
18
17
|
if (!session) return null;
|
|
19
18
|
return <WorkbenchSurface id={SESSION_WORKBENCH_SURFACE} manager={presenter.workbenchSurfaceManager}
|
|
20
|
-
title={session.title}
|
|
21
|
-
|
|
19
|
+
title={session.title} testId="floating-session-conversation" focusOnOpen
|
|
20
|
+
moreActions={<PageResourceActionsMenu page={pageResourceFromTarget({ kind: 'chat-session', title: session.title, url: buildSessionPanelUrl(session.sessionKey), resourceUri: buildSessionPanelUrl(session.sessionKey), historyPolicy: 'none' })} />}
|
|
22
21
|
onClose={sessionSurfaceManager.close}
|
|
23
22
|
onPlace={() => sessionSurfaceManager.dock(session, presenter.docBrowserManager)}
|
|
24
23
|
onOpenMain={() => { navigate(buildSessionPath(session.sessionKey)); sessionSurfaceManager.close(); }}>
|
|
@@ -437,6 +437,7 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
|
|
|
437
437
|
onEditMessage={(payload) => controllerRef.current.editMessage(payload)}
|
|
438
438
|
welcomeSlot={
|
|
439
439
|
<ChatConversationWelcome
|
|
440
|
+
hasDraftContent={Boolean(inputSnapshot.text.trim() || inputSnapshot.attachments.length || inputSnapshot.selectedSkills.length)}
|
|
440
441
|
inputSlot={
|
|
441
442
|
<div className="space-y-2">
|
|
442
443
|
{renderInput("embedded", t("chatWelcomeInputPlaceholder"))}
|
|
@@ -198,4 +198,37 @@ describe('useSessionConversationInputState session preferences', () => {
|
|
|
198
198
|
rerender({ sessionKey: null });
|
|
199
199
|
expect(result.current.inputSnapshot.text).toBe('新会话草稿');
|
|
200
200
|
});
|
|
201
|
+
|
|
202
|
+
it('keeps a successfully cleared draft empty after switching away and back', () => {
|
|
203
|
+
const { result, rerender } = renderHook(
|
|
204
|
+
({ sessionKey }: { sessionKey: string }) =>
|
|
205
|
+
useSessionConversationInputState(null, sessionKey),
|
|
206
|
+
{ initialProps: { sessionKey: 'session-sent' } },
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
act(() => {
|
|
210
|
+
result.current.inputActions.syncComposer({
|
|
211
|
+
text: '已经发送的消息',
|
|
212
|
+
nodes: [],
|
|
213
|
+
selectedSkills: [],
|
|
214
|
+
skillRecords: [],
|
|
215
|
+
});
|
|
216
|
+
result.current.inputActions.resetComposer();
|
|
217
|
+
});
|
|
218
|
+
rerender({ sessionKey: 'session-unsent' });
|
|
219
|
+
act(() => {
|
|
220
|
+
result.current.inputActions.syncComposer({
|
|
221
|
+
text: '仍未发送的草稿',
|
|
222
|
+
nodes: [],
|
|
223
|
+
selectedSkills: [],
|
|
224
|
+
skillRecords: [],
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
rerender({ sessionKey: 'session-sent' });
|
|
229
|
+
expect(result.current.inputSnapshot.text).toBe('');
|
|
230
|
+
|
|
231
|
+
rerender({ sessionKey: 'session-unsent' });
|
|
232
|
+
expect(result.current.inputSnapshot.text).toBe('仍未发送的草稿');
|
|
233
|
+
});
|
|
201
234
|
});
|
|
@@ -122,8 +122,6 @@ class ChatMessageViewModelAdapter {
|
|
|
122
122
|
message,
|
|
123
123
|
processedLabel,
|
|
124
124
|
language,
|
|
125
|
-
failedLabel: t("chatProcessSummaryError", language),
|
|
126
|
-
stoppedLabel: t("chatProcessSummaryStopped", language),
|
|
127
125
|
});
|
|
128
126
|
const processSummaryLabel = processSummary?.label ?? null;
|
|
129
127
|
const executionPresentation = buildChatMessageExecutionPresentation({
|
|
@@ -31,8 +31,6 @@ const baseAssistantMessage = {
|
|
|
31
31
|
|
|
32
32
|
const summaryLabels = {
|
|
33
33
|
processedLabel: "已处理",
|
|
34
|
-
failedLabel: "处理失败",
|
|
35
|
-
stoppedLabel: "已停止",
|
|
36
34
|
language: "zh" as const,
|
|
37
35
|
};
|
|
38
36
|
|
|
@@ -135,8 +133,8 @@ describe("buildChatMessageProcessSummary", () => {
|
|
|
135
133
|
});
|
|
136
134
|
|
|
137
135
|
it.each([
|
|
138
|
-
["failed", "
|
|
139
|
-
] as const)("
|
|
136
|
+
["failed", "已处理"], ["aborted", "已处理"], ["completed", "已处理"],
|
|
137
|
+
] as const)("keeps the process summary neutral for a %s outcome", (outcome, expected) => {
|
|
140
138
|
const message: NcpMessage = {
|
|
141
139
|
...baseAssistantMessage,
|
|
142
140
|
metadata: { ai_execution: createUnavailableNcpAiExecutionMetadata({
|
|
@@ -146,9 +144,9 @@ describe("buildChatMessageProcessSummary", () => {
|
|
|
146
144
|
expect(buildChatMessageProcessSummary({ ...summaryLabels, message })?.label).toBe(expected);
|
|
147
145
|
});
|
|
148
146
|
|
|
149
|
-
it("
|
|
147
|
+
it("keeps the process summary neutral for an error message", () => {
|
|
150
148
|
expect(buildChatMessageProcessSummary({
|
|
151
149
|
...summaryLabels, message: { ...baseAssistantMessage, status: "error" },
|
|
152
|
-
})?.label).toBe("
|
|
150
|
+
})?.label).toBe("已处理");
|
|
153
151
|
});
|
|
154
152
|
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ChatMessageMoreActionsViewModel } from "@nextclaw/agent-chat-ui";
|
|
2
|
+
import { createElement } from "react";
|
|
3
|
+
import { Braces } from "lucide-react";
|
|
2
4
|
import {
|
|
3
5
|
readNcpAiExecutionMetadata,
|
|
4
6
|
type NcpAiExecutionMetadata,
|
|
@@ -159,6 +161,7 @@ export function buildChatMessageExecutionPresentation(params: {
|
|
|
159
161
|
items: [
|
|
160
162
|
{
|
|
161
163
|
key: "ai-execution-metadata",
|
|
164
|
+
icon: createElement(Braces, { className: "h-4 w-4" }),
|
|
162
165
|
label: labels.viewMetadata,
|
|
163
166
|
dialog: {
|
|
164
167
|
title: labels.metadataTitle,
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { NcpMessage } from "@nextclaw/ncp";
|
|
2
2
|
import type { ChatMessageProcessSummarySource } from "@/features/chat/types/chat-message.types";
|
|
3
3
|
import { t, type I18nLanguage } from "@/shared/lib/i18n";
|
|
4
4
|
|
|
5
5
|
type BuildChatMessageProcessSummaryParams = {
|
|
6
6
|
message: NcpMessage;
|
|
7
7
|
processedLabel: string;
|
|
8
|
-
failedLabel: string;
|
|
9
|
-
stoppedLabel: string;
|
|
10
8
|
language: I18nLanguage;
|
|
11
9
|
};
|
|
12
10
|
|
|
@@ -78,8 +76,6 @@ function formatLifecycleDuration(message: NcpMessage, language: I18nLanguage): s
|
|
|
78
76
|
* and must not be mixed into this summary.
|
|
79
77
|
*/
|
|
80
78
|
export function buildChatMessageProcessSummary({
|
|
81
|
-
failedLabel,
|
|
82
|
-
stoppedLabel,
|
|
83
79
|
message,
|
|
84
80
|
processedLabel,
|
|
85
81
|
language,
|
|
@@ -88,11 +84,7 @@ export function buildChatMessageProcessSummary({
|
|
|
88
84
|
return undefined;
|
|
89
85
|
}
|
|
90
86
|
const duration = formatLifecycleDuration(message, language);
|
|
91
|
-
const outcome = readNcpAiExecutionMetadata(message.metadata)?.outcome;
|
|
92
|
-
const statusLabel = message.status === "error" || outcome === "failed"
|
|
93
|
-
? failedLabel
|
|
94
|
-
: outcome === "aborted" ? stoppedLabel : processedLabel;
|
|
95
87
|
return {
|
|
96
|
-
label: duration ? `${
|
|
88
|
+
label: duration ? `${processedLabel} ${duration}` : processedLabel,
|
|
97
89
|
};
|
|
98
90
|
}
|
|
@@ -189,6 +189,8 @@ export function buildChatMessageTexts(
|
|
|
189
189
|
copiedMessageLabel: t("chatMessageCopied"),
|
|
190
190
|
excerptCharacterCountTemplate: t("chatWorkspaceExcerptCharacterCount"),
|
|
191
191
|
mermaidDiagramLabel: t("chatMermaidDiagram"),
|
|
192
|
+
frontmatterLabel: t("chatMarkdownFrontmatter"),
|
|
193
|
+
detailsLabel: t("chatMarkdownDetails"),
|
|
192
194
|
mermaidExpandLabel: t("chatMermaidExpand"),
|
|
193
195
|
mermaidLoadingLabel: t("chatMermaidLoading"),
|
|
194
196
|
mermaidRenderErrorLabel: t("chatMermaidRenderError"),
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ChatMessageMoreActionsViewModel } from "@nextclaw/agent-chat-ui";
|
|
2
|
+
import { createElement } from "react";
|
|
3
|
+
import { Zap } from "lucide-react";
|
|
2
4
|
import {
|
|
3
5
|
readNcpAiExecutionMetadata,
|
|
4
6
|
readNcpRunTriggerMetadata,
|
|
@@ -106,6 +108,7 @@ export function buildChatMessageTriggerDetails(params: {
|
|
|
106
108
|
triggerLabel: labels.moreActions,
|
|
107
109
|
items: [{
|
|
108
110
|
key: "run-trigger-metadata",
|
|
111
|
+
icon: createElement(Zap, { className: "h-4 w-4" }),
|
|
109
112
|
label: labels.viewTrigger,
|
|
110
113
|
dialog: {
|
|
111
114
|
title: labels.title,
|
|
@@ -175,6 +175,7 @@ export function ChatSidebarProjectGroups(props: ChatSidebarProjectGroupsProps) {
|
|
|
175
175
|
{group.projectId ? (
|
|
176
176
|
<Link
|
|
177
177
|
to={`/projects/${encodeURIComponent(group.projectId)}/overview`}
|
|
178
|
+
state={{ returnTo: `${location.pathname}${location.search}` }}
|
|
178
179
|
className="flex h-full min-w-0 flex-1 items-center gap-1.5 rounded-md px-1 text-left focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
|
|
179
180
|
aria-current={isSelected ? "page" : undefined}
|
|
180
181
|
title={group.projectRoot}
|
|
@@ -261,7 +262,7 @@ export function ChatSidebarProjectGroups(props: ChatSidebarProjectGroupsProps) {
|
|
|
261
262
|
onClick={(event) => event.stopPropagation()}
|
|
262
263
|
/>
|
|
263
264
|
</PopoverTrigger>
|
|
264
|
-
<ChatPopoverContent align="end"
|
|
265
|
+
<ChatPopoverContent align="end" variant="menu">
|
|
265
266
|
<ChatSessionHeaderMenuItem
|
|
266
267
|
icon={FolderMinus}
|
|
267
268
|
label={t("projectsRemoveFromList")}
|
|
@@ -29,7 +29,7 @@ export function ChatSessionMetadataDialog({
|
|
|
29
29
|
return (
|
|
30
30
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
31
31
|
<DialogContent className="max-w-2xl gap-0 overflow-hidden p-0">
|
|
32
|
-
<DialogHeader className="border-b border-border px-5 py-4
|
|
32
|
+
<DialogHeader className="border-b border-border px-5 py-4">
|
|
33
33
|
<DialogTitle className="text-base">{t('chatSessionMetadataDialogTitle')}</DialogTitle>
|
|
34
34
|
<DialogDescription className="sr-only">
|
|
35
35
|
{t('chatSessionMetadataDialogDescription')}
|
package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx
CHANGED
|
@@ -56,8 +56,8 @@ export function ChatSessionProjectBadge({
|
|
|
56
56
|
<PopoverTrigger asChild>
|
|
57
57
|
<button
|
|
58
58
|
type="button"
|
|
59
|
-
title={projectRoot
|
|
60
|
-
className="min-w-0 max-w-[
|
|
59
|
+
title={projectRoot ? `${projectName}\n${projectRoot}` : projectName}
|
|
60
|
+
className="min-w-0 max-w-[40%] shrink-0 rounded-full border border-border bg-muted px-2 py-0.5 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border disabled:cursor-not-allowed disabled:opacity-60"
|
|
61
61
|
aria-label={t('chatSessionSetProject')}
|
|
62
62
|
disabled={isProjectPending}
|
|
63
63
|
>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
2
2
|
import { describe, expect, it, vi } from 'vitest';
|
|
3
3
|
import { ChatWelcome } from '@/features/chat/features/welcome/components/chat-welcome';
|
|
4
|
+
import { MemoryRouter } from 'react-router-dom';
|
|
5
|
+
import { buildSessionPath } from '@/features/chat/features/session/utils/chat-session-route.utils';
|
|
4
6
|
|
|
5
7
|
vi.mock(
|
|
6
8
|
'@/features/chat/features/session/components/session-header/chat-session-project-dialog',
|
|
@@ -18,12 +20,14 @@ function renderWelcome(
|
|
|
18
20
|
overrides: Partial<Parameters<typeof ChatWelcome>[0]> = {},
|
|
19
21
|
) {
|
|
20
22
|
return render(
|
|
23
|
+
<MemoryRouter>
|
|
21
24
|
<ChatWelcome
|
|
22
25
|
agents={[
|
|
23
26
|
{ id: 'main', displayName: 'Main' },
|
|
24
27
|
{ id: 'engineer', displayName: 'Engineer' },
|
|
25
28
|
]}
|
|
26
29
|
projectOptions={[]}
|
|
30
|
+
selectedProjectRoot="/tmp/project"
|
|
27
31
|
selectedAgentId="main"
|
|
28
32
|
selectedSessionType="native"
|
|
29
33
|
sessionTypeOptions={sessionTypeOptions}
|
|
@@ -31,11 +35,34 @@ function renderWelcome(
|
|
|
31
35
|
onSelectPrompt={vi.fn()}
|
|
32
36
|
onSelectSessionType={vi.fn()}
|
|
33
37
|
{...overrides}
|
|
34
|
-
|
|
38
|
+
/>
|
|
39
|
+
</MemoryRouter>,
|
|
35
40
|
);
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
describe('ChatWelcome', () => {
|
|
44
|
+
it('offers an open-ended starting point outside an explicit project', () => {
|
|
45
|
+
renderWelcome({ selectedProjectRoot: null });
|
|
46
|
+
expect(screen.getByRole('button', { name: 'Talk about how I’ve been' })).toBeTruthy();
|
|
47
|
+
expect(screen.queryByRole('button', { name: 'Move this project forward' })).toBeNull();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('links to the original session and can dismiss it without removing history', () => {
|
|
51
|
+
renderWelcome({ continuation: { sessionKey: 'session/one', title: 'A real conversation' } });
|
|
52
|
+
const link = screen.getByRole('link', { name: /A real conversation/ });
|
|
53
|
+
expect(link.getAttribute('href')).toBe(buildSessionPath('session/one'));
|
|
54
|
+
expect(screen.getByRole('button', { name: 'Talk about how I’ve been' })).toBeTruthy();
|
|
55
|
+
fireEvent.click(screen.getByRole('button', { name: 'Hide this conversation suggestion for now' }));
|
|
56
|
+
expect(screen.queryByRole('link')).toBeNull();
|
|
57
|
+
expect(screen.getByRole('button', { name: 'Move this project forward' })).toBeTruthy();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('hides starting suggestions while composing but keeps context controls available', () => {
|
|
61
|
+
renderWelcome({ hasDraftContent: true });
|
|
62
|
+
expect(screen.queryByRole('button', { name: 'Move this project forward' })).toBeNull();
|
|
63
|
+
expect(screen.getByRole('combobox', { name: 'Draft agent' })).toBeTruthy();
|
|
64
|
+
expect(screen.getByRole('button', { name: 'Choose session type' })).toBeTruthy();
|
|
65
|
+
});
|
|
39
66
|
it('renders a lightweight draft agent select and allows switching', () => {
|
|
40
67
|
const onSelectAgent = vi.fn();
|
|
41
68
|
|
|
@@ -53,12 +80,10 @@ describe('ChatWelcome', () => {
|
|
|
53
80
|
it('renders a single-purpose welcome surface with compact prompt suggestions', () => {
|
|
54
81
|
renderWelcome({ agents: [{ id: 'main', displayName: 'Main' }] });
|
|
55
82
|
|
|
56
|
-
expect(screen.getByRole('heading', { name: '
|
|
83
|
+
expect(screen.getByRole('heading', { name: 'Where shall we start today?' })).toBeTruthy();
|
|
57
84
|
expect(screen.queryByText(/Describe the goal/)).toBeNull();
|
|
58
85
|
expect(screen.getByRole('group', { name: 'Task context' })).toBeTruthy();
|
|
59
|
-
const suggestion = screen.getByRole('button', { name: '
|
|
60
|
-
expect(suggestion.className).toContain('rounded-full');
|
|
61
|
-
expect(suggestion.className).not.toContain('border');
|
|
86
|
+
const suggestion = screen.getByRole('button', { name: 'Move this project forward' });
|
|
62
87
|
expect(suggestion.parentElement?.className).toContain('flex-wrap');
|
|
63
88
|
});
|
|
64
89
|
|
|
@@ -67,7 +92,7 @@ describe('ChatWelcome', () => {
|
|
|
67
92
|
|
|
68
93
|
renderWelcome({ onSelectPrompt });
|
|
69
94
|
|
|
70
|
-
fireEvent.click(screen.getByRole('button', { name: '
|
|
95
|
+
fireEvent.click(screen.getByRole('button', { name: 'Move this project forward' }));
|
|
71
96
|
|
|
72
97
|
expect(onSelectPrompt).toHaveBeenCalledWith(
|
|
73
98
|
expect.stringContaining('next three concrete things'),
|
|
@@ -19,11 +19,13 @@ import { useAgents } from "@/shared/hooks/use-agents";
|
|
|
19
19
|
import { useProjects } from "@/shared/hooks/use-projects";
|
|
20
20
|
import type { NcpSessionSummaryView } from "@/shared/lib/api";
|
|
21
21
|
import { normalizeSessionProjectRootValue } from "@/shared/lib/session-project";
|
|
22
|
+
import { resolveChatWelcomeContinuation } from "@/features/chat/features/welcome/utils/chat-welcome-continuation.utils";
|
|
22
23
|
|
|
23
24
|
const EMPTY_NCP_SESSION_SUMMARIES: NcpSessionSummaryView[] = [];
|
|
24
25
|
|
|
25
26
|
type ChatConversationWelcomeProps = {
|
|
26
27
|
inputSlot: ReactNode;
|
|
28
|
+
hasDraftContent?: boolean;
|
|
27
29
|
pendingProjectRoot: string | null;
|
|
28
30
|
pendingSessionType: string;
|
|
29
31
|
selectedSessionTypeValue: string | null;
|
|
@@ -34,6 +36,7 @@ type ChatConversationWelcomeProps = {
|
|
|
34
36
|
|
|
35
37
|
export function ChatConversationWelcome({
|
|
36
38
|
inputSlot,
|
|
39
|
+
hasDraftContent = false,
|
|
37
40
|
pendingProjectRoot,
|
|
38
41
|
pendingSessionType,
|
|
39
42
|
selectedSessionTypeValue,
|
|
@@ -50,7 +53,9 @@ export function ChatConversationWelcome({
|
|
|
50
53
|
(state) => state.snapshot.configQuery?.data ?? null,
|
|
51
54
|
);
|
|
52
55
|
const sessionSummaries = useChatQueryStore(
|
|
53
|
-
(state) => state.snapshot.sessionsQuery?.
|
|
56
|
+
(state) => state.snapshot.sessionsQuery?.isSuccess
|
|
57
|
+
? state.snapshot.sessionsQuery.data?.sessions ?? EMPTY_NCP_SESSION_SUMMARIES
|
|
58
|
+
: EMPTY_NCP_SESSION_SUMMARIES,
|
|
54
59
|
);
|
|
55
60
|
const sessionTypesData = useChatQueryStore(
|
|
56
61
|
(state) => state.snapshot.sessionTypesQuery?.data ?? null,
|
|
@@ -104,6 +109,13 @@ export function ChatConversationWelcome({
|
|
|
104
109
|
agents={availableAgents}
|
|
105
110
|
defaultProjectRoot={defaultProjectRoot}
|
|
106
111
|
inputSlot={inputSlot}
|
|
112
|
+
hasDraftContent={hasDraftContent}
|
|
113
|
+
continuation={resolveChatWelcomeContinuation({
|
|
114
|
+
sessions: sessionSummaries,
|
|
115
|
+
projectRoot: selectedProjectRoot ?? defaultProjectRoot,
|
|
116
|
+
defaultProjectRoot,
|
|
117
|
+
agentId: draftAgentId,
|
|
118
|
+
})}
|
|
107
119
|
projectOptions={projectOptions}
|
|
108
120
|
selectedAgentId={draftAgentId}
|
|
109
121
|
selectedProjectRoot={selectedProjectRoot}
|
|
@@ -28,7 +28,7 @@ export function ChatWelcomeAgentPicker({
|
|
|
28
28
|
<Select value={selectedAgentId} onValueChange={onSelectAgent}>
|
|
29
29
|
<SelectTrigger
|
|
30
30
|
aria-label={t('chatDraftAgentTitle')}
|
|
31
|
-
className="h-
|
|
31
|
+
className="h-9 w-auto min-w-0 gap-1.5 rounded-lg border-0 bg-transparent px-2 py-1.5 text-sm font-medium text-foreground/80 shadow-none hover:bg-[var(--interaction-hover)] hover:text-foreground focus:ring-1 focus:ring-border"
|
|
32
32
|
>
|
|
33
33
|
<span className="sr-only">{t('chatDraftAgentTitle')}</span>
|
|
34
34
|
<div className="flex min-w-0 items-center gap-1.5">
|
|
@@ -43,7 +43,7 @@ export function ChatWelcomeProjectPicker({
|
|
|
43
43
|
<PopoverTrigger asChild>
|
|
44
44
|
<button
|
|
45
45
|
type="button"
|
|
46
|
-
className="inline-flex min-w-0 max-w-full items-center gap-1.5 rounded-lg px-2 py-1.5 text-left font-medium text-
|
|
46
|
+
className="inline-flex h-9 min-w-0 max-w-full items-center gap-1.5 rounded-lg px-2 py-1.5 text-left text-sm font-medium text-foreground/80 transition-colors hover:bg-[var(--interaction-hover)] hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
|
|
47
47
|
title={projectRoot ?? undefined}
|
|
48
48
|
aria-label={t('chatWelcomeProjectPickerLabel')}
|
|
49
49
|
disabled={!selectable || isSaving}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { Link } from 'react-router-dom';
|
|
3
|
+
import { ArrowUpRight, History, X } from 'lucide-react';
|
|
4
|
+
import { buildSessionPath } from '@/features/chat/features/session/utils/chat-session-route.utils';
|
|
5
|
+
import type { ChatWelcomeContinuation } from '@/features/chat/features/welcome/utils/chat-welcome-continuation.utils';
|
|
1
6
|
import { t } from '@/shared/lib/i18n';
|
|
2
7
|
|
|
3
8
|
const WELCOME_PROMPT_SUGGESTIONS = [
|
|
4
9
|
{
|
|
5
|
-
labelKey: '
|
|
6
|
-
promptKey: '
|
|
10
|
+
labelKey: 'chatWelcomeOpenStartLabel' as const,
|
|
11
|
+
promptKey: 'chatWelcomeOpenStartPrompt' as const,
|
|
7
12
|
},
|
|
8
13
|
{
|
|
9
14
|
labelKey: 'chatWelcomeSuggestion2Label' as const,
|
|
@@ -17,21 +22,59 @@ const WELCOME_PROMPT_SUGGESTIONS = [
|
|
|
17
22
|
|
|
18
23
|
export function ChatWelcomePromptSuggestions({
|
|
19
24
|
onSelectPrompt,
|
|
25
|
+
hasDraftContent = false,
|
|
26
|
+
hasProject = false,
|
|
27
|
+
continuation,
|
|
20
28
|
}: {
|
|
21
29
|
onSelectPrompt: (prompt: string) => void;
|
|
30
|
+
hasDraftContent?: boolean;
|
|
31
|
+
hasProject?: boolean;
|
|
32
|
+
continuation?: ChatWelcomeContinuation | null;
|
|
22
33
|
}) {
|
|
34
|
+
const [dismissedSessionKey, setDismissedSessionKey] = useState<string | null>(null);
|
|
35
|
+
const showContinuation = continuation && continuation.sessionKey !== dismissedSessionKey;
|
|
23
36
|
return (
|
|
24
|
-
<div className=
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
<div className={`mt-3 min-h-32 ${hasDraftContent ? 'invisible' : ''}`} aria-hidden={hasDraftContent || undefined}>
|
|
38
|
+
<div className="flex flex-wrap justify-center gap-x-2 gap-y-1">
|
|
39
|
+
{WELCOME_PROMPT_SUGGESTIONS.map((suggestion, index) => {
|
|
40
|
+
const projectStart = index === 2 && hasProject;
|
|
41
|
+
return (
|
|
42
|
+
<button
|
|
43
|
+
key={suggestion.labelKey}
|
|
44
|
+
type="button"
|
|
45
|
+
onClick={() => onSelectPrompt(t(projectStart ? 'chatWelcomeSuggestion1Prompt' : suggestion.promptKey))}
|
|
46
|
+
className="rounded-lg bg-muted/70 px-3 py-1.5 text-[13px] font-normal leading-5 text-foreground/80 transition-colors hover:bg-[var(--interaction-hover)] hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
47
|
+
>
|
|
48
|
+
{t(projectStart ? 'chatWelcomeSuggestion1Label' : suggestion.labelKey)}
|
|
49
|
+
</button>
|
|
50
|
+
);
|
|
51
|
+
})}
|
|
52
|
+
</div>
|
|
53
|
+
{continuation ? (
|
|
54
|
+
<div className={`mx-auto mt-5 flex min-w-0 max-w-lg items-center gap-1 border-t border-border/50 pt-3 ${showContinuation ? '' : 'invisible'}`} aria-hidden={!showContinuation || undefined}>
|
|
55
|
+
<Link
|
|
56
|
+
to={buildSessionPath(continuation.sessionKey)}
|
|
57
|
+
title={t('chatWelcomeContinueHint')}
|
|
58
|
+
className="flex min-w-0 flex-1 items-center gap-3 rounded-lg px-2 py-2 transition-colors hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
59
|
+
>
|
|
60
|
+
<History aria-hidden="true" className="h-4 w-4 shrink-0 text-muted-foreground" />
|
|
61
|
+
<span className="min-w-0 flex-1">
|
|
62
|
+
<span className="block text-xs text-muted-foreground">{t('chatWelcomeContinueLabel')}</span>
|
|
63
|
+
<span className="mt-1 block truncate text-sm text-foreground">{continuation.title}</span>
|
|
64
|
+
</span>
|
|
65
|
+
<ArrowUpRight aria-hidden="true" className="h-4 w-4 shrink-0 text-muted-foreground" />
|
|
66
|
+
</Link>
|
|
67
|
+
<button
|
|
68
|
+
type="button"
|
|
69
|
+
aria-label={t('chatWelcomeDismissContinue')}
|
|
70
|
+
title={t('chatWelcomeDismissContinue')}
|
|
71
|
+
onClick={() => setDismissedSessionKey(continuation.sessionKey)}
|
|
72
|
+
className="mr-1 flex h-9 w-9 shrink-0 items-center justify-center rounded-lg text-muted-foreground hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
73
|
+
>
|
|
74
|
+
<X aria-hidden="true" className="h-3.5 w-3.5" />
|
|
75
|
+
</button>
|
|
76
|
+
</div>
|
|
77
|
+
) : null}
|
|
35
78
|
</div>
|
|
36
79
|
);
|
|
37
80
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { Cpu, ChevronDown } from 'lucide-react';
|
|
3
3
|
import { SessionContextIconNode } from '@/features/chat/features/session/components/session-context-icon';
|
|
4
4
|
import { ChatSessionTypeOptionItem } from '@/features/chat/features/session-type/components/chat-session-type-option-item';
|
|
5
5
|
import type { ChatSessionTypeOption } from '@/features/chat/features/session-type/utils/chat-session-type.utils';
|
|
@@ -39,7 +39,7 @@ export function ChatWelcomeSessionTypePicker({
|
|
|
39
39
|
<PopoverTrigger asChild>
|
|
40
40
|
<button
|
|
41
41
|
type="button"
|
|
42
|
-
className="inline-flex min-w-0 max-w-full items-center gap-1.5 rounded-lg px-2 py-1.5 text-left font-medium text-
|
|
42
|
+
className="inline-flex h-9 min-w-0 max-w-full items-center gap-1.5 rounded-lg px-2 py-1.5 text-left text-sm font-medium text-foreground/80 transition-colors hover:bg-[var(--interaction-hover)] hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
|
|
43
43
|
aria-label={t('chatWelcomeSessionTypePickerLabel')}
|
|
44
44
|
>
|
|
45
45
|
{selectedOption.icon?.src ? (
|
|
@@ -53,7 +53,7 @@ export function ChatWelcomeSessionTypePicker({
|
|
|
53
53
|
className="h-4 w-4"
|
|
54
54
|
/>
|
|
55
55
|
) : (
|
|
56
|
-
<
|
|
56
|
+
<Cpu className="h-3.5 w-3.5 shrink-0" />
|
|
57
57
|
)}
|
|
58
58
|
<span className="truncate">{selectedOption.label}</span>
|
|
59
59
|
<ChevronDown className="h-3.5 w-3.5 shrink-0 text-muted-foreground/70" />
|
|
@@ -9,12 +9,15 @@ import type { ChatWelcomeProjectOption } from '@/features/chat/features/welcome/
|
|
|
9
9
|
import type { ChatSessionTypeOption } from '@/features/chat/features/session-type/utils/chat-session-type.utils';
|
|
10
10
|
import type { AgentProfileView } from '@/shared/lib/api';
|
|
11
11
|
import { t } from '@/shared/lib/i18n';
|
|
12
|
+
import type { ChatWelcomeContinuation } from '@/features/chat/features/welcome/utils/chat-welcome-continuation.utils';
|
|
12
13
|
|
|
13
14
|
type SessionTypeOption = ChatSessionTypeOption;
|
|
14
15
|
|
|
15
16
|
type ChatWelcomeProps = {
|
|
16
17
|
agents: AgentProfileView[];
|
|
17
18
|
inputSlot?: ReactNode;
|
|
19
|
+
hasDraftContent?: boolean;
|
|
20
|
+
continuation?: ChatWelcomeContinuation | null;
|
|
18
21
|
defaultProjectRoot?: string | null;
|
|
19
22
|
projectOptions: readonly ChatWelcomeProjectOption[];
|
|
20
23
|
selectedAgentId: string;
|
|
@@ -31,6 +34,8 @@ export function ChatWelcome({
|
|
|
31
34
|
agents,
|
|
32
35
|
defaultProjectRoot,
|
|
33
36
|
inputSlot,
|
|
37
|
+
hasDraftContent = false,
|
|
38
|
+
continuation,
|
|
34
39
|
projectOptions,
|
|
35
40
|
selectedAgentId,
|
|
36
41
|
selectedProjectRoot,
|
|
@@ -64,18 +69,18 @@ export function ChatWelcome({
|
|
|
64
69
|
<div className="flex min-h-full items-center justify-center px-4 py-10 sm:p-8">
|
|
65
70
|
<div className="w-full min-w-0 max-w-[min(680px,100%)]">
|
|
66
71
|
<div className="text-center">
|
|
67
|
-
<h2 className="text-2xl font-
|
|
72
|
+
<h2 className="text-2xl font-[number:var(--welcome-title-weight)] leading-tight text-[hsl(var(--welcome-title-foreground))] sm:text-[1.75rem]">
|
|
68
73
|
{t('chatWelcomeTitle')}
|
|
69
74
|
</h2>
|
|
70
75
|
</div>
|
|
71
76
|
|
|
72
77
|
{inputSlot ? <div className="mt-6">{inputSlot}</div> : null}
|
|
73
78
|
|
|
74
|
-
<div className="mt-
|
|
79
|
+
<div className="mt-1.5 flex justify-center px-1">
|
|
75
80
|
<div
|
|
76
81
|
role="group"
|
|
77
82
|
aria-label={t('chatWelcomeContextLabel')}
|
|
78
|
-
className="flex min-w-0 max-w-full flex-wrap items-center justify-center gap-
|
|
83
|
+
className="flex min-w-0 max-w-full flex-wrap items-center justify-center gap-x-1 gap-y-0.5 text-xs text-muted-foreground"
|
|
79
84
|
>
|
|
80
85
|
{onSelectProjectRoot ? (
|
|
81
86
|
<ChatWelcomeProjectPicker
|
|
@@ -101,7 +106,12 @@ export function ChatWelcome({
|
|
|
101
106
|
</div>
|
|
102
107
|
</div>
|
|
103
108
|
|
|
104
|
-
<ChatWelcomePromptSuggestions
|
|
109
|
+
<ChatWelcomePromptSuggestions
|
|
110
|
+
hasDraftContent={hasDraftContent}
|
|
111
|
+
hasProject={Boolean(selectedProjectRoot)}
|
|
112
|
+
continuation={continuation}
|
|
113
|
+
onSelectPrompt={onSelectPrompt}
|
|
114
|
+
/>
|
|
105
115
|
</div>
|
|
106
116
|
|
|
107
117
|
{onSelectProjectRoot ? (
|
package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-continuation.utils.test.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import type { NcpSessionSummaryView } from '@/shared/lib/api';
|
|
3
|
+
import { resolveChatWelcomeContinuation } from '@/features/chat/features/welcome/utils/chat-welcome-continuation.utils';
|
|
4
|
+
|
|
5
|
+
const summary = (overrides: Partial<NcpSessionSummaryView> = {}): NcpSessionSummaryView => ({
|
|
6
|
+
sessionId: 'original', agentId: 'main', messageCount: 2,
|
|
7
|
+
updatedAt: '2026-09-16T10:00:00Z',
|
|
8
|
+
metadata: { label: 'Project plan', project_root: '/project' },
|
|
9
|
+
...overrides,
|
|
10
|
+
});
|
|
11
|
+
const resolve = (sessions: NcpSessionSummaryView[], projectRoot = '/project') =>
|
|
12
|
+
resolveChatWelcomeContinuation({ sessions, projectRoot, defaultProjectRoot: '/default', agentId: 'main' });
|
|
13
|
+
|
|
14
|
+
describe('resolveChatWelcomeContinuation', () => {
|
|
15
|
+
it('selects by message activity without changing source ordering', () => {
|
|
16
|
+
const sessions = [summary({ sessionId: 'old', lastMessageAt: '2026-09-10T10:00:00Z' }), summary()];
|
|
17
|
+
expect(resolve(sessions)?.sessionKey).toBe('original');
|
|
18
|
+
expect(sessions[0].sessionId).toBe('old');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('excludes other agents, projects, empty, untitled and child sessions', () => {
|
|
22
|
+
expect(resolve([
|
|
23
|
+
summary({ agentId: 'other' }), summary({ messageCount: 0 }),
|
|
24
|
+
summary({ metadata: { project_root: '/other', label: 'Other' } }),
|
|
25
|
+
summary({ metadata: { project_root: '/project' } }),
|
|
26
|
+
summary({ metadata: { project_root: '/project', label: 'Child', parentSessionId: 'parent' } }),
|
|
27
|
+
])).toBeNull();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('uses the default workspace for old sessions without project metadata', () => {
|
|
31
|
+
const sessions = [summary({ metadata: { label: 'Previous discussion' } })];
|
|
32
|
+
expect(resolve(sessions, '/default')?.title).toBe('Previous discussion');
|
|
33
|
+
expect(resolve(sessions)).toBeNull();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('respects a working directory when project metadata is absent', () => {
|
|
37
|
+
expect(resolve([summary({ metadata: { label: 'Working directory' }, workingDir: '/elsewhere' })])).toBeNull();
|
|
38
|
+
expect(resolve([])).toBeNull();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { adaptNcpSessionSummaries } from '@/features/chat/features/session/utils/ncp-session-adapter.utils';
|
|
2
|
+
import type { NcpSessionSummaryView } from '@/shared/lib/api';
|
|
3
|
+
|
|
4
|
+
export type ChatWelcomeContinuation = { sessionKey: string; title: string };
|
|
5
|
+
|
|
6
|
+
export function resolveChatWelcomeContinuation(params: {
|
|
7
|
+
sessions: readonly NcpSessionSummaryView[];
|
|
8
|
+
projectRoot: string | null;
|
|
9
|
+
defaultProjectRoot: string | null;
|
|
10
|
+
agentId: string;
|
|
11
|
+
}): ChatWelcomeContinuation | null {
|
|
12
|
+
const candidates = adaptNcpSessionSummaries([...params.sessions]).filter((session) =>
|
|
13
|
+
!session.isChildSession && session.messageCount > 0 && session.label?.trim() &&
|
|
14
|
+
(session.agentId ?? 'main') === params.agentId &&
|
|
15
|
+
(session.projectRoot ?? session.workingDir ?? params.defaultProjectRoot) === params.projectRoot,
|
|
16
|
+
);
|
|
17
|
+
const activityAt = (session: typeof candidates[number]) =>
|
|
18
|
+
Date.parse(session.lastMessageAt ?? session.updatedAt) || 0;
|
|
19
|
+
const recent = candidates.sort((a, b) => activityAt(b) - activityAt(a))[0];
|
|
20
|
+
return recent ? { sessionKey: recent.key, title: recent.label!.trim() } : null;
|
|
21
|
+
}
|
package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx
CHANGED
|
@@ -359,7 +359,7 @@ function WorkspaceDirectoryBrowserReady({
|
|
|
359
359
|
|
|
360
360
|
const content = (
|
|
361
361
|
<div
|
|
362
|
-
className="flex h-full min-h-0 flex-col bg-
|
|
362
|
+
className="flex h-full min-h-0 flex-col bg-background"
|
|
363
363
|
onContextMenu={(event) => {
|
|
364
364
|
if (!(event.target as HTMLElement).closest('[data-workspace-tree-entry]')) clearSelection();
|
|
365
365
|
}}
|