@nextclaw/ui 0.24.1 → 0.24.3
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 +30 -0
- package/dist/.vite/manifest.json +2477 -0
- package/dist/assets/{abnfDiagram-VRR7QNED-BcFJp_1X.js → abnfDiagram-VRR7QNED-Kzlh3ZEC.js} +1 -1
- package/dist/assets/account-panel-BRTSwNvA.js +1 -0
- package/dist/assets/{aiden0z-pptx-renderer.es-Dp2ezlQn.js → aiden0z-pptx-renderer.es-k1xZLzeo.js} +1 -1
- package/dist/assets/api-BnUzdltV.js +13 -0
- package/dist/assets/app-data-Bjh_zM45.js +1 -0
- package/dist/assets/app-presenter-provider-CBt-lyr_.js +109 -0
- package/dist/assets/app-presenter-provider-D3BuuOyZ.css +1 -0
- package/dist/assets/appearance-settings-page-BrOYSgG0.js +1 -0
- package/dist/assets/{arc-CkgyPMyW.js → arc-CpivM836.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-CVRF_cYQ.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-CMd4cIjI.js → architectureDiagram-ZJ3FMSHR-ifjW1qjI.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-Bz3tbhet.js → blockDiagram-677ZJIJ3-C_zeJrKF.js} +1 -1
- package/dist/assets/{book-open-o2x7OLiO.js → book-open-xqEj1OLE.js} +1 -1
- package/dist/assets/boxes-D6uPnkGo.js +1 -0
- package/dist/assets/{c4Diagram-LMCZKHZV-D9hFNAGv.js → c4Diagram-LMCZKHZV-CpapRftp.js} +1 -1
- package/dist/assets/card-CS8su2Zh.js +1 -0
- package/dist/assets/channel-CBrWRr4N.js +1 -0
- package/dist/assets/channels-list-page-BE0TxB3B.js +8 -0
- package/dist/assets/chevron-down-BL-yMYcX.js +1 -0
- package/dist/assets/chunk-2Q5K7J3B-B8mmRk7d.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-7NrjEITq.js → chunk-32BRIVSS-BKBwdmKR.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-viIcqj9q.js → chunk-52WLFC77-BgZRCpDx.js} +1 -1
- package/dist/assets/{chunk-5FCAYU7R-Vsu4J-VM.js → chunk-5FCAYU7R-YWfOINJi.js} +1 -1
- package/dist/assets/{chunk-5HE753X5-C-w6CQZK.js → chunk-5HE753X5-BZ6I07d2.js} +1 -1
- package/dist/assets/{chunk-5JV3BV7I-CuKgJQ4W.js → chunk-5JV3BV7I-B7QYgZU5.js} +1 -1
- package/dist/assets/{chunk-5TONJI2A-CYeiWZKb.js → chunk-5TONJI2A-DjyQwgL2.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-DRCbfwIn.js → chunk-5VM5RSS4-DheHV7X2.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-BvydOcm3.js → chunk-7BUUIJ7U-D6bq2PKF.js} +1 -1
- package/dist/assets/{chunk-BIQX33UG-RlppOXKo.js → chunk-BIQX33UG-CL9x0ibm.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-DAizzYwr.js → chunk-C7G6YPKG-8z3B6RUH.js} +1 -1
- package/dist/assets/{chunk-CQNSW5MT-5eChJHca.js → chunk-CQNSW5MT-DpHkxY3n.js} +1 -1
- package/dist/assets/{chunk-CYSBUYHQ-YHPr53fv.js → chunk-CYSBUYHQ-DIJDLsdJ.js} +1 -1
- package/dist/assets/{chunk-EMLP6XTP-CK4D7Hz5.js → chunk-EMLP6XTP-B-LjAyVd.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-BmlDFIRW.js → chunk-EX3LRPZG-BChuEPvO.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-D0ksHZZ9.js → chunk-FWX5IMBZ-fBFt0u3f.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-DPkq8FCm.js → chunk-HOUHSVGY-MD0SpW5A.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-FAatv5fC.js → chunk-ICXQ74PX-DvCcw_hz.js} +1 -1
- package/dist/assets/{chunk-JG7HCLWE-DLkIi4F7.js → chunk-JG7HCLWE-B8zqBnU9.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-DawOjNE3.js → chunk-JWPE2WC7-C9efnkGb.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-Di52TorW.js → chunk-MOJQB5TN-gXbfqoqq.js} +1 -1
- package/dist/assets/{chunk-MOZMSUNE-PfyK9w1-.js → chunk-MOZMSUNE-twIwdkqC.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-C3jdH3Ty.js → chunk-OGEWGWER-DdR0_cWK.js} +1 -1
- package/dist/assets/{chunk-OSBZ3O6U-CecHo-f0.js → chunk-OSBZ3O6U-D7D58Foa.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-f3IJh3sN.js → chunk-PUDLZKDR-DPILgOVY.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-DQFeUPxZ.js → chunk-Q4XR5HBZ-C0JJx7lW.js} +1 -1
- package/dist/assets/{chunk-QBLGF6JB-BhUeG0y2.js → chunk-QBLGF6JB-Dbsf69ng.js} +1 -1
- package/dist/assets/{chunk-R7FJI6CG-C3XpZ-2u.js → chunk-R7FJI6CG-Bb8n616-.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-CAqa5klQ.js → chunk-RYQCIY6F-1HOsOrSl.js} +1 -1
- package/dist/assets/{chunk-U6XO7XAA-D_WXezeD.js → chunk-U6XO7XAA-BAFDVb1v.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-CZ70oOtp.js → chunk-V7JOEXUC-8-g68lu5.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-Cpml0inz.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-B7AHEYYk.js → chunk-VR4S4FIN-P6UGmaYd.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-Dn9To_OI.js → chunk-WYO6CB5R-6wjFTXNP.js} +2 -2
- package/dist/assets/chunk-XXDRQBXY-nCiqnCpF.js +1 -0
- package/dist/assets/{chunk-YOTPTUD7-BYEgRBk3.js → chunk-YOTPTUD7-CLYXVZAi.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-C6YtZDU0.js → chunk-ZGVPDNZ5-BRTmSAhp.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-DMuYtnHF.js → chunk-ZIRB5QZD-CH_1eoSV.js} +1 -1
- package/dist/assets/circle-alert-lSa3LRvS.js +1 -0
- package/dist/assets/circle-dashed-CU3yApvP.js +1 -0
- package/dist/assets/classDiagram-OUVF2IWQ-C-DRqAaW.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-DXCcZ42U.js +1 -0
- package/dist/assets/client-BtGBwLTs.js +1 -0
- package/dist/assets/config-split-page-BxDwwAGa.js +1 -0
- package/dist/assets/confirm-dialog-S5JxZcS1.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-Bc2Ex5Y3.js → cose-bilkent-JH36ORCC-L7w_qScX.js} +1 -1
- package/dist/assets/{createLucideIcon-rwwpqyks.js → createLucideIcon-BNKf0_kc.js} +1 -1
- package/dist/assets/cynefin-VYW2F7L2-2SOTgxxC.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-DVysQoGz.js → cynefinDiagram-TSTJHNR4-Bay7uDSR.js} +1 -1
- package/dist/assets/{dagre-CMhQ1cAG.js → dagre-CJ_hX8xv.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-RYyWpPJZ.js → dagre-VKFMJZFB-DDhk-2B3.js} +1 -1
- package/dist/assets/desktop-capabilities-page-BwHxJpbl.js +1 -0
- package/dist/assets/desktop-update-config-Bfg7OdJ2.js +1 -0
- package/dist/assets/{diagram-FQU43EPY-BD6KONdF.js → diagram-FQU43EPY-somFq5y8.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-CGB2ptRR.js → diagram-G47NLZAW-hzgyQsPd.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-DnkOI6cU.js → diagram-NH7WQ7WH-BkJ4gEQJ.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-DF82RZ7P.js → diagram-OA4YK3LP-CS3ZkK4w.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-Be2v7Ck9.js → diagram-WEI45ONY-BApo-JHS.js} +1 -1
- package/dist/assets/dialog-Xe73hpQz.js +5 -0
- package/dist/assets/dist-BiIcnf9j.js +1 -0
- package/dist/assets/dist-C5I0v8Qn.js +1 -0
- package/dist/assets/{dist--ta5rX12.js → dist-Cnhwure9.js} +1 -1
- package/dist/assets/{dist-aNN3iQxV.js → dist-czPa8xFO.js} +1 -1
- package/dist/assets/doc-browser-BgRP0Wni.js +1 -0
- package/dist/assets/doc-browser-C8eqJLi_.js +1 -0
- package/dist/assets/doc-browser-context-BPCDFcC-.js +1 -0
- package/dist/assets/{docx-preview-BqwAjrj3.js → docx-preview-ByCKKIVT.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-CP98OYk8.js → ebnfDiagram-CCIWWBDH-DWjfeEie.js} +1 -1
- package/dist/assets/ellipsis-C5YXdOUx.js +1 -0
- package/dist/assets/{erDiagram-Q63AITRT-ZLlx8xfs.js → erDiagram-Q63AITRT-DR7vWYHM.js} +1 -1
- package/dist/assets/es2015-cuwbYI-l.js +41 -0
- package/dist/assets/eventmodeling-45OFAUF4-CXZNG56U.js +1 -0
- package/dist/assets/extensions-DgKQRebe.js +1 -0
- package/dist/assets/eye-C84inPcV.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-2065oyKr.js +1 -0
- package/dist/assets/form-actions-AIdXOoCL.js +1 -0
- package/dist/assets/{ganttDiagram-NO4QXBWP-DXCDjHR2.js → ganttDiagram-NO4QXBWP-E3l9tuaL.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-B0Ln3ZuK.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-l2HWrTJp.js → gitGraphDiagram-IHSO6WYX-DiMvbHKf.js} +1 -1
- package/dist/assets/i18n-CKvm9zyk.js +2 -0
- package/dist/assets/i18n-provider-CPV43pMX.js +1 -0
- package/dist/assets/info-DKCQHKI2-B06uqGM4.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-D-DjX-bn.js → infoDiagram-FWYZ7A6U-BZDL0NDJ.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-y_Xy128F.js → ishikawaDiagram-FXEZZL3T-BZ9WvJb2.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-DJn5xYcQ.js → journeyDiagram-5HDEW3XC-C3TZvKM8.js} +1 -1
- package/dist/assets/{jszip.min-8hyJpgpx.js → jszip.min-D_AtKL_8.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-DJVIOR21.js → kanban-definition-HUTT4EX6-9FqauDEi.js} +1 -1
- package/dist/assets/{line-Cos7PIOj.js → line-Ca49mj80.js} +1 -1
- package/dist/assets/{linear-BtDLqtzF.js → linear-DlCeG66S.js} +1 -1
- package/dist/assets/loader-circle-K1BDdHR5.js +1 -0
- package/dist/assets/login-page-ClcrvN04.js +1 -0
- package/dist/assets/login-page-DeDQjVxv.js +1 -0
- package/dist/assets/logo-badge-C-5-zim6.js +1 -0
- package/dist/assets/main-DGqlaAaI.css +1 -0
- package/dist/assets/main-i18n-catalog.config-CpNF5aVc.js +1 -0
- package/dist/assets/main-nMVfHb5K.js +2 -0
- package/dist/assets/{map-BKnQyvd0.js → map-WMnNq9UV.js} +1 -1
- package/dist/assets/mcp-marketplace-page-CWjJGp_D.js +10 -0
- package/dist/assets/mcp-marketplace-page-fvu2NcXT.js +1 -0
- package/dist/assets/{mermaid-parser.core-XUNZhr2W.js → mermaid-parser.core-B8xk4hpS.js} +2 -2
- package/dist/assets/{mermaid.core-ySrvolIe.js → mermaid.core-CFPiczKH.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-BypL9tei.js → mindmap-definition-LN4V7U3C-CnxA52L6.js} +1 -1
- package/dist/assets/model-config-page-Dv_zE7HN.js +1 -0
- package/dist/assets/{navigation-link-C_6oj3zz.js → navigation-link-BAQjgx2F.js} +1 -1
- package/dist/assets/{ordinal-CxxVWxYU.js → ordinal-PgiFlfBJ.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-CHx-igbz.js +1 -0
- package/dist/assets/panel-app-BUUle0gP.js +1 -0
- package/dist/assets/panel-app-i18n-catalog.config-BzxE3tZb.js +1 -0
- package/dist/assets/panelStandalone-CFRBHV94.js +2 -0
- package/dist/assets/panelStandalone-Y91OJkgV.css +1 -0
- package/dist/assets/{pegDiagram-2B236MQR-D-U2KBGv.js → pegDiagram-2B236MQR-A8oz7dTH.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-DOaMc-x9.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-CBi3GusJ.js → pieDiagram-ENE6RG2P-mtBnkYY0.js} +1 -1
- package/dist/assets/plus-LA8-jpxP.js +1 -0
- package/dist/assets/popover-NkrFlWHp.js +1 -0
- package/dist/assets/privacy-settings-page-D6uc9f-A.js +1 -0
- package/dist/assets/projects-BD1rG75R.js +1 -0
- package/dist/assets/provider-models-5PGHb6mP.js +1 -0
- package/dist/assets/provider-scoped-model-input-DUa_9uwg.js +1 -0
- package/dist/assets/providers-config-page-DAiqxlF_.js +1 -0
- package/dist/assets/puzzle-D6gulz7u.js +1 -0
- package/dist/assets/pwa-C_Zte1xe.js +1 -0
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-H0ZuvnZL.js → quadrantDiagram-ABIIQ3AL-DE1VybGO.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-CXsdndDk.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-DxgXdrYP.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-CR1tnyjz.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-CjjxZR2U.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-DgVGJCHN.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-D7Y2EqSd.js → railroadDiagram-RFXS5EU6-u9EMg14B.js} +1 -1
- package/dist/assets/{refresh-cw-DsT2kvXi.js → refresh-cw-h9Xq3LY3.js} +1 -1
- package/dist/assets/remote-BO0QP7ua.js +1 -0
- package/dist/assets/{requirementDiagram-TGXJPOKE-BiXNX1NN.js → requirementDiagram-TGXJPOKE-BAWHAqEi.js} +1 -1
- package/dist/assets/{rotate-cw-BCAs6c3R.js → rotate-cw-B6xm41Wn.js} +1 -1
- package/dist/assets/runtime-config-page-w1UAkGF_.js +1 -0
- package/dist/assets/{sankeyDiagram-HTMAVEWB-qzDeLztW.js → sankeyDiagram-HTMAVEWB-aDy-jdwF.js} +1 -1
- package/dist/assets/{save-CadRMTMQ.js → save-fff_WpY2.js} +1 -1
- package/dist/assets/{search-B6tB4fzB.js → search-CUe41wjm.js} +1 -1
- package/dist/assets/search-config-page-3xbhRlW2.js +1 -0
- package/dist/assets/secrets-config-page-Dn8_rdOj.js +3 -0
- package/dist/assets/security-config-Y1nEGM3A.js +1 -0
- package/dist/assets/select-CG5YWnwe.js +1 -0
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-BtRbPQtL.js → sequenceDiagram-DBY2YBRQ-DwHC4mbX.js} +1 -1
- package/dist/assets/service-apps-panel-CGc04aMn.js +1 -0
- package/dist/assets/settings-2-CE3ELQyk.js +1 -0
- package/dist/assets/{sizeCapture-X5ZJPWSS-CMYvM3SL.js → sizeCapture-X5ZJPWSS-oOMY0Fag.js} +1 -1
- package/dist/assets/skeleton-BL9h32W7.js +1 -0
- package/dist/assets/{src-Bw-mzbQb.js → src-CLPoo5iL.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-BJ-mFeOz.js → stateDiagram-2N3HPSRC-B0Epk-VR.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-Ct4zTw8P.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-BsucVOO2.js → swimlanes-5IMT3BWC-T0w-Iuzf.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-CdmN0PBd.js +8 -0
- package/dist/assets/tabs-BuE0qKMh.js +1 -0
- package/dist/assets/{tag-chip-BZKk0UkK.js → tag-chip-BDzpHEli.js} +1 -1
- package/dist/assets/theme-provider-B6FinATQ.js +1 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-Bicewlzo.js → timeline-definition-FHXFAJF6-BEonB5Np.js} +1 -1
- package/dist/assets/tooltip-DYcuWhuP.js +1 -0
- package/dist/assets/trash-2-BPPYt2NV.js +1 -0
- package/dist/assets/treeView-QDETBFTQ-Dad4_Wc7.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-9_GWWZsY.js +1 -0
- package/dist/assets/use-config-BPUM2lbo.js +1 -0
- package/dist/assets/use-desktop-capabilities-BDjArQP3.js +1 -0
- package/dist/assets/use-panel-app-scroll-restoration-DsV1IJx-.js +1 -0
- package/dist/assets/use-viewport-layout-BS18drMT.js +1 -0
- package/dist/assets/utils-CBZPzC_b.js +8 -0
- package/dist/assets/{vennDiagram-L72KCM5P-BxOOnO9x.js → vennDiagram-L72KCM5P-BDvcOCo2.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-BXpvyee9.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-Cl7NltMv.js → wardleyDiagram-EHGQE667-jMLMgjzE.js} +1 -1
- package/dist/assets/x-DdXOqLnX.js +1 -0
- package/dist/assets/{xychartDiagram-FW5EYKEG-DiMIxQ7N.js → xychartDiagram-FW5EYKEG-pzrpclEv.js} +1 -1
- package/dist/index.html +56 -25
- package/dist/panel-standalone.html +30 -0
- package/package.json +4 -4
- package/panel-standalone.html +13 -0
- package/panel-standalone.tailwind.config.js +16 -0
- package/src/app/components/app-presenter-provider.tsx +8 -1
- package/src/app/components/theme-provider.tsx +0 -5
- package/src/app/index.tsx +18 -4
- package/src/app/presenters/app.presenter.ts +4 -4
- package/src/app/styles/panel-app-standalone.css +31 -0
- package/src/app/test/vitest-setup.ts +3 -0
- package/src/features/account/hooks/use-auth.ts +7 -57
- package/src/features/account/index.ts +3 -2
- package/src/features/apps/components/__tests__/apps-panel.test.tsx +7 -5
- package/src/features/apps/components/apps-panel.tsx +9 -3
- package/src/features/chat/features/message/utils/__tests__/chat-message-timeline.utils.test.ts +10 -0
- package/src/features/chat/features/session/components/__tests__/chat-sidebar-project-groups.test.tsx +90 -6
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +64 -2
- package/src/features/chat/features/session/utils/__tests__/chat-sidebar-session-groups.utils.test.ts +27 -2
- package/src/features/chat/features/session/utils/chat-sidebar-session-groups.utils.ts +0 -11
- package/src/features/panel-apps/components/__tests__/panel-app-list-item.test.tsx +18 -0
- package/src/features/panel-apps/components/__tests__/panel-app-open-standalone-menu-item.test.tsx +57 -0
- package/src/features/panel-apps/components/__tests__/panel-app-toolbar.test.tsx +15 -0
- package/src/features/panel-apps/components/panel-app-list-item.tsx +5 -0
- package/src/features/panel-apps/components/panel-app-open-standalone-menu-item.tsx +32 -0
- package/src/features/panel-apps/components/panel-app-runtime-surface.tsx +141 -0
- package/src/features/{service-apps/components/service-action-authorization-dialog.tsx → panel-apps/components/panel-app-service-action-authorization-dialog.tsx} +4 -4
- package/src/features/panel-apps/components/panel-app-toolbar.tsx +5 -0
- package/src/features/panel-apps/hooks/use-panel-app-client-grant.ts +2 -2
- package/src/features/panel-apps/hooks/{use-panel-app-main-runtime.ts → use-panel-app-runtime.ts} +7 -5
- package/src/features/panel-apps/hooks/use-panel-apps.ts +14 -0
- package/src/features/panel-apps/index.ts +5 -0
- package/src/features/panel-apps/managers/__tests__/panel-app-bridge.manager.test.ts +2 -2
- package/src/features/panel-apps/managers/panel-app-bridge.manager.ts +2 -2
- package/src/features/panel-apps/managers/panel-app-service-action-authorization.manager.ts +10 -0
- package/src/features/panel-apps/pages/__tests__/panel-app-main-page.test.tsx +12 -3
- package/src/features/panel-apps/pages/__tests__/panel-app-standalone-page.test.tsx +63 -0
- package/src/features/panel-apps/pages/panel-app-main-page.tsx +9 -121
- package/src/features/panel-apps/pages/panel-app-standalone-page.tsx +29 -0
- package/src/features/panel-apps/presenters/panel-app-host.presenter.ts +9 -0
- package/src/features/panel-apps/providers/panel-app-host.provider.tsx +45 -0
- package/src/features/panel-apps/routes/__tests__/panel-app-standalone.route.test.tsx +50 -0
- package/src/features/panel-apps/routes/panel-app-standalone.route.tsx +94 -0
- package/src/features/{service-apps/stores/service-action-authorization.store.ts → panel-apps/stores/panel-app-service-action-authorization.store.ts} +6 -6
- package/src/features/projects/AGENTS.md +1 -2
- package/src/features/projects/components/project-agreement.tsx +36 -77
- package/src/features/projects/components/project-artifacts.test.tsx +90 -62
- package/src/features/projects/components/project-artifacts.tsx +81 -160
- package/src/features/projects/components/project-materials.test.tsx +80 -0
- package/src/features/projects/components/project-overview.test.tsx +80 -0
- package/src/features/projects/components/project-overview.tsx +115 -56
- package/src/features/projects/components/project-skills.tsx +24 -14
- package/src/features/projects/components/work/project-work-item-drawer.test.tsx +3 -2
- package/src/features/projects/components/work/project-work-item-drawer.tsx +8 -10
- package/src/features/projects/components/work/project-work-items.test.tsx +180 -4
- package/src/features/projects/components/work/project-work-items.tsx +278 -50
- package/src/features/projects/components/work/project-work-state-settings.tsx +7 -3
- package/src/features/projects/hooks/use-project-materials.test.tsx +65 -0
- package/src/features/projects/hooks/use-project-materials.ts +24 -0
- package/src/features/projects/hooks/use-project-work.test.tsx +165 -7
- package/src/features/projects/hooks/use-project-work.ts +88 -9
- package/src/features/projects/pages/project-home-page.tsx +52 -89
- package/src/features/projects/pages/projects-page.test.tsx +81 -32
- package/src/features/projects/presenters/project-home.presenter.test.ts +1 -64
- package/src/features/projects/presenters/project-home.presenter.ts +17 -54
- package/src/features/projects/utils/project-artifact-view.utils.test.ts +19 -53
- package/src/features/projects/utils/project-artifact-view.utils.ts +17 -47
- package/src/features/projects/utils/project-work-state-label.utils.test.ts +28 -0
- package/src/features/projects/utils/project-work-state-label.utils.ts +20 -0
- package/src/features/service-apps/index.ts +3 -3
- package/src/main.tsx +3 -0
- package/src/shared/hooks/use-auth-status.ts +49 -0
- package/src/shared/hooks/use-projects.ts +15 -1
- package/src/shared/lib/api/projects/project.utils.ts +4 -0
- package/src/shared/lib/i18n/configs/main-i18n-catalog.config.ts +78 -0
- package/src/shared/lib/i18n/configs/panel-app-i18n-catalog.config.ts +12 -0
- package/src/shared/lib/i18n/index.ts +30 -82
- package/src/shared/lib/i18n/locales/en-US/doc-browser.json +0 -55
- package/src/shared/lib/i18n/locales/en-US/panel-app.json +59 -0
- package/src/shared/lib/i18n/locales/en-US/projects.json +24 -59
- package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +0 -55
- package/src/shared/lib/i18n/locales/zh-CN/panel-app.json +59 -0
- package/src/shared/lib/i18n/locales/zh-CN/projects.json +24 -59
- package/vite.config.ts +36 -1
- package/dist/assets/api-BqVIq0lF.js +0 -13
- package/dist/assets/appearance-settings-page-CTWn1eAT.js +0 -1
- package/dist/assets/architecture-TIHT7OUA-DO2x53FK.js +0 -1
- package/dist/assets/channel-nBvMaVyP.js +0 -1
- package/dist/assets/channels-list-page-Bzn-pzyJ.js +0 -8
- package/dist/assets/chunk-2Q5K7J3B-CJgqFDS4.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-BGvh3yIx.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-DaBxG5gs.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-P6N03G2R.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-B1_uLvMv.js +0 -1
- package/dist/assets/config-split-page-CnRbXXlh.js +0 -1
- package/dist/assets/confirm-dialog-B_Hbcra2.js +0 -5
- package/dist/assets/cynefin-VYW2F7L2-B-H8Qp-n.js +0 -1
- package/dist/assets/desktop-capabilities-page-C2ayYQTr.js +0 -1
- package/dist/assets/desktop-update-config-C13czpyL.js +0 -1
- package/dist/assets/dist-BsF3hfOi.js +0 -1
- package/dist/assets/doc-browser-D8dIOo9E.js +0 -1
- package/dist/assets/doc-browser-DcuOOtpP.js +0 -1
- package/dist/assets/doc-browser-context-Dhsit2Ma.js +0 -1
- package/dist/assets/eventmodeling-45OFAUF4-YVtShyFA.js +0 -1
- package/dist/assets/extensions-CD6xvKF_.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-BeKXabVO.js +0 -1
- package/dist/assets/form-actions-CC4Wz_lL.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-jTSiBj-p.js +0 -1
- package/dist/assets/index-BTsbdtv6.js +0 -109
- package/dist/assets/index-Bcfy2kTh.css +0 -1
- package/dist/assets/info-DKCQHKI2-BIporNWb.js +0 -1
- package/dist/assets/loader-circle-B6aFbB-8.js +0 -1
- package/dist/assets/mcp-marketplace-page-BtUAypA7.js +0 -1
- package/dist/assets/mcp-marketplace-page-r2MmD9xO.js +0 -10
- package/dist/assets/model-config-page-DboxoT-I.js +0 -1
- package/dist/assets/packet-7NZHBO7P-CuFMADV0.js +0 -1
- package/dist/assets/pie-RZYD4A2V-XUeIXhM9.js +0 -1
- package/dist/assets/plus-DRsq9Kvs.js +0 -1
- package/dist/assets/privacy-settings-page-C2sDBqhb.js +0 -1
- package/dist/assets/projects-BcPcx-uD.js +0 -1
- package/dist/assets/providers-config-page-CmUFl9RF.js +0 -1
- package/dist/assets/radar-I7S5WNFK-D-NNGh1k.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-C67_uDaM.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-BZ8Yflnd.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-B7zO7RoK.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-R63PTgLz.js +0 -1
- package/dist/assets/react-BjO9I4WZ.js +0 -8
- package/dist/assets/remote-Ci6x91ES.js +0 -1
- package/dist/assets/runtime-config-page-cQKNeAjL.js +0 -1
- package/dist/assets/search-config-page-C8lOIkxn.js +0 -1
- package/dist/assets/secrets-config-page-8clzAag2.js +0 -3
- package/dist/assets/security-config-DPbM6IVT.js +0 -1
- package/dist/assets/select-CO9S_C2C.js +0 -41
- package/dist/assets/skeleton-IHILNhIW.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-BE-HqxOK.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-Dr1H9LJH.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-npJ5dbqS.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-pYrBx6oa.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-CmSRKLR8.js +0 -1
- package/dist/assets/x-BuvHIb1d.js +0 -1
- package/src/features/projects/components/project-requests.tsx +0 -57
- package/src/features/projects/components/project-runs.tsx +0 -60
- package/src/features/projects/hooks/use-project-observation.test.tsx +0 -93
- package/src/features/projects/hooks/use-project-observation.ts +0 -115
- package/src/features/projects/utils/project-request-response.utils.test.ts +0 -44
- package/src/features/projects/utils/project-request-response.utils.ts +0 -39
- package/src/features/service-apps/managers/service-action-authorization.manager.ts +0 -10
- /package/dist/assets/{array-BQVzeGRt.js → array-BHDgItFN.js} +0 -0
- /package/dist/assets/{chunk-DseTPa7n.js → chunk-DF37yw5_.js} +0 -0
- /package/dist/assets/{chunk-KEIR6QF5-f9psyCXK.js → chunk-KEIR6QF5-DstBw0Hk.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-D1mAU_Po.js → chunk-Y2CYZVJY-CA3ymQuH.js} +0 -0
- /package/dist/assets/{config-hints-nV5HPOvq.js → config-hints-CBPHrfYk.js} +0 -0
- /package/dist/assets/{cytoscape.esm-0uDtdD0l.js → cytoscape.esm-C7xr90o_.js} +0 -0
- /package/dist/assets/{defaultLocale-DSWXGgt0.js → defaultLocale-BG1oDVag.js} +0 -0
- /package/dist/assets/{graphlib-CQ6QV4yP.js → graphlib-CNMGfuTb.js} +0 -0
- /package/dist/assets/{host-capabilities-Tk038i04.js → host-capabilities-B107nwS3.js} +0 -0
- /package/dist/assets/{init-Y6h9jGtZ.js → init-wQIZuRSH.js} +0 -0
- /package/dist/assets/{katex-ARhY9PS1.js → katex-J8JuvgNl.js} +0 -0
- /package/dist/assets/{middleware-DXsbf9xI.js → middleware-0o3JF3tS.js} +0 -0
- /package/dist/assets/{path-10BjdyLh.js → path-N-C4MRP0.js} +0 -0
- /package/dist/assets/{preload-helper-D4M6sveU.js → preload-helper-ca-nBW7U.js} +0 -0
- /package/dist/assets/{rough.esm-DxgC_14r.js → rough.esm-BeWA068d.js} +0 -0
- /package/dist/assets/{xlsx-DrDuDNAa.js → xlsx-CwUXNtD3.js} +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
useMemo,
|
|
5
|
+
type Context,
|
|
6
|
+
type ReactNode,
|
|
7
|
+
} from "react";
|
|
8
|
+
import { PanelAppHostPresenter } from "@/features/panel-apps/presenters/panel-app-host.presenter";
|
|
9
|
+
|
|
10
|
+
type PanelAppHostContextGlobal = typeof globalThis & {
|
|
11
|
+
__NEXTCLAW_PANEL_APP_HOST_CONTEXT__?: Context<PanelAppHostPresenter | null>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const contextGlobal = globalThis as PanelAppHostContextGlobal;
|
|
15
|
+
const PanelAppHostContext =
|
|
16
|
+
contextGlobal.__NEXTCLAW_PANEL_APP_HOST_CONTEXT__ ??
|
|
17
|
+
createContext<PanelAppHostPresenter | null>(null);
|
|
18
|
+
|
|
19
|
+
contextGlobal.__NEXTCLAW_PANEL_APP_HOST_CONTEXT__ = PanelAppHostContext;
|
|
20
|
+
|
|
21
|
+
export function PanelAppHostProvider({
|
|
22
|
+
children,
|
|
23
|
+
presenter: providedPresenter,
|
|
24
|
+
}: {
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
presenter?: PanelAppHostPresenter;
|
|
27
|
+
}) {
|
|
28
|
+
const presenter = useMemo(
|
|
29
|
+
() => providedPresenter ?? new PanelAppHostPresenter(),
|
|
30
|
+
[providedPresenter],
|
|
31
|
+
);
|
|
32
|
+
return (
|
|
33
|
+
<PanelAppHostContext.Provider value={presenter}>
|
|
34
|
+
{children}
|
|
35
|
+
</PanelAppHostContext.Provider>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function usePanelAppHostPresenter(): PanelAppHostPresenter {
|
|
40
|
+
const presenter = useContext(PanelAppHostContext);
|
|
41
|
+
if (!presenter) {
|
|
42
|
+
throw new Error("usePanelAppHostPresenter must be used inside PanelAppHostProvider");
|
|
43
|
+
}
|
|
44
|
+
return presenter;
|
|
45
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import {
|
|
4
|
+
PanelAppStandaloneRoute,
|
|
5
|
+
readStandalonePanelAppId,
|
|
6
|
+
} from '@/features/panel-apps/routes/panel-app-standalone.route';
|
|
7
|
+
|
|
8
|
+
vi.mock('sonner', () => ({
|
|
9
|
+
Toaster: () => <div data-testid="toaster" />,
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
vi.mock('@/shared/hooks/use-auth-status', () => ({
|
|
13
|
+
isTransientAuthStatusBootstrapError: () => false,
|
|
14
|
+
useAuthStatus: () => ({
|
|
15
|
+
data: { authenticated: true, enabled: false },
|
|
16
|
+
isError: false,
|
|
17
|
+
isLoading: false,
|
|
18
|
+
}),
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
vi.mock('@/features/panel-apps/pages/panel-app-standalone-page', () => ({
|
|
22
|
+
PanelAppStandalonePage: ({ appId }: { appId: string }) => (
|
|
23
|
+
<main data-testid="standalone-panel-app" data-app-id={appId} />
|
|
24
|
+
),
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
vi.mock('@/features/panel-apps/providers/panel-app-host.provider', () => ({
|
|
28
|
+
PanelAppHostProvider: ({ children }: { children: React.ReactNode }) => children,
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
vi.mock('@/features/panel-apps/components/panel-app-service-action-authorization-dialog', () => ({
|
|
32
|
+
PanelAppServiceActionAuthorizationDialog: () => <div data-testid="authorization-dialog" />,
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
describe('PanelAppStandaloneRoute', () => {
|
|
36
|
+
it('parses only the dedicated standalone route', () => {
|
|
37
|
+
expect(readStandalonePanelAppId('/apps/panel/publisher.todo/standalone')).toBe('publisher.todo');
|
|
38
|
+
expect(readStandalonePanelAppId('/apps/panel/a%20b/standalone/')).toBe('a b');
|
|
39
|
+
expect(readStandalonePanelAppId('/apps/panel/publisher.todo')).toBeNull();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('renders the lightweight Panel host for the requested app', () => {
|
|
43
|
+
render(<PanelAppStandaloneRoute pathname="/apps/panel/publisher.todo/standalone" />);
|
|
44
|
+
|
|
45
|
+
expect(screen.getByTestId('standalone-panel-app').getAttribute('data-app-id'))
|
|
46
|
+
.toBe('publisher.todo');
|
|
47
|
+
expect(screen.getByTestId('authorization-dialog')).toBeTruthy();
|
|
48
|
+
expect(screen.getByTestId('toaster')).toBeTruthy();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { lazy, StrictMode, Suspense } from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import { QueryClientProvider } from '@tanstack/react-query';
|
|
4
|
+
import { Toaster } from 'sonner';
|
|
5
|
+
import { appQueryClient } from '@/app-query-client';
|
|
6
|
+
import { I18nProvider } from '@/app/components/i18n-provider';
|
|
7
|
+
import { ThemeProvider } from '@/app/components/theme-provider';
|
|
8
|
+
import { PanelAppStandalonePage } from '@/features/panel-apps/pages/panel-app-standalone-page';
|
|
9
|
+
import { PanelAppHostProvider } from '@/features/panel-apps/providers/panel-app-host.provider';
|
|
10
|
+
import { PanelAppServiceActionAuthorizationDialog } from '@/features/panel-apps/components/panel-app-service-action-authorization-dialog';
|
|
11
|
+
import { installPanelAppI18nCatalog, t } from '@/shared/lib/i18n';
|
|
12
|
+
import { isTransientAuthStatusBootstrapError, useAuthStatus } from '@/shared/hooks/use-auth-status';
|
|
13
|
+
import '@/app/styles/panel-app-standalone.css';
|
|
14
|
+
|
|
15
|
+
const LoginPage = lazy(async () => ({
|
|
16
|
+
default: (await import('@/features/account/components/login-page')).LoginPage,
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
const PANEL_APP_STANDALONE_PATH = /^\/apps\/panel\/([^/]+)\/standalone\/?$/;
|
|
20
|
+
|
|
21
|
+
export function readStandalonePanelAppId(pathname: string): string | null {
|
|
22
|
+
const match = PANEL_APP_STANDALONE_PATH.exec(pathname);
|
|
23
|
+
if (!match) return null;
|
|
24
|
+
try {
|
|
25
|
+
return decodeURIComponent(match[1]);
|
|
26
|
+
} catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function StandaloneAuthGate({ appId }: { appId: string }) {
|
|
32
|
+
const authStatus = useAuthStatus();
|
|
33
|
+
const isTransientBootstrapFailure =
|
|
34
|
+
authStatus.isError && isTransientAuthStatusBootstrapError(authStatus.error);
|
|
35
|
+
|
|
36
|
+
if (
|
|
37
|
+
(authStatus.isLoading && !authStatus.isError) ||
|
|
38
|
+
isTransientBootstrapFailure ||
|
|
39
|
+
authStatus.isError
|
|
40
|
+
) {
|
|
41
|
+
return <PanelAppStandalonePage appId={appId} />;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (authStatus.data?.enabled && !authStatus.data.authenticated) {
|
|
45
|
+
return (
|
|
46
|
+
<Suspense fallback={<StandaloneStatus message={t('loading')} />}>
|
|
47
|
+
<LoginPage username={authStatus.data.username} />
|
|
48
|
+
</Suspense>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return <PanelAppStandalonePage appId={appId} />;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function StandaloneStatus({ message }: { message: string }) {
|
|
56
|
+
return (
|
|
57
|
+
<main className="flex h-dvh items-center justify-center bg-background px-6 text-sm text-muted-foreground">
|
|
58
|
+
{message}
|
|
59
|
+
</main>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function PanelAppStandaloneRoute({ pathname = window.location.pathname }: { pathname?: string }) {
|
|
64
|
+
const appId = readStandalonePanelAppId(pathname);
|
|
65
|
+
|
|
66
|
+
if (!appId) {
|
|
67
|
+
return <StandaloneStatus message={t('panelAppsMainUnavailable')} />;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<QueryClientProvider client={appQueryClient}>
|
|
72
|
+
<PanelAppHostProvider>
|
|
73
|
+
<StandaloneAuthGate appId={appId} />
|
|
74
|
+
<PanelAppServiceActionAuthorizationDialog />
|
|
75
|
+
<Toaster position="top-right" richColors offset={16} />
|
|
76
|
+
</PanelAppHostProvider>
|
|
77
|
+
</QueryClientProvider>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
await installPanelAppI18nCatalog();
|
|
82
|
+
|
|
83
|
+
const rootElement = document.getElementById('root');
|
|
84
|
+
if (rootElement) {
|
|
85
|
+
createRoot(rootElement).render(
|
|
86
|
+
<StrictMode>
|
|
87
|
+
<ThemeProvider>
|
|
88
|
+
<I18nProvider>
|
|
89
|
+
<PanelAppStandaloneRoute />
|
|
90
|
+
</I18nProvider>
|
|
91
|
+
</ThemeProvider>
|
|
92
|
+
</StrictMode>,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
@@ -3,28 +3,28 @@ import type { ServiceActionListView } from '@nextclaw/client-sdk';
|
|
|
3
3
|
|
|
4
4
|
type ServiceActionRisk = ServiceActionListView['actions'][number]['risk'];
|
|
5
5
|
|
|
6
|
-
export type
|
|
6
|
+
export type PanelAppServiceActionAuthorizationItem = {
|
|
7
7
|
actionId: string;
|
|
8
8
|
actionTitle?: string;
|
|
9
9
|
actionDescription?: string;
|
|
10
10
|
risk?: ServiceActionRisk;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
export type
|
|
13
|
+
export type PanelAppServiceActionAuthorizationRequest = {
|
|
14
14
|
id: string;
|
|
15
15
|
panelAppId: string;
|
|
16
|
-
actions:
|
|
16
|
+
actions: PanelAppServiceActionAuthorizationItem[];
|
|
17
17
|
inputPreview?: string;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
type PendingAuthorization =
|
|
20
|
+
type PendingAuthorization = PanelAppServiceActionAuthorizationRequest & {
|
|
21
21
|
resolve: (allowed: boolean) => void;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
type ServiceActionAuthorizationState = {
|
|
25
25
|
pending: PendingAuthorization | null;
|
|
26
26
|
requestAuthorization: (
|
|
27
|
-
request: Omit<
|
|
27
|
+
request: Omit<PanelAppServiceActionAuthorizationRequest, 'id'>,
|
|
28
28
|
) => Promise<boolean>;
|
|
29
29
|
resolveAuthorization: (allowed: boolean) => void;
|
|
30
30
|
};
|
|
@@ -33,7 +33,7 @@ function createAuthorizationId(): string {
|
|
|
33
33
|
return `service-action-auth-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
export const
|
|
36
|
+
export const usePanelAppServiceActionAuthorizationStore = create<ServiceActionAuthorizationState>((set, get) => ({
|
|
37
37
|
pending: null,
|
|
38
38
|
requestAuthorization: async (request) =>
|
|
39
39
|
await new Promise<boolean>((resolve) => {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Projects UI boundary
|
|
2
2
|
|
|
3
|
-
- 本目录拥有 Projects 页面、presenter
|
|
4
|
-
- 页面默认只读;确认/拒绝只复用现有 agent-run 消息入口,并携带可追踪、可幂等的响应元数据,不创建第二套 response bridge。
|
|
3
|
+
- 本目录拥有 Projects 页面、presenter 和查询状态;工作项与产物来自 Project Work API,Skills 与工作约定来自独立的有界材料 API,组件不得读取项目配置、扫描文件或从会话正文重建项目事实。
|
|
5
4
|
- Overview、列表和看板消费同一份工作项查询状态;所有工作项入口统一打开右侧详情抽屉,不得在页面内追加平铺详情。
|
|
6
5
|
- `project.work.changed` 只用于失效查询;UI 不重放事件历史,也不以轮询或目录扫描代替业务存储。
|
|
7
6
|
- 组件负责连接与展示,跨组件状态归 hook/presenter;用户文案必须走 Projects i18n 资源。
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ProjectAgreementMaterial } from "@nextclaw/client-sdk";
|
|
2
2
|
import { t } from "@/shared/lib/i18n";
|
|
3
3
|
import {
|
|
4
4
|
ProjectEmptyState,
|
|
@@ -7,86 +7,45 @@ import {
|
|
|
7
7
|
} from "./project-section";
|
|
8
8
|
|
|
9
9
|
export function ProjectAgreement({
|
|
10
|
-
|
|
10
|
+
agreement,
|
|
11
|
+
isLoading,
|
|
12
|
+
isError,
|
|
11
13
|
onOpenFile,
|
|
12
14
|
}: {
|
|
13
|
-
|
|
15
|
+
agreement?: ProjectAgreementMaterial;
|
|
16
|
+
isLoading: boolean;
|
|
17
|
+
isError: boolean;
|
|
14
18
|
onOpenFile: (path: string, label: string) => void;
|
|
15
19
|
}) {
|
|
16
20
|
return (
|
|
17
|
-
<
|
|
18
|
-
<
|
|
19
|
-
{
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
</span>
|
|
47
|
-
</div>
|
|
48
|
-
))}
|
|
49
|
-
</div>
|
|
50
|
-
{snapshot.diagnostics.length ? (
|
|
51
|
-
<div className="mt-4 space-y-2 border-t border-border/60 pt-4">
|
|
52
|
-
{snapshot.diagnostics.map((diagnostic) => (
|
|
53
|
-
<div
|
|
54
|
-
key={diagnostic.id}
|
|
55
|
-
className="rounded-xl bg-muted/35 p-3 text-sm"
|
|
56
|
-
>
|
|
57
|
-
<p className="font-medium">{diagnostic.code}</p>
|
|
58
|
-
<p className="mt-1 text-xs text-muted-foreground">
|
|
59
|
-
{diagnostic.message}
|
|
60
|
-
</p>
|
|
61
|
-
</div>
|
|
62
|
-
))}
|
|
63
|
-
</div>
|
|
64
|
-
) : null}
|
|
65
|
-
</ProjectSection>
|
|
66
|
-
</div>
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function ProjectContextReference({
|
|
71
|
-
context,
|
|
72
|
-
onOpenFile,
|
|
73
|
-
}: {
|
|
74
|
-
context: ProjectObservationSnapshot["project"]["context"][number];
|
|
75
|
-
onOpenFile: (path: string, label: string) => void;
|
|
76
|
-
}) {
|
|
77
|
-
const { accessible, role, source } = context;
|
|
78
|
-
return (
|
|
79
|
-
<ProjectFilePreviewButton
|
|
80
|
-
available={accessible}
|
|
81
|
-
path={source}
|
|
82
|
-
label={role}
|
|
83
|
-
onOpen={onOpenFile}
|
|
84
|
-
className="block w-full py-3 text-left first:pt-0 enabled:hover:text-foreground enabled:focus-visible:outline-none enabled:focus-visible:ring-1 enabled:focus-visible:ring-border"
|
|
85
|
-
>
|
|
86
|
-
<span className="block text-sm font-medium">{role}</span>
|
|
87
|
-
<span className="mt-1 block truncate text-xs text-muted-foreground">
|
|
88
|
-
{source}{!accessible ? ` · ${t("projectsUnavailable")}` : ""}
|
|
89
|
-
</span>
|
|
90
|
-
</ProjectFilePreviewButton>
|
|
21
|
+
<ProjectSection title={t("projectsAgreementFile")}>
|
|
22
|
+
<p className="mb-4 text-sm text-muted-foreground">
|
|
23
|
+
{t("projectsAgreementDescription")}
|
|
24
|
+
</p>
|
|
25
|
+
{isLoading ? (
|
|
26
|
+
<p className="py-5 text-sm text-muted-foreground">
|
|
27
|
+
{t("projectsLoading")}
|
|
28
|
+
</p>
|
|
29
|
+
) : isError ? (
|
|
30
|
+
<p className="py-5 text-sm text-destructive">
|
|
31
|
+
{t("projectsLoadFailed")}
|
|
32
|
+
</p>
|
|
33
|
+
) : agreement?.available ? (
|
|
34
|
+
<ProjectFilePreviewButton
|
|
35
|
+
available
|
|
36
|
+
path={agreement.path}
|
|
37
|
+
label={agreement.path}
|
|
38
|
+
onOpen={onOpenFile}
|
|
39
|
+
className="block w-full rounded-xl bg-muted/45 p-3 text-left transition-colors enabled:hover:bg-[var(--interaction-hover)] enabled:focus-visible:outline-none enabled:focus-visible:ring-1 enabled:focus-visible:ring-border"
|
|
40
|
+
>
|
|
41
|
+
<span className="block text-sm font-medium">{agreement.path}</span>
|
|
42
|
+
<span className="mt-1 block text-xs text-muted-foreground">
|
|
43
|
+
{t("projectsAgreementOpen")}
|
|
44
|
+
</span>
|
|
45
|
+
</ProjectFilePreviewButton>
|
|
46
|
+
) : (
|
|
47
|
+
<ProjectEmptyState>{t("projectsNoAgreement")}</ProjectEmptyState>
|
|
48
|
+
)}
|
|
49
|
+
</ProjectSection>
|
|
91
50
|
);
|
|
92
51
|
}
|
|
@@ -1,77 +1,105 @@
|
|
|
1
1
|
import { fireEvent, render, screen } from "@testing-library/react";
|
|
2
2
|
import { describe, expect, it, vi } from "vitest";
|
|
3
|
-
import type { ProjectObservationSnapshot } from "@nextclaw/client-sdk";
|
|
4
3
|
import { ProjectArtifacts } from "./project-artifacts";
|
|
5
4
|
|
|
6
|
-
const
|
|
7
|
-
const designs = Array.from({ length: 11 }, (_, index) => ({
|
|
8
|
-
id: `design-${index + 1}`,
|
|
9
|
-
path: `docs/designs/${index + 1}.md`,
|
|
10
|
-
categoryId: "designs",
|
|
11
|
-
categoryLabel: "Designs",
|
|
12
|
-
exists: true,
|
|
13
|
-
fileUpdatedAt: `2026-08-${String(index + 1).padStart(2, "0")}T00:00:00.000Z`,
|
|
14
|
-
references: [],
|
|
15
|
-
}));
|
|
5
|
+
const useProjectArtifacts = vi.fn();
|
|
16
6
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
artifactCategories: [
|
|
25
|
-
{ id: "plans", label: "Plans" },
|
|
26
|
-
{ id: "designs", label: "Designs" },
|
|
27
|
-
],
|
|
28
|
-
artifacts: [
|
|
29
|
-
...designs,
|
|
30
|
-
{
|
|
31
|
-
id: "plan-1",
|
|
32
|
-
path: "docs/plans/delivery.md",
|
|
33
|
-
categoryId: "plans",
|
|
34
|
-
categoryLabel: "Plans",
|
|
35
|
-
exists: true,
|
|
36
|
-
fileUpdatedAt: "2026-08-30T00:00:00.000Z",
|
|
37
|
-
references: [],
|
|
38
|
-
},
|
|
39
|
-
],
|
|
40
|
-
signals: [],
|
|
41
|
-
requests: [],
|
|
42
|
-
activity: [],
|
|
43
|
-
skills: [],
|
|
44
|
-
diagnostics: [],
|
|
45
|
-
dataQuality: "complete",
|
|
46
|
-
};
|
|
7
|
+
vi.mock(
|
|
8
|
+
"@/features/projects/hooks/use-project-work",
|
|
9
|
+
async (importOriginal) => ({
|
|
10
|
+
...(await importOriginal()),
|
|
11
|
+
useProjectArtifacts: (...args: unknown[]) => useProjectArtifacts(...args),
|
|
12
|
+
}),
|
|
13
|
+
);
|
|
47
14
|
|
|
48
15
|
describe("ProjectArtifacts", () => {
|
|
49
|
-
it("
|
|
16
|
+
it("loads linked artifacts, searches through the owner, and opens available files", () => {
|
|
17
|
+
useProjectArtifacts.mockReturnValue({
|
|
18
|
+
data: {
|
|
19
|
+
pages: [
|
|
20
|
+
{
|
|
21
|
+
artifacts: [
|
|
22
|
+
{
|
|
23
|
+
id: "artifact-1",
|
|
24
|
+
path: "docs/design.md",
|
|
25
|
+
label: "Design",
|
|
26
|
+
workItemTitle: "Current work",
|
|
27
|
+
createdAt: "2026-09-03T00:00:00.000Z",
|
|
28
|
+
exists: true,
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
total: 1,
|
|
32
|
+
nextCursor: null,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
isLoading: false,
|
|
37
|
+
isError: false,
|
|
38
|
+
hasNextPage: false,
|
|
39
|
+
});
|
|
50
40
|
const onOpenFile = vi.fn();
|
|
51
|
-
render(<ProjectArtifacts
|
|
41
|
+
render(<ProjectArtifacts projectId="project-1" onOpenFile={onOpenFile} />);
|
|
42
|
+
|
|
43
|
+
fireEvent.click(screen.getByRole("button", { name: /Design/ }));
|
|
44
|
+
expect(onOpenFile).toHaveBeenCalledWith("docs/design.md", "Design");
|
|
45
|
+
|
|
46
|
+
fireEvent.change(screen.getByPlaceholderText(/Search artifacts|搜索产物/), {
|
|
47
|
+
target: { value: "report" },
|
|
48
|
+
});
|
|
49
|
+
expect(useProjectArtifacts).toHaveBeenLastCalledWith("project-1", {
|
|
50
|
+
limit: 20,
|
|
51
|
+
query: "report",
|
|
52
|
+
});
|
|
53
|
+
});
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
it("explains that artifacts come from work-item links", () => {
|
|
56
|
+
useProjectArtifacts.mockReturnValue({
|
|
57
|
+
data: { pages: [{ artifacts: [], total: 0, nextCursor: null }] },
|
|
58
|
+
isLoading: false,
|
|
59
|
+
isError: false,
|
|
60
|
+
hasNextPage: false,
|
|
61
|
+
});
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
expect(screen.getByTitle("docs/designs/1.md")).toBeTruthy();
|
|
63
|
+
render(<ProjectArtifacts projectId="project-1" onOpenFile={vi.fn()} />);
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
expect(
|
|
66
|
+
screen.getByText(/Link a file from a work item|从工作项关联文件/),
|
|
67
|
+
).toBeTruthy();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("keeps missing links visible and loads the next page explicitly", () => {
|
|
71
|
+
const fetchNextPage = vi.fn();
|
|
72
|
+
useProjectArtifacts.mockReturnValue({
|
|
73
|
+
data: {
|
|
74
|
+
pages: [
|
|
75
|
+
{
|
|
76
|
+
artifacts: [
|
|
77
|
+
{
|
|
78
|
+
id: "artifact-missing",
|
|
79
|
+
path: "docs/missing.md",
|
|
80
|
+
label: null,
|
|
81
|
+
workItemTitle: "Archived work",
|
|
82
|
+
createdAt: "2026-09-03T00:00:00.000Z",
|
|
83
|
+
exists: false,
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
total: 21,
|
|
87
|
+
nextCursor: "next",
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
isLoading: false,
|
|
92
|
+
isError: false,
|
|
93
|
+
hasNextPage: true,
|
|
94
|
+
isFetchingNextPage: false,
|
|
95
|
+
fetchNextPage,
|
|
66
96
|
});
|
|
67
|
-
expect(screen.queryByRole("button", { name: /Designs 11/ })).toBeNull();
|
|
68
|
-
expect(screen.getByTitle("docs/plans/delivery.md")).toBeTruthy();
|
|
69
|
-
fireEvent.click(screen.getByTitle("docs/plans/delivery.md"));
|
|
70
|
-
expect(onOpenFile).toHaveBeenCalledWith("docs/plans/delivery.md", "docs/plans/delivery.md");
|
|
71
97
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
expect(
|
|
75
|
-
expect(screen.
|
|
98
|
+
render(<ProjectArtifacts projectId="project-1" onOpenFile={vi.fn()} />);
|
|
99
|
+
|
|
100
|
+
expect(screen.getByText(/Currently unavailable|暂不可用/)).toBeTruthy();
|
|
101
|
+
expect(screen.queryByRole("button", { name: /missing\.md/ })).toBeNull();
|
|
102
|
+
fireEvent.click(screen.getByRole("button", { name: /Show more|显示更多/ }));
|
|
103
|
+
expect(fetchNextPage).toHaveBeenCalledTimes(1);
|
|
76
104
|
});
|
|
77
105
|
});
|